merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 07 Apr 2016 11:52:05 +0200
changeset 292135 b6683e141c47
parent 292134 8fc46323cee6 (current diff)
parent 291953 1c0b058b86be (diff)
child 292136 772253c53374
child 292223 579cca4926ab
child 292243 e787670d68a4
push id74762
push usercbook@mozilla.com
push date2016-04-07 09:56 +0000
treeherdermozilla-inbound@772253c53374 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.0a1
first release with
nightly linux32
b6683e141c47 / 48.0a1 / 20160407030234 / files
nightly linux64
b6683e141c47 / 48.0a1 / 20160407030234 / files
nightly mac
b6683e141c47 / 48.0a1 / 20160407030234 / files
nightly win32
b6683e141c47 / 48.0a1 / 20160407030234 / files
nightly win64
b6683e141c47 / 48.0a1 / 20160407030234 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/animation/test/css-animations/file_animation-play.html
dom/animation/test/css-animations/test_animation-play.html
media/omx-plugin/gb/OmxPlugin236.cpp
media/omx-plugin/gb/moz.build
media/omx-plugin/gb235/OmxPlugin235.cpp
media/omx-plugin/gb235/moz.build
media/omx-plugin/hc/OmxPluginHoneycomb.cpp
media/omx-plugin/hc/moz.build
media/omx-plugin/include/gb/OMX.h
media/omx-plugin/include/gb/android/native_window.h
media/omx-plugin/include/gb/android/rect.h
media/omx-plugin/include/gb/binder/Binder.h
media/omx-plugin/include/gb/binder/IBinder.h
media/omx-plugin/include/gb/binder/IInterface.h
media/omx-plugin/include/gb/cutils/atomic.h
media/omx-plugin/include/gb/cutils/log.h
media/omx-plugin/include/gb/cutils/logd.h
media/omx-plugin/include/gb/cutils/native_handle.h
media/omx-plugin/include/gb/cutils/uio.h
media/omx-plugin/include/gb/hardware/gralloc.h
media/omx-plugin/include/gb/hardware/hardware.h
media/omx-plugin/include/gb/media/IOMX.h
media/omx-plugin/include/gb/media/stagefright/MediaBuffer.h
media/omx-plugin/include/gb/media/stagefright/MediaErrors.h
media/omx-plugin/include/gb/media/stagefright/MediaSource.h
media/omx-plugin/include/gb/media/stagefright/openmax/OMX_Core.h
media/omx-plugin/include/gb/media/stagefright/openmax/OMX_IVCommon.h
media/omx-plugin/include/gb/media/stagefright/openmax/OMX_Index.h
media/omx-plugin/include/gb/media/stagefright/openmax/OMX_Types.h
media/omx-plugin/include/gb/media/stagefright/openmax/OMX_Video.h
media/omx-plugin/include/gb/pixelflinger/format.h
media/omx-plugin/include/gb/pixelflinger/pixelflinger.h
media/omx-plugin/include/gb/stagefright/ColorConverter.h
media/omx-plugin/include/gb/stagefright/DataSource.h
media/omx-plugin/include/gb/stagefright/HTTPStream.h
media/omx-plugin/include/gb/stagefright/MediaExtractor.h
media/omx-plugin/include/gb/stagefright/MetaData.h
media/omx-plugin/include/gb/stagefright/NuHTTPDataSource.h
media/omx-plugin/include/gb/stagefright/OMXClient.h
media/omx-plugin/include/gb/stagefright/OMXCodec.h
media/omx-plugin/include/gb/stagefright/stagefright_string.h
media/omx-plugin/include/gb/ui/GraphicBuffer.h
media/omx-plugin/include/gb/ui/PixelFormat.h
media/omx-plugin/include/gb/ui/Point.h
media/omx-plugin/include/gb/ui/Rect.h
media/omx-plugin/include/gb/ui/android_native_buffer.h
media/omx-plugin/include/gb/ui/egl/android_natives.h
media/omx-plugin/include/gb/utils/Errors.h
media/omx-plugin/include/gb/utils/Flattenable.h
media/omx-plugin/include/gb/utils/KeyedVector.h
media/omx-plugin/include/gb/utils/List.h
media/omx-plugin/include/gb/utils/Log.h
media/omx-plugin/include/gb/utils/RefBase.h
media/omx-plugin/include/gb/utils/SharedBuffer.h
media/omx-plugin/include/gb/utils/SortedVector.h
media/omx-plugin/include/gb/utils/String16.h
media/omx-plugin/include/gb/utils/String8.h
media/omx-plugin/include/gb/utils/TextOutput.h
media/omx-plugin/include/gb/utils/Timers.h
media/omx-plugin/include/gb/utils/TypeHelpers.h
media/omx-plugin/include/gb/utils/Vector.h
media/omx-plugin/include/gb/utils/VectorImpl.h
media/omx-plugin/include/gb/utils/threads.h
media/omx-plugin/lib/gb/libstagefright/libstagefright.cpp
media/omx-plugin/lib/gb/libstagefright/moz.build
media/omx-plugin/lib/gb/libstagefright_color_conversion/libstagefright_color_conversion.cpp
media/omx-plugin/lib/gb/libstagefright_color_conversion/moz.build
media/omx-plugin/lib/gb/libutils/libutils.cpp
media/omx-plugin/lib/gb/libutils/moz.build
media/omx-plugin/lib/gb235/libstagefright/libstagefright.cpp
media/omx-plugin/lib/gb235/libstagefright/moz.build
media/omx-plugin/lib/hc/libstagefright/libstagefright.cpp
media/omx-plugin/lib/hc/libstagefright/moz.build
mobile/android/base/java/org/mozilla/gecko/db/SQLiteBridgeContentProvider.java
mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java
security/nss/lib/ssl/sslgathr.c
security/nss/tests/pkcs11/netscape/suites/Makefile
security/nss/tests/pkcs11/netscape/suites/config.mk
security/nss/tests/pkcs11/netscape/suites/manifest.mn
security/nss/tests/pkcs11/netscape/suites/security/Makefile
security/nss/tests/pkcs11/netscape/suites/security/config.mk
security/nss/tests/pkcs11/netscape/suites/security/manifest.mn
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/Makefile
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/config.mk
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/manifest.mn
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/pk11test.c
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/pk11test.h
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/pk11test.htp
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/pkcs11.h
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/pkcs11.reg
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/pkcs11.rep
security/nss/tests/pkcs11/netscape/suites/security/pkcs11/rules.mk
security/nss/tests/pkcs11/netscape/suites/security/ssl/Makefile
security/nss/tests/pkcs11/netscape/suites/security/ssl/config.mk
security/nss/tests/pkcs11/netscape/suites/security/ssl/manifest.mn
security/nss/tests/pkcs11/netscape/suites/security/ssl/ssl.reg
security/nss/tests/pkcs11/netscape/suites/security/ssl/sslc.c
security/nss/tests/pkcs11/netscape/suites/security/ssl/sslc.h
security/nss/tests/pkcs11/netscape/suites/security/ssl/ssls.c
security/nss/tests/pkcs11/netscape/suites/security/ssl/ssls.h
security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.c
security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.h
security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.htp
security/nss/tests/pkcs11/netscape/suites/security/ssl/sslt.rep
security/nss/tests/pkcs11/netscape/trivial/Makefile.in
security/nss/tests/pkcs11/netscape/trivial/acconfig.h
security/nss/tests/pkcs11/netscape/trivial/configure.in
security/nss/tests/pkcs11/netscape/trivial/trivial.c
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -270,33 +270,37 @@ TreeWalker::Prev()
 
   mPhase = eAtStart;
   return nullptr;
 }
 
 Accessible*
 TreeWalker::AccessibleFor(nsIContent* aNode, uint32_t aFlags, bool* aSkipSubtree)
 {
-  Accessible* child = nullptr;
-  if (aFlags & eWalkCache) {
-    child = mDoc->GetAccessible(aNode);
-  }
-  else if (mContext->IsAcceptableChild(aNode)) {
-    child = GetAccService()->
-      GetOrCreateAccessible(aNode, mContext, aSkipSubtree);
+  // Ignore the accessible and its subtree if it was repositioned by means
+  // of aria-owns.
+  Accessible* child = mDoc->GetAccessible(aNode);
+  if (child) {
+    if (child->IsRelocated()) {
+      *aSkipSubtree = true;
+      return nullptr;
+    }
+    return child;
   }
 
-  // Ignore the accessible and its subtree if it was repositioned by means
-  // of aria-owns.
-  if (child && child->IsRelocated()) {
-    *aSkipSubtree = true;
-    return nullptr;
+  // Create an accessible if allowed.
+  if (!(aFlags & eWalkCache) && mContext->IsAcceptableChild(aNode)) {
+    if (mDoc->RelocateARIAOwnedIfNeeded(aNode)) {
+      *aSkipSubtree = true;
+      return nullptr;
+    }
+    return GetAccService()->CreateAccessible(aNode, mContext, aSkipSubtree);
   }
 
-  return child;
+  return nullptr;
 }
 
 dom::AllChildrenIterator*
 TreeWalker::PopState()
 {
   size_t length = mStateStack.Length();
   mStateStack.RemoveElementAt(length - 1);
   return mStateStack.IsEmpty() ? nullptr : &mStateStack.LastElement();
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -1005,36 +1005,30 @@ nsAccessibilityService::IsLogged(const n
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessibilityService public
 
 Accessible*
-nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
-                                              Accessible* aContext,
-                                              bool* aIsSubtreeHidden)
+nsAccessibilityService::CreateAccessible(nsINode* aNode,
+                                         Accessible* aContext,
+                                         bool* aIsSubtreeHidden)
 {
-  NS_PRECONDITION(aContext && aNode && !gIsShutdown,
-                  "Maybe let'd do a crash? Oh, yes, baby!");
+  MOZ_ASSERT(aContext, "No context provided");
+  MOZ_ASSERT(aNode, "No node to create an accessible for");
+  MOZ_ASSERT(!gIsShutdown, "No creation after shutdown");
 
   if (aIsSubtreeHidden)
     *aIsSubtreeHidden = false;
 
   DocAccessible* document = aContext->Document();
-
-  // Check to see if we already have an accessible for this node in the cache.
-  // XXX: we don't have context check here. It doesn't really necessary until
-  // we have in-law children adoption.
-  Accessible* cachedAccessible = document->GetAccessible(aNode);
-  if (cachedAccessible)
-    return cachedAccessible;
-
-  // No cache entry, so we must create the accessible.
+  MOZ_ASSERT(!document->GetAccessible(aNode),
+             "We already have an accessible for this node.");
 
   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     // If it's document node then ask accessible document loader for
     // document accessible, otherwise return null.
     nsCOMPtr<nsIDocument> document(do_QueryInterface(aNode));
     return GetDocAccessible(document);
   }
 
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -175,26 +175,25 @@ public:
   // nsAccessibiltiyService
 
   /**
    * Return true if accessibility service has been shutdown.
    */
   static bool IsShutdown() { return gIsShutdown; }
 
   /**
-   * Return an accessible for the given DOM node from the cache or create new
-   * one.
+   * Creates an accessible for the given DOM node.
    *
    * @param  aNode             [in] the given node
    * @param  aContext          [in] context the accessible is created in
    * @param  aIsSubtreeHidden  [out, optional] indicates whether the node's
    *                             frame and its subtree is hidden
    */
-  Accessible* GetOrCreateAccessible(nsINode* aNode, Accessible* aContext,
-                                    bool* aIsSubtreeHidden = nullptr);
+  Accessible* CreateAccessible(nsINode* aNode, Accessible* aContext,
+                               bool* aIsSubtreeHidden = nullptr);
 
   mozilla::a11y::role MarkupRole(const nsIContent* aContent) const
   {
     const mozilla::a11y::MarkupMapInfo* markupMap =
       mMarkupMaps.Get(aContent->NodeInfo()->NameAtom());
     return markupMap ? markupMap->role : mozilla::a11y::roles::NOTHING;
   }
 
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1261,18 +1261,16 @@ DocAccessible::BindToDocument(Accessible
 
   AddDependentIDsFor(aAccessible);
 
   if (aAccessible->HasOwnContent()) {
     nsIContent* el = aAccessible->GetContent();
     if (el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_owns)) {
       mNotificationController->ScheduleRelocation(aAccessible);
     }
-
-    RelocateARIAOwnedIfNeeded(el);
   }
 }
 
 void
 DocAccessible::UnbindFromDocument(Accessible* aAccessible)
 {
   NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
                "Unbinding the unbound accessible!");
@@ -1810,18 +1808,20 @@ void
 DocAccessible::ProcessContentInserted(Accessible* aContainer, nsIContent* aNode)
 {
   if (!aContainer->IsInDocument()) {
     return;
   }
 
   TreeWalker walker(aContainer);
   if (aContainer->IsAcceptableChild(aNode) && walker.Seek(aNode)) {
-    Accessible* child =
-      GetAccService()->GetOrCreateAccessible(aNode, aContainer);
+    Accessible* child = GetAccessible(aNode);
+    if (!child) {
+      child = GetAccService()->CreateAccessible(aNode, aContainer);
+    }
 
     if (child) {
       RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
 
       AutoTreeMutation mt(aContainer);
       aContainer->InsertAfter(child, walker.Prev());
       mt.AfterInsertion(child);
       mt.Done();
@@ -1972,34 +1972,37 @@ DocAccessible::UpdateTreeInternal(Access
   if (focusedAcc) {
     FocusMgr()->DispatchFocusEvent(this, focusedAcc);
     SelectionMgr()->SetControlSelectionListener(focusedAcc->GetNode()->AsElement());
   }
 
   return updateFlags;
 }
 
-void
+bool
 DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement)
 {
   if (!aElement->HasID())
-    return;
+    return false;
 
   AttrRelProviderArray* list =
     mDependentIDsHash.Get(nsDependentAtomString(aElement->GetID()));
   if (list) {
     for (uint32_t idx = 0; idx < list->Length(); idx++) {
       if (list->ElementAt(idx)->mRelAttr == nsGkAtoms::aria_owns) {
         Accessible* owner = GetAccessible(list->ElementAt(idx)->mContent);
         if (owner) {
           mNotificationController->ScheduleRelocation(owner);
+          return true;
         }
       }
     }
   }
+
+  return false;
 }
 
 void
 DocAccessible::ValidateARIAOwned()
 {
   for (auto it = mARIAOwnsHash.Iter(); !it.Done(); it.Next()) {
     Accessible* owner = it.Key();
     nsTArray<RefPtr<Accessible> >* children = it.UserData();
@@ -2048,20 +2051,44 @@ DocAccessible::DoARIAOwnsRelocation(Acce
   MOZ_ASSERT(aOwner, "aOwner must be a valid pointer");
   MOZ_ASSERT(aOwner->Elm(), "aOwner->Elm() must be a valid pointer");
 
 #ifdef A11Y_LOG
   logging::TreeInfo("aria owns relocation", logging::eVerbose, aOwner);
 #endif
 
   IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns);
-  Accessible* child = nullptr;
+  uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
+  while (nsIContent* childEl = iter.NextElem()) {
+    Accessible* child = GetAccessible(childEl);
+
+    // Make an attempt to create an accessible if it wasn't created yet.
+    if (!child) {
+      if (aOwner->IsAcceptableChild(childEl)) {
+        child = GetAccService()->CreateAccessible(childEl, aOwner);
+        if (child) {
+          AutoTreeMutation imut(aOwner);
+          aOwner->InsertChildAt(insertIdx, child);
+          imut.AfterInsertion(child);
+          imut.Done();
 
-  uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
-  while ((child = iter.Next())) {
+          child->SetRelocated(true);
+          children->InsertElementAt(arrayIdx, child);
+
+          insertIdx = child->IndexInParent() + 1;
+          arrayIdx++;
+
+          RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aOwner);
+          uint32_t flags = UpdateTreeInternal(child, true, reorderEvent);
+          FireEventsOnInsertion(aOwner, reorderEvent, flags);
+        }
+      }
+      continue;
+    }
+
 #ifdef A11Y_LOG
   logging::TreeInfo("aria owns traversal", logging::eVerbose,
                     "candidate", child, nullptr);
 #endif
 
     // Same child on same position, no change.
     if (child->Parent() == aOwner &&
         child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
--- a/accessible/generic/DocAccessible.h
+++ b/accessible/generic/DocAccessible.h
@@ -362,16 +362,22 @@ public:
   void UpdateText(nsIContent* aTextNode);
 
   /**
    * Recreate an accessible, results in hide/show events pair.
    */
   void RecreateAccessible(nsIContent* aContent);
 
   /**
+   * Schedule ARIA owned element relocation if needed. Return true if relocation
+   * was scheduled.
+   */
+  bool RelocateARIAOwnedIfNeeded(nsIContent* aEl);
+
+  /**
    * If this document is in a content process return the object responsible for
    * communicating with the main process for it.
    */
   DocAccessibleChild* IPCDoc() const { return mIPCDoc; }
 
 protected:
   virtual ~DocAccessible();
 
@@ -516,21 +522,16 @@ protected:
     eAccessible = 1,
     eAlertAccessible = 2
   };
 
   uint32_t UpdateTreeInternal(Accessible* aChild, bool aIsInsert,
                               AccReorderEvent* aReorderEvent);
 
   /**
-   * Schedule ARIA owned element relocation if needed.
-   */
-  void RelocateARIAOwnedIfNeeded(nsIContent* aEl);
-
-  /**
    * Validates all aria-owns connections and updates the tree accordingly.
    */
   void ValidateARIAOwned();
 
   /**
    * Steals or puts back accessible subtrees.
    */
   void DoARIAOwnsRelocation(Accessible* aOwner);
--- a/accessible/tests/mochitest/selectable/a11y.ini
+++ b/accessible/tests/mochitest/selectable/a11y.ini
@@ -1,12 +1,11 @@
 [DEFAULT]
 support-files =
   !/accessible/tests/mochitest/*.js
   !/accessible/tests/mochitest/treeview.css
-  !/accessible/tests/mochitest/treeview.js
 
 [test_aria.html]
 [test_listbox.xul]
 [test_menu.xul]
 [test_menulist.xul]
 [test_select.html]
 [test_tree.xul]
--- a/accessible/tests/mochitest/tree/test_aria_owns.html
+++ b/accessible/tests/mochitest/tree/test_aria_owns.html
@@ -15,17 +15,17 @@
   <script type="application/javascript"
           src="../role.js"></script>
 
   <script type="application/javascript">
     ////////////////////////////////////////////////////////////////////////////
     // Tests
     ////////////////////////////////////////////////////////////////////////////
 
-    //enableLogging("tree"); // debug stuff
+    //enableLogging("tree,verbose"); // debug stuff
 
     var gQueue = null;
 
     function doTest()
     {
       var tree =
         { SECTION: [ // t1_1
           { HEADING: [ // t1_2
@@ -139,28 +139,28 @@
   <div id="t1_2" aria-owns="t1_1" role="heading"></div>
 
   <!-- loop -->
   <div id="t2_2" aria-owns="t2_3" role="group"></div>
   <div id="t2_1" aria-owns="t2_2"></div>
   <div id="t2_3" aria-owns="t2_1" role="heading"></div>
 
   <!-- loop #2 -->
-  <div id="t3_3" aria-owns="t3_1"></div>
   <div id="t3_1" aria-owns="t3_2" role="group"></div>
   <div id="t3_2" role="note">
     <div aria-owns="t3_3" role="heading"></div>
   </div>
+  <div id="t3_3" aria-owns="t3_1"></div>
 
   <!-- self loop -->
   <div id="t4_1"><div aria-owns="t4_1" role="group"></div></div>
 
   <!-- natural and aria-owns hierarchy -->
+  <div id="t5_2" role="note"><div aria-owns="t5_3" role="heading"></div></div>
   <div id="t5_1"><div aria-owns="t5_2" role="group"></div></div>
-  <div id="t5_2" role="note"><div aria-owns="t5_3" role="heading"></div></div>
   <div id="t5_3" role="form"><div aria-owns="t5_1" role="tooltip"></div></div>
 
   <!-- rearrange children -->
   <div id="t6_1" aria-owns="t6_3 t6_2">
     <div id="t6_2" role="button"></div>
     <div id="t6_3" role="checkbox"></div>
     <div role="radio"></div>
   </div>
--- a/browser/components/newtab/NewTabMessages.jsm
+++ b/browser/components/newtab/NewTabMessages.jsm
@@ -1,71 +1,93 @@
 /*global
   NewTabWebChannel,
   NewTabPrefsProvider,
+  PlacesProvider,
   Preferences,
   XPCOMUtils
 */
 
 /* exported NewTabMessages */
 
 "use strict";
 
 const {utils: Cu} = Components;
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesProvider",
+                                  "resource:///modules/PlacesProvider.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PreviewProvider",
                                   "resource:///modules/PreviewProvider.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
                                   "resource:///modules/NewTabPrefsProvider.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
                                   "resource:///modules/NewTabWebChannel.jsm");
 
 this.EXPORTED_SYMBOLS = ["NewTabMessages"];
 
 const PREF_ENABLED = "browser.newtabpage.remote";
 
 // Action names are from the content's perspective. in from chrome == out from content
 // Maybe replace the ACTION objects by a bi-directional Map a bit later?
 const ACTIONS = {
+  inboundActions: [
+    "REQUEST_PREFS",
+    "REQUEST_THUMB",
+    "REQUEST_FRECENT",
+  ],
   prefs: {
     inPrefs: "REQUEST_PREFS",
     outPrefs: "RECEIVE_PREFS",
-    action_types: new Set(["REQUEST_PREFS"]),
   },
   preview: {
     inThumb: "REQUEST_THUMB",
     outThumb: "RECEIVE_THUMB",
-    action_types: new Set(["REQUEST_THUMB"]),
+  },
+  links: {
+    inFrecent: "REQUEST_FRECENT",
+    outFrecent: "RECEIVE_FRECENT",
+    outPlacesChange: "RECEIVE_PLACES_CHANGE",
   },
 };
 
 let NewTabMessages = {
 
   _prefs: {},
 
   /** NEWTAB EVENT HANDLERS **/
 
-  /*
-   * Return to the originator all newtabpage prefs. A point-to-point request.
-   */
-  handlePrefRequest(actionName, {target}) {
-    if (ACTIONS.prefs.inPrefs === actionName) {
-      let results = NewTabPrefsProvider.prefs.newtabPagePrefs;
-      NewTabWebChannel.send(ACTIONS.prefs.outPrefs, results, target);
+  handleContentRequest(actionName, {data, target}) {
+    switch (actionName) {
+      case ACTIONS.prefs.inPrefs:
+        // Return to the originator all newtabpage prefs
+        let results = NewTabPrefsProvider.prefs.newtabPagePrefs;
+        NewTabWebChannel.send(ACTIONS.prefs.outPrefs, results, target);
+        break;
+      case ACTIONS.preview.inThumb:
+        // Return to the originator a preview URL
+        PreviewProvider.getThumbnail(data).then(imgData => {
+          NewTabWebChannel.send(ACTIONS.preview.outThumb, {url: data, imgData}, target);
+        });
+        break;
+      case ACTIONS.links.inFrecent:
+        // Return to the originator the top frecent links
+        PlacesProvider.links.getLinks().then(links => {
+          NewTabWebChannel.send(ACTIONS.links.outFrecent, links, target);
+        });
+        break;
     }
   },
 
-  handlePreviewRequest(actionName, {data, target}) {
-    if (ACTIONS.preview.inThumb === actionName) {
-      PreviewProvider.getThumbnail(data).then(imgData => {
-        NewTabWebChannel.send(ACTIONS.preview.outThumb, {url: data, imgData}, target);
-      });
-    }
+  /*
+   * Broadcast places change to all open newtab pages
+   */
+  handlePlacesChange(type, data) {
+    NewTabWebChannel.broadcast(ACTIONS.links.outPlacesChange, {type, data});
   },
 
   /*
    * Broadcast preference changes to all open newtab pages
    */
   handlePrefChange(actionName, value) {
     let prefChange = {};
     prefChange[actionName] = value;
@@ -78,47 +100,54 @@ let NewTabMessages = {
         this.uninit();
       } else if (!this._prefs.enabled && value) {
         this.init();
       }
     }
   },
 
   init() {
-    this.handlePrefRequest = this.handlePrefRequest.bind(this);
-    this.handlePreviewRequest = this.handlePreviewRequest.bind(this);
-    this.handlePrefChange = this.handlePrefChange.bind(this);
+    this.handleContentRequest = this.handleContentRequest.bind(this);
     this._handleEnabledChange = this._handleEnabledChange.bind(this);
 
+    PlacesProvider.links.init();
     NewTabPrefsProvider.prefs.init();
     NewTabWebChannel.init();
 
     this._prefs.enabled = Preferences.get(PREF_ENABLED, false);
 
     if (this._prefs.enabled) {
-      NewTabWebChannel.on(ACTIONS.prefs.inPrefs, this.handlePrefRequest);
-      NewTabWebChannel.on(ACTIONS.preview.inThumb, this.handlePreviewRequest);
-
+      for (let action of ACTIONS.inboundActions) {
+        NewTabWebChannel.on(action, this.handleContentRequest);
+      }
       NewTabPrefsProvider.prefs.on(PREF_ENABLED, this._handleEnabledChange);
 
       for (let pref of NewTabPrefsProvider.newtabPagePrefSet) {
         NewTabPrefsProvider.prefs.on(pref, this.handlePrefChange);
       }
+
+      PlacesProvider.links.on("deleteURI", this.handlePlacesChange);
+      PlacesProvider.links.on("clearHistory", this.handlePlacesChange);
+      PlacesProvider.links.on("linkChanged", this.handlePlacesChange);
+      PlacesProvider.links.on("manyLinksChanged", this.handlePlacesChange);
     }
   },
 
   uninit() {
     this._prefs.enabled = Preferences.get(PREF_ENABLED, false);
 
     if (this._prefs.enabled) {
       NewTabPrefsProvider.prefs.off(PREF_ENABLED, this._handleEnabledChange);
 
-      NewTabWebChannel.off(ACTIONS.prefs.inPrefs, this.handlePrefRequest);
-      NewTabWebChannel.off(ACTIONS.prefs.inThumb, this.handlePreviewRequest);
+      for (let action of ACTIONS.inboundActions) {
+        NewTabWebChannel.off(action, this.handleContentRequest);
+      }
+
       for (let pref of NewTabPrefsProvider.newtabPagePrefSet) {
         NewTabPrefsProvider.prefs.off(pref, this.handlePrefChange);
       }
     }
 
+    PlacesProvider.links.uninit();
     NewTabPrefsProvider.prefs.uninit();
     NewTabWebChannel.uninit();
   }
 };
--- a/browser/components/newtab/PlacesProvider.jsm
+++ b/browser/components/newtab/PlacesProvider.jsm
@@ -1,27 +1,24 @@
 /* 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/. */
 
-/* global XPCOMUtils, Services, BinarySearch, PlacesUtils, gPrincipal, EventEmitter */
+/* global XPCOMUtils, Services, PlacesUtils, gPrincipal, EventEmitter */
 /* global gLinks */
 /* exported PlacesProvider */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["PlacesProvider"];
 
 const {interfaces: Ci, utils: Cu} = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "BinarySearch",
-  "resource://gre/modules/BinarySearch.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
   "resource://gre/modules/PlacesUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
   const {EventEmitter} = Cu.import("resource://devtools/shared/event-emitter.js", {});
   return EventEmitter;
 });
 
@@ -135,24 +132,32 @@ Links.prototype = {
                         Ci.nsISupportsWeakReference])
   },
 
   /**
    * Must be called before the provider is used.
    * Makes it easy to disable under pref
    */
   init: function PlacesProvider_init() {
-    PlacesUtils.history.addObserver(this.historyObserver, true);
+    try {
+      PlacesUtils.history.addObserver(this.historyObserver, true);
+    } catch (e) {
+      Cu.reportError(e);
+    }
   },
 
   /**
    * Must be called before the provider is unloaded.
    */
-  destroy: function PlacesProvider_destroy() {
-    PlacesUtils.history.removeObserver(this.historyObserver);
+  uninit: function PlacesProvider_uninit() {
+    try {
+      PlacesUtils.history.removeObserver(this.historyObserver);
+    } catch (e) {
+      Cu.reportError(e);
+    }
   },
 
   /**
    * Gets the current set of links delivered by this provider.
    *
    * @returns {Promise} Returns a promise with the array of links as payload.
    */
   getLinks: Task.async(function*() {
--- a/browser/components/newtab/tests/browser/browser.ini
+++ b/browser/components/newtab/tests/browser/browser.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
 support-files =
   blue_page.html
   dummy_page.html
   newtabwebchannel_basic.html
+  newtabmessages_places.html
   newtabmessages_prefs.html
   newtabmessages_preview.html
 
 [browser_PreviewProvider.js]
 [browser_remotenewtab_pageloads.js]
 [browser_newtab_overrides.js]
 [browser_newtabmessages.js]
 [browser_newtabwebchannel.js]
--- a/browser/components/newtab/tests/browser/browser_newtabmessages.js
+++ b/browser/components/newtab/tests/browser/browser_newtabmessages.js
@@ -1,17 +1,19 @@
-/* globals Cu, XPCOMUtils, Preferences, is, registerCleanupFunction, NewTabWebChannel */
+/* globals Cu, XPCOMUtils, Preferences, is, registerCleanupFunction, NewTabWebChannel, PlacesTestUtils */
 
 "use strict";
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
                                   "resource:///modules/NewTabWebChannel.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NewTabMessages",
                                   "resource:///modules/NewTabMessages.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+                                  "resource://testing-common/PlacesTestUtils.jsm");
 
 function setup() {
   Preferences.set("browser.newtabpage.enhanced", true);
   Preferences.set("browser.newtabpage.remote.mode", "test");
   Preferences.set("browser.newtabpage.remote", true);
   NewTabMessages.init();
 }
 
@@ -78,8 +80,81 @@ add_task(function* previewMessages_reque
   });
 
   yield BrowserTestUtils.withNewTab(tabOptions, function*() {
     yield previewResponseAck;
   });
   cleanup();
   Services.prefs.setBoolPref("browser.pagethumbnails.capturing_disabled", oldEnabledPref);
 });
+
+/*
+ * Sanity tests for places messages
+ */
+add_task(function* placesMessages_request() {
+  setup();
+  let testURL = "https://example.com/browser/browser/components/newtab/tests/browser/newtabmessages_places.html";
+
+  // url prefix for test history population
+  const TEST_URL = "https://mozilla.com/";
+  // time when the test starts execution
+  const TIME_NOW = (new Date()).getTime();
+
+  // utility function to compute past timestamp
+  function timeDaysAgo(numDays) {
+    return TIME_NOW - (numDays * 24 * 60 * 60 * 1000);
+  }
+
+  // utility function to make a visit for insertion into places db
+  function makeVisit(index, daysAgo, isTyped, domain=TEST_URL) {
+    let {
+      TRANSITION_TYPED,
+      TRANSITION_LINK
+    } = PlacesUtils.history;
+
+    return {
+      uri: NetUtil.newURI(`${domain}${index}`),
+      visitDate: timeDaysAgo(daysAgo),
+      transition: (isTyped) ? TRANSITION_TYPED : TRANSITION_LINK,
+    };
+  }
+
+  yield PlacesTestUtils.clearHistory();
+
+  // all four visits must come from different domains to avoid deduplication
+  let visits = [
+    makeVisit(0, 0, true, "http://bar.com/"), // frecency 200, today
+    makeVisit(1, 0, true, "http://foo.com/"), // frecency 200, today
+    makeVisit(2, 2, true, "http://buz.com/"), // frecency 200, 2 days ago
+    makeVisit(3, 2, false, "http://aaa.com/"), // frecency 10, 2 days ago, transition
+  ];
+
+  yield PlacesTestUtils.addVisits(visits);
+
+  /** Test Begins **/
+
+  let tabOptions = {
+    gBrowser,
+    url: testURL
+  };
+
+  let placesResponseAck = new Promise(resolve => {
+    NewTabWebChannel.once("numItemsAck", (_, msg) => {
+      ok(true, "a request response has been received");
+      is(msg.data, visits.length + 1, "received an expect number of history items");
+      resolve();
+    });
+  });
+
+  yield BrowserTestUtils.withNewTab(tabOptions, function*() {
+    yield placesResponseAck;
+    let placesChangeAck = new Promise(resolve => {
+      NewTabWebChannel.once("clearHistoryAck", (_, msg) => {
+        ok(true, "a change response has been received");
+        is(msg.data, "clearHistory", "a clear history message has been received");
+        resolve();
+      });
+    });
+    yield PlacesTestUtils.clearHistory();
+    yield placesChangeAck;
+  });
+  cleanup();
+});
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/tests/browser/newtabmessages_places.html
@@ -0,0 +1,49 @@
+<html>
+  <head>
+    <meta charset="utf8">
+    <title>Newtab WebChannel test</title>
+  </head>
+  <body>
+    <script>
+      window.addEventListener("WebChannelMessageToContent", function(e) {
+        if (e.detail.message) {
+          let reply;
+          switch (e.detail.message.type) {
+            case "RECEIVE_FRECENT":
+              reply = new window.CustomEvent("WebChannelMessageToChrome", {
+                detail: {
+                  id: "newtab",
+                  message: JSON.stringify({type: "numItemsAck", data: e.detail.message.data.length}),
+                }
+              });
+              window.dispatchEvent(reply);
+              break;
+            case "RECEIVE_PLACES_CHANGE":
+              if (e.detail.message.data.type === "clearHistory") {
+                reply = new window.CustomEvent("WebChannelMessageToChrome", {
+                  detail: {
+                    id: "newtab",
+                    message: JSON.stringify({type: "clearHistoryAck", data: e.detail.message.data.type}),
+                  }
+                });
+                window.dispatchEvent(reply);
+              }
+              break;
+          }
+        }
+      }, true);
+
+      document.onreadystatechange = function () {
+        if (document.readyState === "complete") {
+          let msg = new window.CustomEvent("WebChannelMessageToChrome", {
+            detail: {
+              id: "newtab",
+              message: JSON.stringify({type: "REQUEST_FRECENT"}),
+            }
+          });
+          window.dispatchEvent(msg);
+        }
+      }
+    </script>
+  </body>
+</html>
--- a/browser/components/newtab/tests/xpcshell/test_PlacesProvider.js
+++ b/browser/components/newtab/tests/xpcshell/test_PlacesProvider.js
@@ -165,17 +165,17 @@ add_task(function* test_Links_onLinkChan
   });
 
   // add a visit
   let testURI = NetUtil.newURI(url);
   yield PlacesTestUtils.addVisits(testURI);
   yield linkChangedPromise;
 
   yield PlacesTestUtils.clearHistory();
-  provider.destroy();
+  provider.uninit();
 });
 
 add_task(function* test_Links_onClearHistory() {
   let provider = PlacesProvider.links;
   provider.init();
 
   let clearHistoryPromise = new Promise(resolve => {
     let handler = () => {
@@ -189,17 +189,17 @@ add_task(function* test_Links_onClearHis
   // add visits
   for (let i = 0; i <= 10; i++) {
     let url = `https://example.com/onClearHistory${i}`;
     let testURI = NetUtil.newURI(url);
     yield PlacesTestUtils.addVisits(testURI);
   }
   yield PlacesTestUtils.clearHistory();
   yield clearHistoryPromise;
-  provider.destroy();
+  provider.uninit();
 });
 
 add_task(function* test_Links_onDeleteURI() {
   let provider = PlacesProvider.links;
   provider.init();
 
   let testURL = "https://example.com/toDelete";
 
@@ -212,17 +212,17 @@ add_task(function* test_Links_onDeleteUR
 
     provider.on("deleteURI", handler);
   });
 
   let testURI = NetUtil.newURI(testURL);
   yield PlacesTestUtils.addVisits(testURI);
   yield PlacesUtils.history.remove(testURL);
   yield deleteURIPromise;
-  provider.destroy();
+  provider.uninit();
 });
 
 add_task(function* test_Links_onManyLinksChanged() {
   let provider = PlacesProvider.links;
   provider.init();
 
   let promise = new Promise(resolve => {
     let handler = () => {
@@ -238,17 +238,17 @@ add_task(function* test_Links_onManyLink
   let testURI = NetUtil.newURI(testURL);
   yield PlacesTestUtils.addVisits(testURI);
 
   // trigger DecayFrecency
   PlacesUtils.history.QueryInterface(Ci.nsIObserver).
     observe(null, "idle-daily", "");
 
   yield promise;
-  provider.destroy();
+  provider.uninit();
 });
 
 add_task(function* test_Links_execute_query() {
   yield PlacesTestUtils.clearHistory();
   let provider = PlacesProvider.links;
 
   let visits = [
     makeVisit(0, 0, true), // frecency 200, today
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1561,21 +1561,27 @@ html|span.ac-tag {
 
 .tab-close-button:not(:hover):-moz-lwtheme-darktext {
   background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 96, 16, 80);
 }
 
 /* Tabstrip new tab button */
 .tabs-newtab-button,
 #TabsToolbar > #new-tab-button ,
-#TabsToolbar > #wrapper-new-tab-button > #new-tab-button {
-  list-style-image: url("moz-icon://stock/gtk-add?size=menu");
+#TabsToolbar > toolbarpaletteitem > #new-tab-button {
+  list-style-image: url(chrome://browser/skin/tabbrowser/newtab.svg);
   -moz-image-region: auto;
 }
 
+#TabsToolbar[brighttext] .tabs-newtab-button,
+#TabsToolbar[brighttext] > #new-tab-button,
+#TabsToolbar[brighttext] > toolbarpaletteitem > #new-tab-button {
+  list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted.svg);
+}
+
 /* Tabbrowser arrowscrollbox arrows */
 .tabbrowser-arrowscrollbox > .scrollbutton-up > .toolbarbutton-icon,
 .tabbrowser-arrowscrollbox > .scrollbutton-down > .toolbarbutton-icon {
   -moz-appearance: none;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -96,16 +96,18 @@ browser.jar:
   skin/classic/browser/preferences/search.css         (preferences/search.css)
   skin/classic/browser/social/services-16.png         (social/services-16.png)
   skin/classic/browser/social/services-64.png         (social/services-64.png)
   skin/classic/browser/social/share-button.png        (social/share-button.png)
   skin/classic/browser/social/share-button-active.png (social/share-button-active.png)
   skin/classic/browser/tabbrowser/alltabs.png         (tabbrowser/alltabs.png)
   skin/classic/browser/tabbrowser/alltabs-inverted.png (tabbrowser/alltabs-inverted.png)
   skin/classic/browser/tabbrowser/connecting.png      (tabbrowser/connecting.png)
+  skin/classic/browser/tabbrowser/newtab.svg                (tabbrowser/newtab.svg)
+  skin/classic/browser/tabbrowser/newtab-inverted.svg       (tabbrowser/newtab-inverted.svg)
   skin/classic/browser/tabbrowser/tab-active-middle.png     (tabbrowser/tab-active-middle.png)
   skin/classic/browser/tabbrowser/tab-arrow-left.png        (tabbrowser/tab-arrow-left.png)
   skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png)
   skin/classic/browser/tabbrowser/tab-background-end.png    (tabbrowser/tab-background-end.png)
   skin/classic/browser/tabbrowser/tab-background-middle.png (tabbrowser/tab-background-middle.png)
   skin/classic/browser/tabbrowser/tab-background-start.png  (tabbrowser/tab-background-start.png)
 
 # NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in
copy from browser/themes/windows/tabbrowser/newtab-inverted.svg
copy to browser/themes/linux/tabbrowser/newtab-inverted.svg
copy from browser/themes/windows/tabbrowser/newtab.svg
copy to browser/themes/linux/tabbrowser/newtab.svg
--- a/build/docs/mozinfo.rst
+++ b/build/docs/mozinfo.rst
@@ -93,16 +93,23 @@ healthreport
 
    Always defined.
 
 mozconfig
    The path of the :ref:`mozconfig file <mozconfig>` used to produce this build.
 
    Optional.
 
+nightly_build
+   Whether this is a nightly build.
+
+   Values are ``true`` and ``false``.
+
+   Always defined.
+
 os
    The operating system the build is produced for. Values for tier-1
    supported platforms are ``linux``, ``win``, ``mac``, ``b2g``, and
    ``android``. For other platforms, the value is the lowercase version
    of the ``OS_TARGET`` variable from ``config.status``.
 
    Always defined.
 
--- a/build/valgrind/output_handler.py
+++ b/build/valgrind/output_handler.py
@@ -101,16 +101,16 @@ class OutputHandler(object):
             else:
                 # We've finished getting the first few stack entries. Print the
                 # failure message and the buffered lines, and then reset state.
                 self.logger(logging.ERROR, 'valgrind-error-msg',
                             {'error': self.curr_error,
                              'location': self.curr_location},
                              'TEST-UNEXPECTED-FAIL | valgrind-test | {error} at {location}')
                 for b in self.buffered_lines:
-                    self.log(line)
+                    self.log(b)
                 self.curr_error = None
                 self.curr_location = None
                 self.buffered_lines = None
 
         if re.match(self.re_suppression, line):
             self.suppression_count += 1
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -24,18 +24,26 @@ ifndef INCLUDED_VERSION_MK
 include $(MOZILLA_DIR)/config/version.mk
 endif
 
 USE_AUTOTARGETS_MK = 1
 include $(MOZILLA_DIR)/config/makefiles/makeutils.mk
 
 ifdef REBUILD_CHECK
 REPORT_BUILD = $(info $(shell $(PYTHON) $(MOZILLA_DIR)/config/rebuild_check.py $@ $^))
+REPORT_BUILD_VERBOSE = $(REPORT_BUILD)
 else
 REPORT_BUILD = $(info $(notdir $@))
+
+ifdef BUILD_VERBOSE_LOG
+REPORT_BUILD_VERBOSE = $(REPORT_BUILD)
+else
+REPORT_BUILD_VERBOSE =
+endif
+
 endif
 
 EXEC			= exec
 
 # ELOG prints out failed command when building silently (gmake -s). Pymake
 # prints out failed commands anyway, so ELOG just makes things worse by
 # forcing shell invocations.
 ifneq (,$(findstring s, $(filter-out --%, $(MAKEFLAGS))))
@@ -854,98 +862,98 @@ endef
 mk_libname = $(basename lib$(notdir $1)).$(LIB_SUFFIX)
 src_libdep = $(call mk_libname,$1): $1 $$(call mkdir_deps,$$(MDDEPDIR))
 $(foreach f,$(RSSRCS),$(eval $(call src_libdep,$(f))))
 
 $(OBJS) $(HOST_OBJS) $(PROGOBJS) $(HOST_PROGOBJS): $(GLOBAL_DEPS)
 
 # Rules for building native targets must come first because of the host_ prefix
 $(HOST_COBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CPPFLAGS) $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
 $(HOST_CPPOBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(call BUILDSTATUS,OBJECT_FILE $@)
 	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CPPFLAGS) $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
 $(HOST_CMOBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CPPFLAGS) $(HOST_CFLAGS) $(HOST_CMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
 $(HOST_CMMOBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CPPFLAGS) $(HOST_CXXFLAGS) $(HOST_CMMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
 $(COBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 # DEFINES and ACDEFINES are needed here to enable conditional compilation of Q_OBJECTs:
 # 'moc' only knows about #defines it gets on the command line (-D...), not in
 # included headers like mozilla-config.h
 $(filter moc_%.cpp,$(CPPSRCS)): moc_%.cpp: %.h
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(MOC) $(DEFINES) $(ACDEFINES) $< $(OUTOPTION)$@
 
 $(filter moc_%.cc,$(CPPSRCS)): moc_%.cc: %.cc
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(MOC) $(DEFINES) $(ACDEFINES) $(_VPATH_SRCS:.cc=.h) $(OUTOPTION)$@
 
 $(filter qrc_%.cpp,$(CPPSRCS)): qrc_%.cpp: %.qrc
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(RCC) -name $* $< $(OUTOPTION)$@
 
 ifdef ASFILES
 # The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept
 # a '-c' flag.
 $(ASOBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $($(notdir $<)_FLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS)
 endif
 
 ifdef MOZ_RUST
 # Assume any system libraries rustc links against are already
 # in the target's LIBS.
 $(RSOBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(RUSTC) $(RUSTFLAGS) --crate-type staticlib --emit dep-info=$(MDDEPDIR)/$(call mk_libname,$<).pp,link=$(call mk_libname,$<) $(_VPATH_SRCS)
 endif
 
 $(SOBJS):
 	$(REPORT_BUILD)
 	$(AS) -o $@ $(ASFLAGS) $($(notdir $<)_FLAGS) $(LOCAL_INCLUDES) $(TARGET_LOCAL_INCLUDES) -c $<
 
 $(CPPOBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(call BUILDSTATUS,OBJECT_FILE $@)
 	$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(CMMOBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(CMOBJS):
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(ELOG) $(CC) -o $@ -c $(COMPILE_CFLAGS) $(COMPILE_CMFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(filter %.s,$(CPPSRCS:%.cpp=%.s)): %.s: %.cpp $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(CCC) -S $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(filter %.s,$(CPPSRCS:%.cc=%.s)): %.s: %.cc $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(CCC) -S $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(filter %.s,$(CPPSRCS:%.cxx=%.s)): %.s: %.cpp $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(CCC) -S $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(filter %.s,$(CSRCS:%.c=%.s)): %.s: %.c $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(CC) -S $(COMPILE_CFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 ifneq (,$(filter %.i,$(MAKECMDGOALS)))
 # Call as $(call _group_srcs,extension,$(SRCS)) - this will create a list
 # of the full sources, as well as the $(notdir) version. So:
 #   foo.cpp sub/bar.cpp
 # becomes:
 #   foo.cpp sub/bar.cpp bar.cpp
@@ -962,37 +970,37 @@ ifneq (,$(filter %.i,$(MAKECMDGOALS)))
 # reach $(srcdir)/frontend/Parser.i
 VPATH += $(addprefix $(srcdir)/,$(sort $(dir $(CPPSRCS) $(CSRCS) $(CMMSRCS))))
 
 # Make preprocessed files PHONY so they are always executed, since they are
 # manual targets and we don't necessarily write to $@.
 .PHONY: $(_PREPROCESSED_CPP_FILES) $(_PREPROCESSED_CC_FILES) $(_PREPROCESSED_CXX_FILES) $(_PREPROCESSED_C_FILES) $(_PREPROCESSED_CMM_FILES)
 
 $(_PREPROCESSED_CPP_FILES): %.i: %.cpp $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(addprefix $(MKDIR) -p ,$(filter-out .,$(@D)))
 	$(CCC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(_PREPROCESSED_CC_FILES): %.i: %.cc $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(addprefix $(MKDIR) -p ,$(filter-out .,$(@D)))
 	$(CCC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(_PREPROCESSED_CXX_FILES): %.i: %.cxx $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(addprefix $(MKDIR) -p ,$(filter-out .,$(@D)))
 	$(CCC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CXXFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(_PREPROCESSED_C_FILES): %.i: %.c $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(addprefix $(MKDIR) -p ,$(filter-out .,$(@D)))
 	$(CC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 $(_PREPROCESSED_CMM_FILES): %.i: %.mm $(call mkdir_deps,$(MDDEPDIR))
-	$(REPORT_BUILD)
+	$(REPORT_BUILD_VERBOSE)
 	$(addprefix $(MKDIR) -p ,$(filter-out .,$(@D)))
 	$(CCC) -C $(PREPROCESS_OPTION)$@ $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $($(notdir $<)_FLAGS) $(TARGET_LOCAL_INCLUDES) $(_VPATH_SRCS)
 
 # Default to pre-processing the actual unified file. This can be overridden
 # at the command-line to pre-process only the individual source file.
 PP_UNIFIED ?= 1
 
 # PP_REINVOKE gets set on the sub-make to prevent us from going in an
--- a/devtools/server/actors/storage.js
+++ b/devtools/server/actors/storage.js
@@ -342,20 +342,28 @@ StorageActors.defaults = function(typeNa
       let sortOn = options.sortOn || "name";
 
       let toReturn = {
         offset: offset,
         total: 0,
         data: []
       };
 
+      let principal = null;
+      if (this.typeName === "indexedDB") {
+        // We only acquire principal when the type of the storage is indexedDB
+        // because the principal only matters the indexedDB.
+        let win = this.storageActor.getWindowFromHost(host);
+        principal = win.document.nodePrincipal;
+      }
+
       if (names) {
         for (let name of names) {
           let values =
-            yield this.getValuesForHost(host, name, options, this.hostVsStores);
+            yield this.getValuesForHost(host, name, options, this.hostVsStores, principal);
 
           let {result, objectStores} = values;
 
           if (result && typeof result.objectsSize !== "undefined") {
             for (let {key, count} of result.objectsSize) {
               this.objectsSize[key] = count;
             }
           }
@@ -375,17 +383,17 @@ StorageActors.defaults = function(typeNa
           toReturn.data = [];
         } else {
           toReturn.data = toReturn.data.sort((a, b) => {
             return a[sortOn] - b[sortOn];
           }).slice(offset, offset + size).map(a => this.toStoreObject(a));
         }
       } else {
         let obj = yield this.getValuesForHost(host, undefined, undefined,
-                                              this.hostVsStores);
+                                              this.hostVsStores, principal);
         if (obj.dbs) {
           obj = obj.dbs;
         }
 
         toReturn.total = obj.length;
         if (offset > toReturn.total) {
           // In this case, toReturn.data is an empty array.
           toReturn.offset = offset = toReturn.total;
@@ -1546,19 +1554,21 @@ StorageActors.createActor({
     for (let host of this.hosts) {
       yield this.populateStoresForHost(host);
     }
   }),
 
   populateStoresForHost: Task.async(function*(host) {
     let storeMap = new Map();
     let {names} = yield this.getDBNamesForHost(host);
+    let win = this.storageActor.getWindowFromHost(host);
+    let principal = win.document.nodePrincipal;
 
     for (let name of names) {
-      let metadata = yield this.getDBMetaData(host, name);
+      let metadata = yield this.getDBMetaData(host, principal, name);
 
       metadata = indexedDBHelpers.patchMetadataMapsAndProtos(metadata);
       storeMap.set(name, metadata);
     }
 
     this.hostVsStores.set(host, storeMap);
   }),
 
@@ -1612,17 +1622,17 @@ StorageActors.createActor({
   },
 
   maybeSetupChildProcess: function() {
     if (!DebuggerServer.isInChildProcess) {
       this.backToChild = function(...args) {
         return args[1];
       };
       this.getDBMetaData = indexedDBHelpers.getDBMetaData;
-      this.openWithOrigin = indexedDBHelpers.openWithOrigin;
+      this.openWithPrincipal = indexedDBHelpers.openWithPrincipal;
       this.getDBNamesForHost = indexedDBHelpers.getDBNamesForHost;
       this.getSanitizedHost = indexedDBHelpers.getSanitizedHost;
       this.getNameFromDatabaseFile = indexedDBHelpers.getNameFromDatabaseFile;
       this.getValuesForHost = indexedDBHelpers.getValuesForHost;
       this.getObjectStoreData = indexedDBHelpers.getObjectStoreData;
       this.patchMetadataMapsAndProtos =
         indexedDBHelpers.patchMetadataMapsAndProtos;
       return;
@@ -1681,21 +1691,21 @@ var indexedDBHelpers = {
     mm.broadcastAsyncMessage("storage:storage-indexedDB-request-child", {
       method: "backToChild",
       args: args
     });
   },
 
   /**
    * Fetches and stores all the metadata information for the given database
-   * `name` for the given `host`. The stored metadata information is of
-   * `DatabaseMetadata` type.
+   * `name` for the given `host` with its `principal`. The stored metadata
+   * information is of `DatabaseMetadata` type.
    */
-  getDBMetaData: Task.async(function*(host, name) {
-    let request = this.openWithOrigin(host, name);
+  getDBMetaData: Task.async(function*(host, principal, name) {
+    let request = this.openWithPrincipal(principal, name);
     let success = promise.defer();
 
     request.onsuccess = event => {
       let db = event.target.result;
 
       let dbData = new DatabaseMetadata(host, db);
       db.close();
 
@@ -1707,29 +1717,19 @@ var indexedDBHelpers = {
                     host);
       this.backToChild("getDBMetaData", null);
       success.resolve(null);
     };
     return success.promise;
   }),
 
   /**
-   * Opens an indexed db connection for the given `host` and database `name`.
+   * Opens an indexed db connection for the given `principal` and database `name`.
    */
-  openWithOrigin: function(host, name) {
-    let principal;
-
-    if (/^(about:|chrome:)/.test(host)) {
-      principal = Services.scriptSecurityManager.getSystemPrincipal();
-    } else {
-      let uri = Services.io.newURI(host, null, null);
-      principal = Services.scriptSecurityManager
-                          .createCodebasePrincipal(uri, {});
-    }
-
+  openWithPrincipal: function(principal, name) {
     return require("indexedDB").openForPrincipal(principal, name);
   },
 
     /**
    * Fetches all the databases and their metadata for the given `host`.
    */
   getDBNamesForHost: Task.async(function*(host) {
     let sanitizedHost = this.getSanitizedHost(host);
@@ -1815,17 +1815,17 @@ var indexedDBHelpers = {
     let name = rows[0].getResultByName("name");
 
     yield connection.close();
 
     return name;
   }),
 
   getValuesForHost:
-  Task.async(function*(host, name = "null", options, hostVsStores) {
+  Task.async(function*(host, name = "null", options, hostVsStores, principal) {
     name = JSON.parse(name);
     if (!name || !name.length) {
       // This means that details about the db in this particular host are
       // requested.
       let dbs = [];
       if (hostVsStores.has(host)) {
         for (let [, db] of hostVsStores.get(host)) {
           db = indexedDBHelpers.patchMetadataMapsAndProtos(db);
@@ -1849,45 +1849,47 @@ var indexedDBHelpers = {
 
         for (let objectStore2 of objectStores2) {
           objectStores.push(objectStore2[1].toObject());
         }
       }
       return this.backToChild("getValuesForHost", {objectStores: objectStores});
     }
     // Get either all entries from the object store, or a particular id
-    let result = yield this.getObjectStoreData(host, db2, objectStore, id,
+    let result = yield this.getObjectStoreData(host, principal, db2, objectStore, id,
                                                options.index, options.size);
     return this.backToChild("getValuesForHost", {result: result});
   }),
 
   /**
    * Returns all or requested entries from a particular objectStore from the db
    * in the given host.
    *
    * @param {string} host
    *        The given host.
+   * @param {nsIPrincipal} principal
+   *        The principal of the given document.
    * @param {string} dbName
    *        The name of the indexed db from the above host.
    * @param {string} objectStore
    *        The name of the object store from the above db.
    * @param {string} id
    *        id of the requested entry from the above object store.
    *        null if all entries from the above object store are requested.
    * @param {string} index
    *        name of the IDBIndex to be iterated on while fetching entries.
    *        null or "name" if no index is to be iterated.
    * @param {number} offset
    *        ofsset of the entries to be fetched.
    * @param {number} size
    *        The intended size of the entries to be fetched.
    */
   getObjectStoreData:
-  function(host, dbName, objectStore, id, index, offset, size) {
-    let request = this.openWithOrigin(host, dbName);
+  function(host, principal, dbName, objectStore, id, index, offset, size) {
+    let request = this.openWithPrincipal(principal, dbName);
     let success = promise.defer();
     let data = [];
     let db;
 
     if (!size || size > MAX_STORE_OBJECT_COUNT) {
       size = MAX_STORE_OBJECT_COUNT;
     }
 
@@ -1981,30 +1983,34 @@ var indexedDBHelpers = {
   },
 
   handleChildRequest: function(msg) {
     let host;
     let name;
     let args = msg.data.args;
 
     switch (msg.json.method) {
-      case "getDBMetaData":
+      case "getDBMetaData": {
         host = args[0];
-        name = args[1];
-        return indexedDBHelpers.getDBMetaData(host, name);
+        let principal = args[1];
+        name = args[2];
+        return indexedDBHelpers.getDBMetaData(host, principal, name);
+      }
       case "getDBNamesForHost":
         host = args[0];
         return indexedDBHelpers.getDBNamesForHost(host);
-      case "getValuesForHost":
+      case "getValuesForHost": {
         host = args[0];
         name = args[1];
         let options = args[2];
         let hostVsStores = args[3];
+        let principal = args[4];
         return indexedDBHelpers.getValuesForHost(host, name, options,
-                                                 hostVsStores);
+                                                 hostVsStores, principal);
+      }
       default:
         console.error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD", msg.json.method);
         throw new Error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD");
     }
   }
 };
 
 /**
@@ -2170,16 +2176,28 @@ var StorageActor = exports.StorageActor 
                    .currentInnerWindowID;
       if (id == innerID) {
         return win;
       }
     }
     return null;
   },
 
+  getWindowFromHost: function(host) {
+    for (let win of this.childWindowPool.values()) {
+      let origin = win.document
+                      .nodePrincipal
+                      .originNoSuffix;
+      if (origin === host) {
+        return win;
+      }
+    }
+    return null;
+  },
+
   /**
    * Event handler for any docshell update. This lets us figure out whenever
    * any new window is added, or an existing window is removed.
    */
   observe: function(subject, topic) {
     if (subject.location &&
         (!subject.location.href || subject.location.href == "about:blank")) {
       return null;
--- a/dom/animation/test/css-animations/file_animation-cancel.html
+++ b/dom/animation/test/css-animations/file_animation-cancel.html
@@ -12,105 +12,96 @@
   from { margin-left: 100px }
   to { margin-left: 200px }
 }
 </style>
 <body>
 <script>
 'use strict';
 
-async_test(function(t) {
+promise_test(function(t) {
   var div = addDiv(t, { style: 'animation: translateAnim 100s' });
+  var animation = div.getAnimations()[0];
 
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(function() {
+  return animation.ready.then(function() {
     assert_not_equals(getComputedStyle(div).transform, 'none',
                       'transform style is animated before cancelling');
     animation.cancel();
     assert_equals(getComputedStyle(div).transform, 'none',
                   'transform style is no longer animated after cancelling');
-    t.done();
-  }));
+  });
 }, 'Animated style is cleared after cancelling a running CSS animation');
 
-async_test(function(t) {
+promise_test(function(t) {
   var div = addDiv(t, { style: 'animation: translateAnim 100s forwards' });
-
   var animation = div.getAnimations()[0];
   animation.finish();
 
-  animation.ready.then(t.step_func(function() {
+  return animation.ready.then(function() {
     assert_not_equals(getComputedStyle(div).transform, 'none',
                       'transform style is filling before cancelling');
     animation.cancel();
     assert_equals(getComputedStyle(div).transform, 'none',
                   'fill style is cleared after cancelling');
-    t.done();
-  }));
+  });
 }, 'Animated style is cleared after cancelling a filling CSS animation');
 
-async_test(function(t) {
+promise_test(function(t) {
   var div = addDiv(t, { style: 'animation: translateAnim 100s' });
   var animation = div.getAnimations()[0];
-
   div.addEventListener('animationend', t.step_func(function() {
     assert_unreached('Got unexpected end event on cancelled animation');
   }));
 
-  animation.ready.then(t.step_func(function() {
+  return animation.ready.then(function() {
     // Seek to just before the end then cancel
     animation.currentTime = 99.9 * 1000;
     animation.cancel();
 
     // Then wait a couple of frames and check that no event was dispatched
     return waitForAnimationFrames(2);
-  })).then(t.step_func(function() {
-    t.done();
-  }));
+  });
 }, 'Cancelled CSS animations do not dispatch events');
 
 test(function(t) {
   var div = addDiv(t, { style: 'animation: marginLeftAnim 100s linear' });
+  var animation = div.getAnimations()[0];
+  animation.cancel();
 
-  var animation = div.getAnimations()[0];
-
-  animation.cancel();
   assert_equals(getComputedStyle(div).marginLeft, '0px',
                 'margin-left style is not animated after cancelling');
 
   animation.currentTime = 50 * 1000;
   assert_equals(getComputedStyle(div).marginLeft, '50px',
                 'margin-left style is updated when cancelled animation is'
                 + ' seeked');
 }, 'After cancelling an animation, it can still be seeked');
 
-async_test(function(t) {
+promise_test(function(t) {
   var div =
     addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
+  var animation = div.getAnimations()[0];
 
-  var animation = div.getAnimations()[0];
-  animation.ready.then(t.step_func(function() {
+  return animation.ready.then(function() {
     animation.cancel();
     assert_equals(getComputedStyle(div).marginLeft, '0px',
                   'margin-left style is not animated after cancelling');
     animation.play();
     assert_equals(getComputedStyle(div).marginLeft, '100px',
                   'margin-left style is animated after re-starting animation');
     return animation.ready;
-  })).then(t.step_func(function() {
+  }).then(function() {
     assert_equals(animation.playState, 'running',
                   'Animation succeeds in running after being re-started');
-    t.done();
-  }));
+  });
 }, 'After cancelling an animation, it can still be re-used');
 
 test(function(t) {
   var div =
     addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
-
   var animation = div.getAnimations()[0];
   animation.cancel();
   assert_equals(getComputedStyle(div).marginLeft, '0px',
                 'margin-left style is not animated after cancelling');
 
   // Trigger a change to some animation properties and check that this
   // doesn't cause the animation to become live again
   div.style.animationDuration = '200s';
@@ -121,17 +112,16 @@ test(function(t) {
   assert_equals(animation.playState, 'idle',
                 'Animation is still idle after updating animation-duration');
 }, 'After cancelling an animation, updating animation properties doesn\'t make'
    + ' it live again');
 
 test(function(t) {
   var div =
     addDiv(t, { style: 'animation: marginLeftAnim100To200 100s linear' });
-
   var animation = div.getAnimations()[0];
   animation.cancel();
   assert_equals(getComputedStyle(div).marginLeft, '0px',
                 'margin-left style is not animated after cancelling');
 
   // Make some changes to animation-play-state and check that the
   // animation doesn't become live again. This is because it should be
   // possible to cancel an animation from script such that all future
deleted file mode 100644
--- a/dom/animation/test/css-animations/file_animation-play.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="../testcommon.js"></script>
-<style>
-@keyframes abc {
-  to { transform: translate(10px) }
-}
-</style>
-<body>
-<script>
-'use strict';
-
-async_test(function(t) {
-  var div = addDiv(t, { style: 'animation: abc 100s infinite' });
-  var animation = div.getAnimations()[0];
-
-  animation.ready.then(t.step_func(function() {
-    // Seek to a time outside the active range so that play() will have to
-    // snap back to the start
-    animation.currentTime = -5000;
-    animation.playbackRate = -1;
-
-    assert_throws('InvalidStateError',
-                  function () { animation.play(); },
-                  'Expect InvalidStateError exception on calling play() ' +
-                  'with a negative playbackRate and infinite-duration ' +
-                  'animation');
-    t.done();
-  }));
-}, 'play() throws when seeking an infinite-duration animation played in ' +
-   'reverse');
-
-done();
-</script>
-</body>
--- a/dom/animation/test/css-animations/file_animation-playstate.html
+++ b/dom/animation/test/css-animations/file_animation-playstate.html
@@ -3,87 +3,69 @@
 <script src="../testcommon.js"></script>
 <style>
 @keyframes anim { }
 </style>
 <body>
 <script>
 'use strict';
 
-async_test(function(t) {
+promise_test(function(t) {
   var div = addDiv(t);
   var cs = window.getComputedStyle(div);
   div.style.animation = 'anim 1000s';
-
   var animation = div.getAnimations()[0];
   assert_equals(animation.playState, 'pending');
 
-  animation.ready.then(t.step_func(function() {
+  return animation.ready.then(function() {
     assert_equals(animation.playState, 'running');
-    t.done();
-  }));
+  });
 }, 'Animation returns correct playState when running');
 
-async_test(function(t) {
+promise_test(function(t) {
   var div = addDiv(t);
   var cs = window.getComputedStyle(div);
   div.style.animation = 'anim 1000s paused';
-
   var animation = div.getAnimations()[0];
   assert_equals(animation.playState, 'pending');
 
-  animation.ready.then(t.step_func(function() {
+  return animation.ready.then(function() {
     assert_equals(animation.playState, 'paused');
-    t.done();
-  }));
+  });
 }, 'Animation returns correct playState when paused');
 
-async_test(function(t) {
+promise_test(function(t) {
   var div = addDiv(t);
   var cs = window.getComputedStyle(div);
   div.style.animation = 'anim 1000s';
-
   var animation = div.getAnimations()[0];
   animation.pause();
   assert_equals(animation.playState, 'pending');
 
-  animation.ready.then(t.step_func(function() {
+  return animation.ready.then(function() {
     assert_equals(animation.playState, 'paused');
-    t.done();
-  }));
+  });
 }, 'Animation.playState updates when paused by script');
 
 test(function(t) {
   var div = addDiv(t);
   var cs = window.getComputedStyle(div);
   div.style.animation = 'anim 1000s paused';
-
   var animation = div.getAnimations()[0];
   div.style.animationPlayState = 'running';
+
   // This test also checks that calling playState flushes style
   assert_equals(animation.playState, 'pending',
                 'Animation.playState reports pending after updating'
                 + ' animation-play-state (got: ' + animation.playState + ')');
 }, 'Animation.playState updates when resumed by setting style');
 
 test(function(t) {
   var div = addDiv(t);
   div.style.animation = 'anim 1000s';
-
   var animation = div.getAnimations()[0];
   animation.cancel();
   assert_equals(animation.playState, 'idle');
 }, 'Animation returns correct playState when cancelled');
 
-test(function(t) {
-  var div = addDiv(t);
-  div.style.animation = 'anim 1000s';
-
-  var animation = div.getAnimations()[0];
-  animation.cancel();
-  animation.currentTime = 50 * 1000;
-  assert_equals(animation.playState, 'paused',
-                'After seeking an idle animation, it is effectively paused');
-}, 'After cancelling an animation, seeking it makes it paused');
-
 done();
 </script>
 </body>
deleted file mode 100644
--- a/dom/animation/test/css-animations/test_animation-play.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id="log"></div>
-<script>
-'use strict';
-setup({explicit_done: true});
-SpecialPowers.pushPrefEnv(
-  { "set": [["dom.animations-api.core.enabled", true]]},
-  function() {
-    window.open("file_animation-play.html");
-  });
-</script>
-</html>
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -7,17 +7,16 @@ support-files =
   css-animations/file_animation-computed-timing.html
   css-animations/file_animation-currenttime.html
   css-animations/file_animation-finish.html
   css-animations/file_animation-finished.html
   css-animations/file_animation-id.html
   css-animations/file_animation-oncancel.html
   css-animations/file_animation-onfinish.html
   css-animations/file_animation-pausing.html
-  css-animations/file_animation-play.html
   css-animations/file_animation-playstate.html
   css-animations/file_animation-ready.html
   css-animations/file_animation-reverse.html
   css-animations/file_animation-starttime.html
   css-animations/file_animations-dynamic-changes.html
   css-animations/file_cssanimation-animationname.html
   css-animations/file_document-get-animations.html
   css-animations/file_effect-target.html
@@ -48,17 +47,16 @@ support-files =
 [css-animations/test_animation-computed-timing.html]
 [css-animations/test_animation-currenttime.html]
 [css-animations/test_animation-finish.html]
 [css-animations/test_animation-finished.html]
 [css-animations/test_animation-id.html]
 [css-animations/test_animation-oncancel.html]
 [css-animations/test_animation-onfinish.html]
 [css-animations/test_animation-pausing.html]
-[css-animations/test_animation-play.html]
 [css-animations/test_animation-playstate.html]
 [css-animations/test_animation-ready.html]
 [css-animations/test_animation-reverse.html]
 [css-animations/test_animation-starttime.html]
 [css-animations/test_cssanimation-animationname.html]
 [css-animations/test_document-get-animations.html]
 [css-animations/test_effect-target.html]
 [css-animations/test_element-get-animations.html]
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -690,27 +690,16 @@ public:
   {
     NS_ASSERTION(mFile, "must have file");
     if (aContentType.IsEmpty()) {
       // Lazily get the content type and size
       mContentType.SetIsVoid(true);
     }
   }
 
-  // Create as a file to be later initialized
-  BlobImplFile()
-    : BlobImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
-    , mWholeFile(true)
-    , mIsTemporary(false)
-  {
-    // Lazily get the content type and size
-    mContentType.SetIsVoid(true);
-    mName.SetIsVoid(true);
-  }
-
   // Overrides
   virtual uint64_t GetSize(ErrorResult& aRv) override;
   virtual void GetType(nsAString& aType) override;
   virtual int64_t GetLastModified(ErrorResult& aRv) override;
   virtual void SetLastModified(int64_t aLastModified) override;
   virtual void GetMozFullPathInternal(nsAString& aFullPath,
                                       ErrorResult& aRv) const override;
   virtual void GetInternalStream(nsIInputStream** aInputStream,
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -87,10 +87,12 @@ MSG_DEF(MSG_PROMISE_CAPABILITY_HAS_SOMET
 MSG_DEF(MSG_PROMISE_RESOLVE_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the resolve function.")
 MSG_DEF(MSG_PROMISE_REJECT_FUNCTION_NOT_CALLABLE, 0, JSEXN_TYPEERR, "A Promise subclass passed a non-callable value as the reject function.")
 MSG_DEF(MSG_PROMISE_ARG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable")
 MSG_DEF(MSG_IS_NOT_PROMISE, 1, JSEXN_TYPEERR, "{0} is not a Promise")
 MSG_DEF(MSG_SW_INSTALL_ERROR, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} encountered an error during installation.")
 MSG_DEF(MSG_SW_SCRIPT_THREW, 2, JSEXN_TYPEERR, "ServiceWorker script at {0} for scope {1} threw an exception during script evaluation.")
 MSG_DEF(MSG_TYPEDARRAY_IS_SHARED, 1, JSEXN_TYPEERR, "{0} can't be a typed array on SharedArrayBuffer")
 MSG_DEF(MSG_CACHE_ADD_FAILED_RESPONSE, 3, JSEXN_TYPEERR, "Cache got {0} response with bad status {1} while trying to add request {2}")
+MSG_DEF(MSG_SW_UPDATE_BAD_REGISTRATION, 2, JSEXN_TYPEERR, "Failed to update the ServiceWorker for scope {0] because the registration has been {1} since the update was scheduled.")
 MSG_DEF(MSG_INVALID_DURATION_ERROR, 1, JSEXN_TYPEERR, "Invalid duration '{0}'.")
-MSG_DEF(MSG_INVALID_EASING_ERROR, 1, JSEXN_TYPEERR, "Invalid easing '{0}'.")
\ No newline at end of file
+MSG_DEF(MSG_INVALID_EASING_ERROR, 1, JSEXN_TYPEERR, "Invalid easing '{0}'.")
+MSG_DEF(MSG_USELESS_SETTIMEOUT, 1, JSEXN_TYPEERR, "Useless {0} call (missing quotes around argument?)")
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -18,19 +18,22 @@
 #include "BrowserElementAudioChannel.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsVariant.h"
 #include "mozilla/dom/BrowserElementDictionariesBinding.h"
 #include "mozilla/dom/CustomEvent.h"
+#include "mozilla/layout/RenderFrameParent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::layers;
+using namespace mozilla::layout;
 
 namespace {
 
 using mozilla::BrowserElementParent;
 /**
  * Create an <iframe mozbrowser> owned by the same document as
  * aOpenerFrameElement.
  */
@@ -200,19 +203,22 @@ BrowserElementParent::DispatchOpenWindow
 
   return BrowserElementParent::OPEN_WINDOW_IGNORED;
 }
 
 /*static*/
 BrowserElementParent::OpenWindowResult
 BrowserElementParent::OpenWindowOOP(TabParent* aOpenerTabParent,
                                     TabParent* aPopupTabParent,
+                                    PRenderFrameParent* aRenderFrame,
                                     const nsAString& aURL,
                                     const nsAString& aName,
-                                    const nsAString& aFeatures)
+                                    const nsAString& aFeatures,
+                                    TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                    uint64_t* aLayersId)
 {
   // Create an iframe owned by the same document which owns openerFrameElement.
   nsCOMPtr<Element> openerFrameElement = aOpenerTabParent->GetOwnerElement();
   NS_ENSURE_TRUE(openerFrameElement,
                  BrowserElementParent::OPEN_WINDOW_IGNORED);
   RefPtr<HTMLIFrameElement> popupFrameElement =
     CreateIframe(openerFrameElement, aName, /* aRemote = */ true);
 
@@ -236,16 +242,23 @@ BrowserElementParent::OpenWindowOOP(TabP
     return opened;
   }
 
   // The popup was not blocked, so hook up the frame element and the popup tab
   // parent, and return success.
   aPopupTabParent->SetOwnerElement(popupFrameElement);
   popupFrameElement->AllowCreateFrameLoader();
   popupFrameElement->CreateRemoteFrameLoader(aPopupTabParent);
+
+  RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
+  if (!aPopupTabParent->SetRenderFrame(rfp) ||
+      !aPopupTabParent->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
+    return BrowserElementParent::OPEN_WINDOW_IGNORED;
+  }
+
   return opened;
 }
 
 /* static */
 BrowserElementParent::OpenWindowResult
 BrowserElementParent::OpenWindowInProcess(nsPIDOMWindowOuter* aOpenerWindow,
                                           nsIURI* aURI,
                                           const nsAString& aName,
--- a/dom/browser-element/BrowserElementParent.h
+++ b/dom/browser-element/BrowserElementParent.h
@@ -17,16 +17,24 @@ class nsIDOMWindow;
 class nsIURI;
 
 namespace mozilla {
 
 namespace dom {
 class TabParent;
 } // namespace dom
 
+namespace layers {
+struct TextureFactoryIdentifier;
+} // namespace layers
+
+namespace layout {
+class PRenderFrameParent;
+} // namespace layout
+
 /**
  * BrowserElementParent implements a portion of the parent-process side of
  * <iframe mozbrowser>.
  *
  * Most of the parent-process side of <iframe mozbrowser> is implemented in
  * BrowserElementParent.js.  This file implements the few parts of this
  * functionality which must be written in C++.
  *
@@ -82,19 +90,22 @@ public:
    *                        live.
    * @return an OpenWindowresult that describes whether the embedder added the
    *         frame to a document and whether it called preventDefault to prevent
    *         the platform from handling the open request.
    */
   static OpenWindowResult
   OpenWindowOOP(dom::TabParent* aOpenerTabParent,
                 dom::TabParent* aPopupTabParent,
+                layout::PRenderFrameParent* aRenderFrame,
                 const nsAString& aURL,
                 const nsAString& aName,
-                const nsAString& aFeatures);
+                const nsAString& aFeatures,
+                layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                uint64_t* aLayersId);
 
   /**
    * Handle a window.open call from an in-process <iframe mozbrowser>.
    *
    * (These parameter types are silly, but they match what our caller has in
    * hand.  Feel free to add an override, if they are inconvenient to you.)
    *
    * @param aURI the URI the new window should load.  May be null.
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -836,29 +836,44 @@ WebGLContext::FakeBlackTexture::FakeBlac
     // We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
     // minimize the risk of running into a driver bug in texImage2D, as it is a bit
     // unusual maybe to create 1x1 textures, and the stack may not have the alignment that
     // TexImage2D expects.
 
     const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE};
     UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation.
 
+    MOZ_ASSERT(gl->IsCurrent());
     if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
         for (int i = 0; i < 6; ++i) {
             const TexImageTarget curTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
             const GLenum error = DoTexImage(mGL, curTarget.get(), 0, &dui, 1, 1, 1,
                                             zeros.get());
-            if (error)
-                MOZ_CRASH("Unexpected error during FakeBlack creation.");
+            if (error) {
+                const nsPrintfCString text("DoTexImage failed with `error`: 0x%04x, "
+                                           "for `curTarget`: 0x%04x, "
+                                           "`dui`: {0x%04x, 0x%04x, 0x%04x}.",
+                                           error, curTarget.get(), dui.internalFormat,
+                                           dui.unpackFormat, dui.unpackType);
+                gfxCriticalError() << text.BeginReading();
+                MOZ_CRASH("Unexpected error during cube map FakeBlack creation.");
+            }
         }
     } else {
         const GLenum error = DoTexImage(mGL, target.get(), 0, &dui, 1, 1, 1,
                                         zeros.get());
-        if (error)
+        if (error) {
+            const nsPrintfCString text("DoTexImage failed with `error`: 0x%04x, "
+                                       "for `target`: 0x%04x, "
+                                       "`dui`: {0x%04x, 0x%04x, 0x%04x}.",
+                                       error, target.get(), dui.internalFormat,
+                                       dui.unpackFormat, dui.unpackType);
+            gfxCriticalError() << text.BeginReading();
             MOZ_CRASH("Unexpected error during FakeBlack creation.");
+        }
     }
 }
 
 WebGLContext::FakeBlackTexture::~FakeBlackTexture()
 {
     mGL->MakeCurrent();
     mGL->fDeleteTextures(1, &mGLName);
 }
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -2,17 +2,17 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 TEST_DIRS += ['compiledtest']
 
 # Number changes to this file to avoid bug 1081323 (clobber after changing a manifest):
-# 11
+# 12
 
 MOCHITEST_MANIFESTS += [
     'test/crossorigin/mochitest.ini',
     'test/mochitest-subsuite-webgl.ini',
     'test/mochitest.ini',
 ]
 
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome/chrome.ini']
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -43,16 +43,17 @@ fail-if = (os == 'android') || (os == 'l
 fail-if = (os == 'mac' && os_version == '10.6')
 [webgl-mochitest/ensure-exts/test_WEBGL_draw_buffers.html]
 # Win7 is 6.1
 fail-if = (os == 'android') || (os == 'win' && (os_version == '5.1' || os_version == '6.1'))
 
 [webgl-mochitest/ensure-exts/test_common.html]
 
 
+[webgl-mochitest/test_backends.html]
 [webgl-mochitest/test_backbuffer_channels.html]
 fail-if = (os == 'b2g')
 [webgl-mochitest/test_depth_readpixels.html]
 [webgl-mochitest/test_capture.html]
 support-files = captureStream_common.js
 [webgl-mochitest/test_cubemap_must_be_square.html]
 [webgl-mochitest/test_depth_tex_lazy_clear.html]
 [webgl-mochitest/test_draw.html]
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test_backends.html
@@ -0,0 +1,170 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset='UTF-8'>
+  <script src='/tests/SimpleTest/SimpleTest.js'></script>
+  <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+</head>
+<body>
+<script>
+
+function RunWithPrefs(prefPairList, func) {
+  var prefEnv = {'set': prefPairList};
+  try {
+    SpecialPowers.pushPrefEnv(prefEnv, func);
+  } catch (e) {
+    console.log('Warning: Failed to set prefs: ' + JSON.stringify(prefPairList));
+    func();
+  }
+}
+
+////////////////////////////////////////
+
+var ANGLE_IS_SINGLETON = true;
+
+var expectD3DType;
+try {
+  // code borrowed from browser/modules/test/browser_taskbar_preview.js
+  var version = SpecialPowers.Services.sysinfo.getProperty('version');
+  version = parseFloat(version);
+
+  // Version 6.0 is Vista, 6.1 is 7.
+  // Our Win7 slaves prefer d3d9, though!
+  if (version <= 6.1)
+    expectD3DType = 'd3d9';
+  else
+    expectD3DType = 'd3d11';
+} catch (e) {
+  expectD3DType = 'd3d11';
+}
+
+function GetRenderer() {
+  var c = document.createElement('canvas');
+  var gl = c.getContext('experimental-webgl');
+  if (!gl)
+    return undefined;
+
+  var ext = gl.getExtension('WEBGL_debug_renderer_info');
+  if (!ext)
+    throw new Error('Requires WEBGL_debug_renderer_info.');
+
+  var renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
+  return renderer;
+}
+
+function GetRendererType() {
+  var renderer = GetRenderer();
+  if (renderer === undefined)
+    return 'none';
+
+  if (renderer.includes('ANGLE')) {
+    if (renderer.includes('Microsoft Basic Render Driver')) // Also includes 'Direct3D11'.
+      return 'warp';
+    if (renderer.includes('Direct3D11'))
+      return 'd3d11';
+    if (renderer.includes('Direct3D9'))
+      return 'd3d9';
+
+  } else {
+    return 'gl';
+  }
+
+  throw new Error('Unrecognized renderer type for: ' + renderer);
+}
+
+function TestActualType(testName, expectedType) {
+  var actualType = GetRendererType();
+  ok(actualType == expectedType,
+     '[' + testName + '] Expected ' + expectedType + ', was ' + actualType);
+}
+
+////////////////////////////////////////
+
+function TestDefault() {
+  var expectedType = 'gl';
+  var isWindows = (navigator.platform.indexOf('Win') == 0);
+  if (isWindows) {
+    expectedType = expectD3DType;
+  }
+  TestActualType('TestDefault', expectedType);
+
+  if (isWindows && !ANGLE_IS_SINGLETON) {
+    var prefPairList = [
+      ['webgl.angle.force-warp', true],
+    ];
+    RunWithPrefs(prefPairList, TestWARP);
+    return;
+  }
+
+  var prefPairList = [
+    ['webgl.disabled', true],
+  ];
+  RunWithPrefs(prefPairList, TestDisabled);
+  return;
+}
+
+
+function TestWARP() {
+  var expectedType = (expectD3DType == 'd3d11') ? 'warp' : 'none';
+  TestActualType('TestWARP', expectedType);
+
+  var prefPairList = [
+    ['webgl.angle.force-warp', false],
+    ['webgl.angle.force-d3d11', true],
+  ];
+  RunWithPrefs(prefPairList, TestD3D11);
+}
+
+
+function TestD3D11() {
+  var expectedType = (expectD3DType == 'd3d11') ? 'd3d11' : 'none';
+  TestActualType('TestD3D11', expectedType);
+
+  var prefPairList = [
+    ['webgl.angle.force-d3d11', false],
+    ['webgl.angle.try-d3d11', false],
+  ];
+  RunWithPrefs(prefPairList, TestD3D9);
+}
+
+
+function TestD3D9() {
+  TestActualType('TestD3D9', 'd3d9');
+
+  var prefPairList = [
+    ['webgl.angle.try-d3d11', true],
+    ['webgl.disable-angle', true],
+  ];
+  RunWithPrefs(prefPairList, TestWinGL);
+}
+
+
+function TestWinGL() {
+  TestActualType('TestWinGL', 'gl');
+
+  var prefPairList = [
+    ['webgl.disabled', true],
+  ];
+  RunWithPrefs(prefPairList, TestDisabled);
+}
+
+
+function TestDisabled() {
+  TestActualType('TestDisabled', 'none');
+
+  SimpleTest.finish();
+}
+
+////////////////////////////////////////
+
+SimpleTest.waitForExplicitFinish();
+
+var prefPairList = [
+  ['webgl.force-enabled', true],
+  ['webgl.enable-debug-renderer-info', true],
+];
+RunWithPrefs(prefPairList, TestDefault);
+
+</script>
+</body>
+</html>
--- a/dom/encoding/EncodingUtils.cpp
+++ b/dom/encoding/EncodingUtils.cpp
@@ -10,21 +10,21 @@
 #include "nsUConvPropertySearch.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsComponentManagerUtils.h"
 
 namespace mozilla {
 namespace dom {
 
-static const char* const labelsEncodings[][3] = {
+static const nsUConvProp labelsEncodings[] = {
 #include "labelsencodings.properties.h"
 };
 
-static const char* const encodingsGroups[][3] = {
+static const nsUConvProp encodingsGroups[] = {
 #include "encodingsgroups.properties.h"
 };
 
 bool
 EncodingUtils::FindEncodingForLabel(const nsACString& aLabel,
                                     nsACString& aOutEncoding)
 {
   // Save aLabel first because it may refer the same string as aOutEncoding.
--- a/dom/encoding/FallbackEncoding.cpp
+++ b/dom/encoding/FallbackEncoding.cpp
@@ -10,25 +10,25 @@
 #include "nsUConvPropertySearch.h"
 #include "nsIChromeRegistry.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 
 namespace mozilla {
 namespace dom {
 
-static const char* const localesFallbacks[][3] = {
+static const nsUConvProp localesFallbacks[] = {
 #include "localesfallbacks.properties.h"
 };
 
-static const char* const domainsFallbacks[][3] = {
+static const nsUConvProp domainsFallbacks[] = {
 #include "domainsfallbacks.properties.h"
 };
 
-static const char* const nonParticipatingDomains[][3] = {
+static const nsUConvProp nonParticipatingDomains[] = {
 #include "nonparticipatingdomains.properties.h"
 };
 
 FallbackEncoding* FallbackEncoding::sInstance = nullptr;
 bool FallbackEncoding::sGuessFallbackFromTopLevelDomain = true;
 
 FallbackEncoding::FallbackEncoding()
 {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2298,18 +2298,18 @@ EventStateManager::SendLineScrollEvent(n
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.mTime = aEvent->mTime;
   event.mTimeStamp = aEvent->mTimeStamp;
   event.mModifiers = aEvent->mModifiers;
   event.buttons = aEvent->buttons;
-  event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
-  event.delta = aDelta;
+  event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
+  event.mDelta = aDelta;
   event.inputSource = aEvent->inputSource;
 
   nsEventStatus status = nsEventStatus_eIgnore;
   EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
                             &event, nullptr, &status);
   aState.mDefaultPrevented =
     event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
   aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
@@ -2338,18 +2338,18 @@ EventStateManager::SendPixelScrollEvent(
   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.mTime = aEvent->mTime;
   event.mTimeStamp = aEvent->mTimeStamp;
   event.mModifiers = aEvent->mModifiers;
   event.buttons = aEvent->buttons;
-  event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
-  event.delta = aPixelDelta;
+  event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
+  event.mDelta = aPixelDelta;
   event.inputSource = aEvent->inputSource;
 
   nsEventStatus status = nsEventStatus_eIgnore;
   EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
                             &event, nullptr, &status);
   aState.mDefaultPrevented =
     event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
   aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
@@ -4512,16 +4512,23 @@ EventStateManager::FireDragEnterOrExit(n
         aMessage == eDragEnter) {
       UpdateDragDataTransfer(&event);
     }
   }
 
   // Finally dispatch the event to the frame
   if (aTargetFrame)
     aTargetFrame->HandleEvent(aPresContext, &event, &status);
+
+  if (aMessage == eDragExit && IsRemoteTarget(aTargetContent)) {
+    nsEventStatus status = nsEventStatus_eIgnore;
+    WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), aMessage, aDragEvent->widget);
+    remoteEvent.AssignDragEventData(*aDragEvent, true);
+    HandleCrossProcessEvent(&remoteEvent, &status);
+  }
 }
 
 void
 EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent)
 {
   NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!");
   if (!dragEvent->mDataTransfer) {
     return;
--- a/dom/events/MouseScrollEvent.cpp
+++ b/dom/events/MouseScrollEvent.cpp
@@ -24,17 +24,17 @@ MouseScrollEvent::MouseScrollEvent(Event
   } else {
     mEventIsInternal = true;
     mEvent->mTime = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
     static_cast<WidgetMouseEventBase*>(mEvent)->inputSource =
       nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
   }
 
-  mDetail = mEvent->AsMouseScrollEvent()->delta;
+  mDetail = mEvent->AsMouseScrollEvent()->mDelta;
 }
 
 NS_IMPL_ADDREF_INHERITED(MouseScrollEvent, MouseEvent)
 NS_IMPL_RELEASE_INHERITED(MouseScrollEvent, MouseEvent)
 
 NS_INTERFACE_MAP_BEGIN(MouseScrollEvent)
 NS_INTERFACE_MAP_END_INHERITING(MouseEvent)
 
@@ -55,24 +55,24 @@ MouseScrollEvent::InitMouseScrollEvent(c
                                        uint16_t aButton,
                                        EventTarget* aRelatedTarget,
                                        int32_t aAxis)
 {
   MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
                              aScreenX, aScreenY, aClientX, aClientY,
                              aCtrlKey, aAltKey, aShiftKey, aMetaKey, aButton,
                              aRelatedTarget);
-  mEvent->AsMouseScrollEvent()->isHorizontal =
+  mEvent->AsMouseScrollEvent()->mIsHorizontal =
     (aAxis == nsIDOMMouseScrollEvent::HORIZONTAL_AXIS);
 }
 
 int32_t
 MouseScrollEvent::Axis()
 {
-  return mEvent->AsMouseScrollEvent()->isHorizontal ?
+  return mEvent->AsMouseScrollEvent()->mIsHorizontal ?
           static_cast<int32_t>(nsIDOMMouseScrollEvent::HORIZONTAL_AXIS) :
           static_cast<int32_t>(nsIDOMMouseScrollEvent::VERTICAL_AXIS);
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
--- a/dom/indexedDB/test/browser_permissionsPrompt.html
+++ b/dom/indexedDB/test/browser_permissionsPrompt.html
@@ -1,14 +1,15 @@
 <!--
   Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/
 -->
 <html>
   <head>
+    <meta charset=UTF-8>
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
       function testSteps()
       {
         const name = window.location.pathname;
 
         let request = indexedDB.open(name, { version: 1,
--- a/dom/indexedDB/test/browser_permissionsPromptDeny.js
+++ b/dom/indexedDB/test/browser_permissionsPromptDeny.js
@@ -15,24 +15,26 @@ function setUsePrivateBrowsing(browser, 
 
   return ContentTask.spawn(browser, val, function* (val) {
     docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing = val;
   });
 };
 
 
 function promiseMessage(aMessage) {
-  return new Promise(function(resolve, reject) {
-    content.addEventListener("message", function messageListener(event) {
-      content.removeEventListener("message", messageListener);
-      is(event.data, aMessage, "received " + aMessage);
-      if (event.data == aMessage)
-        resolve();
-      else
-        reject();
+  return ContentTask.spawn(gBrowser.selectedBrowser, aMessage, function* (aMessage) {
+    yield new Promise((resolve, reject) => {
+      content.addEventListener("message", function messageListener(event) {
+        content.removeEventListener("message", messageListener);
+        is(event.data, aMessage, "received " + aMessage);
+        if (event.data == aMessage)
+          resolve();
+        else
+          reject();
+      });
     });
   });
 }
 
 add_task(function test1() {
   removePermission(testPageURL, "indexedDB");
 
   info("creating tab");
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -847,21 +847,26 @@ ContentChild::ProvideWindowCommon(TabChi
     url.SetIsVoid(true);
   }
 
   nsString name(aName);
   nsAutoCString features(aFeatures);
   nsTArray<FrameScriptInfo> frameScripts;
   nsCString urlToLoad;
 
+  PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
+  TextureFactoryIdentifier textureFactoryIdentifier;
+  uint64_t layersId = 0;
+
   if (aIframeMoz) {
     MOZ_ASSERT(aTabOpener);
-    newChild->SendBrowserFrameOpenWindow(aTabOpener, NS_ConvertUTF8toUTF16(url),
+    newChild->SendBrowserFrameOpenWindow(aTabOpener, renderFrame, NS_ConvertUTF8toUTF16(url),
                                          name, NS_ConvertUTF8toUTF16(features),
-                                         aWindowIsNew);
+                                         aWindowIsNew, &textureFactoryIdentifier,
+                                         &layersId);
   } else {
     nsAutoCString baseURIString;
     if (aTabOpener) {
       auto* opener = nsPIDOMWindowOuter::From(aParent);
       nsCOMPtr<nsIDocument> doc = opener->GetDoc();
       nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
       if (!baseURI) {
         NS_ERROR("nsIDocument didn't return a base URI");
@@ -880,47 +885,47 @@ ContentChild::ProvideWindowCommon(TabChi
       nsCOMPtr<nsIContentViewer> cv;
       openerDocShell->GetContentViewer(getter_AddRefs(cv));
       if (cv) {
         cv->GetFullZoom(&fullZoom);
       }
     }
 
     nsresult rv;
-    if (!SendCreateWindow(aTabOpener, newChild,
+    if (!SendCreateWindow(aTabOpener, newChild, renderFrame,
                           aChromeFlags, aCalledFromJS, aPositionSpecified,
                           aSizeSpecified, url,
                           name, features,
                           baseURIString,
                           openerDocShell
                             ? openerDocShell->GetOriginAttributes()
                             : DocShellOriginAttributes(),
                           fullZoom,
                           &rv,
                           aWindowIsNew,
                           &frameScripts,
-                          &urlToLoad)) {
+                          &urlToLoad,
+                          &textureFactoryIdentifier,
+                          &layersId)) {
+      PRenderFrameChild::Send__delete__(renderFrame);
       return NS_ERROR_NOT_AVAILABLE;
     }
 
     if (NS_FAILED(rv)) {
+      PRenderFrameChild::Send__delete__(renderFrame);
+      PBrowserChild::Send__delete__(newChild);
       return rv;
     }
   }
   if (!*aWindowIsNew) {
+    PRenderFrameChild::Send__delete__(renderFrame);
     PBrowserChild::Send__delete__(newChild);
     return NS_ERROR_ABORT;
   }
 
-  TextureFactoryIdentifier textureFactoryIdentifier;
-  uint64_t layersId = 0;
-  PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
-  newChild->SendGetRenderFrameInfo(renderFrame,
-                                   &textureFactoryIdentifier,
-                                   &layersId);
   if (layersId == 0) { // if renderFrame is invalid.
     PRenderFrameChild::Send__delete__(renderFrame);
     renderFrame = nullptr;
   }
 
   ShowInfo showInfo(EmptyString(), false, false, true, 0, 0);
   auto* opener = nsPIDOMWindowOuter::From(aParent);
   nsIDocShell* openerShell;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -83,16 +83,17 @@
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
 #include "mozilla/ipc/TestShellParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/PAPZParent.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/SharedBufferManagerParent.h"
+#include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/media/MediaParent.h"
 #include "mozilla/Move.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitor.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
@@ -298,16 +299,17 @@ using namespace mozilla::dom::mobilemess
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
 using namespace mozilla::media;
 using namespace mozilla::embedding;
 using namespace mozilla::gmp;
 using namespace mozilla::hal;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
+using namespace mozilla::layout;
 using namespace mozilla::net;
 using namespace mozilla::jsipc;
 using namespace mozilla::psm;
 using namespace mozilla::widget;
 
 // XXX Workaround for bug 986973 to maintain the existing broken semantics
 template<>
 struct nsIConsoleService::COMTypeInfo<nsConsoleService, void> {
@@ -5327,30 +5329,33 @@ ContentParent::DeallocPWebBrowserPersist
 {
   delete aActor;
   return true;
 }
 
 bool
 ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
                                 PBrowserParent* aNewTab,
+                                PRenderFrameParent* aRenderFrame,
                                 const uint32_t& aChromeFlags,
                                 const bool& aCalledFromJS,
                                 const bool& aPositionSpecified,
                                 const bool& aSizeSpecified,
                                 const nsCString& aURI,
                                 const nsString& aName,
                                 const nsCString& aFeatures,
                                 const nsCString& aBaseURI,
                                 const DocShellOriginAttributes& aOpenerOriginAttributes,
                                 const float& aFullZoom,
                                 nsresult* aResult,
                                 bool* aWindowIsNew,
                                 InfallibleTArray<FrameScriptInfo>* aFrameScripts,
-                                nsCString* aURLToLoad)
+                                nsCString* aURLToLoad,
+                                TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                uint64_t* aLayersId)
 {
   // We always expect to open a new window here. If we don't, it's an error.
   *aWindowIsNew = true;
 
   // The content process should never be in charge of computing whether or
   // not a window should be private or remote - the parent will do that.
   const uint32_t badFlags =
         nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
@@ -5452,16 +5457,23 @@ ContentParent::RecvCreateWindow(PBrowser
                                   openLocation,
                                   nsIBrowserDOMWindow::OPEN_NEW,
                                   getter_AddRefs(frameLoaderOwner));
     if (!frameLoaderOwner) {
       *aWindowIsNew = false;
     }
 
     newTab->SwapFrameScriptsFrom(*aFrameScripts);
+
+    RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
+    if (!newTab->SetRenderFrame(rfp) ||
+        !newTab->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
+      *aResult = NS_ERROR_FAILURE;
+    }
+
     return true;
   }
 
   // WindowWatcher is going to expect a valid URI to open a window
   // to. If it can't find one, it's going to attempt to figure one
   // out on its own, which is problematic because it can't access
   // the document for the remote browser we're opening. Luckily,
   // TabChild has sent us a baseURI with which we can ensure that
@@ -5531,16 +5543,23 @@ ContentParent::RecvCreateWindow(PBrowser
 
   if (NS_WARN_IF(NS_FAILED(*aResult))) {
     return true;
   }
 
   MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
 
   newTab->SwapFrameScriptsFrom(*aFrameScripts);
+
+  RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
+  if (!newTab->SetRenderFrame(rfp) ||
+      !newTab->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
+    *aResult = NS_ERROR_FAILURE;
+  }
+
   return true;
 }
 
 /* static */ bool
 ContentParent::PermissionManagerAddref(const ContentParentId& aCpId,
                                        const TabId& aTabId)
 {
   MOZ_ASSERT(XRE_IsParentProcess(),
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -58,18 +58,23 @@ class TestShellParent;
 
 namespace jsipc {
 class PJavaScriptParent;
 } // namespace jsipc
 
 namespace layers {
 class PCompositorBridgeParent;
 class PSharedBufferManagerParent;
+struct TextureFactoryIdentifier;
 } // namespace layers
 
+namespace layout {
+class PRenderFrameParent;
+} // namespace layout
+
 namespace dom {
 
 class Element;
 class TabParent;
 class PStorageParent;
 class ClonedMessageData;
 class MemoryReport;
 class TabContext;
@@ -492,30 +497,33 @@ public:
   bool HasGamepadListener() const { return mHasGamepadListener; }
 
   void SetNuwaParent(NuwaParent* aNuwaParent) { mNuwaParent = aNuwaParent; }
 
   void ForkNewProcess(bool aBlocking);
 
   virtual bool RecvCreateWindow(PBrowserParent* aThisTabParent,
                                 PBrowserParent* aOpener,
+                                layout::PRenderFrameParent* aRenderFrame,
                                 const uint32_t& aChromeFlags,
                                 const bool& aCalledFromJS,
                                 const bool& aPositionSpecified,
                                 const bool& aSizeSpecified,
                                 const nsCString& aURI,
                                 const nsString& aName,
                                 const nsCString& aFeatures,
                                 const nsCString& aBaseURI,
                                 const DocShellOriginAttributes& aOpenerOriginAttributes,
                                 const float& aFullZoom,
                                 nsresult* aResult,
                                 bool* aWindowIsNew,
                                 InfallibleTArray<FrameScriptInfo>* aFrameScripts,
-                                nsCString* aURLToLoad) override;
+                                nsCString* aURLToLoad,
+                                layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                uint64_t* aLayersId) override;
 
   static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
 
 protected:
   void OnChannelConnected(int32_t pid) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -404,19 +404,21 @@ parent:
      * process), then calls BrowserFrameOpenWindow on it.
      *
      * The parent process gets a chance to accept or reject the window.open
      * call, and windowOpened is set to true if we ended up going through with
      * the window.open.
      *
      * @param opener the PBrowser whose content called window.open.
      */
-    sync BrowserFrameOpenWindow(PBrowser opener, nsString aURL,
-                                nsString aName, nsString aFeatures)
-      returns (bool windowOpened);
+    sync BrowserFrameOpenWindow(PBrowser opener, PRenderFrame renderFrame,
+                                nsString aURL, nsString aName, nsString aFeatures)
+      returns (bool windowOpened,
+               TextureFactoryIdentifier textureFactoryIdentifier,
+               uint64_t layersId);
 
     /**
      * Tells the containing widget whether the given input block results in a
      * swipe. Should be called in response to a WidgetWheelEvent that has
      * mFlags.mCanTriggerSwipe set on it.
      */
     async RespondStartSwipeEvent(uint64_t aInputBlockId, bool aStartSwipe);
 
@@ -478,20 +480,16 @@ parent:
      * Child informs the parent that the graphics objects are ready for
      * compositing.  This is sent when all pending changes have been
      * sent to the compositor and are ready to be shown on the next composite.
      * @see PCompositor
      * @see RequestNotifyAfterRemotePaint
      */
     async RemotePaintIsReady();
 
-    sync GetRenderFrameInfo(PRenderFrame aRenderFrame)
-        returns (TextureFactoryIdentifier textureFactoryIdentifier,
-                 uint64_t layersId);
-
     /**
      * Sent by the child to the parent to inform it that an update to the
      * dimensions has been requested, likely through win.moveTo or resizeTo
      */
     async SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy);
 
     prio(high) sync DispatchWheelEvent(WidgetWheelEvent event);
     prio(high) sync DispatchMouseEvent(WidgetMouseEvent event);
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -37,16 +37,17 @@ include protocol PNecko;
 //       PContent and PPluginModule it seems to think that PContent's parent and
 //       child live in the same process!
 include protocol PGMPContent;
 include protocol PGMPService;
 include protocol PPluginModule;
 include protocol PGMP;
 include protocol PPrinting;
 include protocol POfflineCacheUpdate;
+include protocol PRenderFrame;
 include protocol PScreenManager;
 include protocol PSharedBufferManager;
 include protocol PSms;
 include protocol PSpeechSynthesis;
 include protocol PStorage;
 include protocol PTelephony;
 include protocol PTestShell;
 include protocol PVoicemail;
@@ -90,16 +91,17 @@ using mozilla::dom::NativeThreadId from 
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
 using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
 using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
 using mozilla::DocShellOriginAttributes from "mozilla/ipc/BackgroundUtils.h";
+using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
     OverrideMapping;
     SubstitutionMapping;
 };
 
@@ -1168,30 +1170,33 @@ parent:
     /**
      * Request graphics initialization information from the parent.
      */
     sync GetGraphicsDeviceInitData()
         returns (DeviceInitData aData);
 
     sync CreateWindow(nullable PBrowser aThisTab,
                       PBrowser aNewTab,
+                      PRenderFrame aRenderFrame,
                       uint32_t aChromeFlags,
                       bool aCalledFromJS,
                       bool aPositionSpecified,
                       bool aSizeSpecified,
                       nsCString aURI,
                       nsString aName,
                       nsCString aFeatures,
                       nsCString aBaseURI,
                       DocShellOriginAttributes aOpenerOriginAttributes,
                       float aFullZoom)
       returns (nsresult rv,
                bool windowOpened,
                FrameScriptInfo[] frameScripts,
-               nsCString urlToLoad);
+               nsCString urlToLoad,
+               TextureFactoryIdentifier textureFactoryIdentifier,
+               uint64_t layersId);
 
     sync GetDeviceStorageLocation(nsString type)
         returns (nsString path);
 
     sync GetDeviceStorageLocations()
 	returns (DeviceStorageLocationInfo info);
 
     sync GetAndroidSystemInfo()
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -884,32 +884,34 @@ TabParent::Show(const ScreenIntSize& siz
     if (mIsDestroyed) {
         return;
     }
 
     TextureFactoryIdentifier textureFactoryIdentifier;
     uint64_t layersId = 0;
     bool success = false;
     RenderFrameParent* renderFrame = nullptr;
-    // If TabParent is initialized by parent side then the RenderFrame must also
-    // be created here. If TabParent is initialized by child side,
-    // child side will create RenderFrame.
-    MOZ_ASSERT(!GetRenderFrame());
     if (IsInitedByParent()) {
+        // If TabParent is initialized by parent side then the RenderFrame must also
+        // be created here. If TabParent is initialized by child side,
+        // child side will create RenderFrame.
+        MOZ_ASSERT(!GetRenderFrame());
         RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
         if (frameLoader) {
-          renderFrame =
-              new RenderFrameParent(frameLoader,
-                                    &textureFactoryIdentifier,
-                                    &layersId,
-                                    &success);
+          renderFrame = new RenderFrameParent(frameLoader, &success);
           MOZ_ASSERT(success);
+          layersId = renderFrame->GetLayersId();
+          renderFrame->GetTextureFactoryIdentifier(&textureFactoryIdentifier);
           AddTabParentToTable(layersId, this);
           Unused << SendPRenderFrameConstructor(renderFrame);
         }
+    } else {
+      // Otherwise, the child should have constructed the RenderFrame,
+      // and we should already know about it.
+      MOZ_ASSERT(GetRenderFrame());
     }
 
     nsCOMPtr<nsISupports> container = mFrameElement->OwnerDoc()->GetContainer();
     nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
     nsCOMPtr<nsIWidget> mainWidget;
     baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
     mSizeMode = mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal;
 
@@ -2554,56 +2556,81 @@ TabParent::DeallocPColorPickerParent(PCo
   return true;
 }
 
 PRenderFrameParent*
 TabParent::AllocPRenderFrameParent()
 {
   MOZ_ASSERT(ManagedPRenderFrameParent().IsEmpty());
   RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
-  TextureFactoryIdentifier textureFactoryIdentifier;
   uint64_t layersId = 0;
   bool success = false;
 
   PRenderFrameParent* renderFrame =
-    new RenderFrameParent(frameLoader,
-                          &textureFactoryIdentifier,
-                          &layersId,
-                          &success);
+    new RenderFrameParent(frameLoader, &success);
   if (success) {
+    RenderFrameParent* rfp = static_cast<RenderFrameParent*>(renderFrame);
+    layersId = rfp->GetLayersId();
     AddTabParentToTable(layersId, this);
   }
   return renderFrame;
 }
 
 bool
 TabParent::DeallocPRenderFrameParent(PRenderFrameParent* aFrame)
 {
   delete aFrame;
   return true;
 }
 
 bool
-TabParent::RecvGetRenderFrameInfo(PRenderFrameParent* aRenderFrame,
-                                  TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                                  uint64_t* aLayersId)
+TabParent::SetRenderFrame(PRenderFrameParent* aRFParent)
 {
-  RenderFrameParent* renderFrame = static_cast<RenderFrameParent*>(aRenderFrame);
-  renderFrame->GetTextureFactoryIdentifier(aTextureFactoryIdentifier);
-  *aLayersId = renderFrame->GetLayersId();
+  if (IsInitedByParent()) {
+    return false;
+  }
+
+  RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
+
+  if (!frameLoader) {
+    return false;
+  }
+
+  RenderFrameParent* renderFrame = static_cast<RenderFrameParent*>(aRFParent);
+  bool success = renderFrame->Init(frameLoader);
+  if (!success) {
+    return false;
+  }
+
+  uint64_t layersId = renderFrame->GetLayersId();
+  AddTabParentToTable(layersId, this);
 
   if (mNeedLayerTreeReadyNotification) {
     RequestNotifyLayerTreeReady();
     mNeedLayerTreeReadyNotification = false;
   }
 
   return true;
 }
 
 bool
+TabParent::GetRenderFrameInfo(TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                              uint64_t* aLayersId)
+{
+  RenderFrameParent* rfp = GetRenderFrame();
+  if (!rfp) {
+    return false;
+  }
+
+  *aLayersId = rfp->GetLayersId();
+  rfp->GetTextureFactoryIdentifier(aTextureFactoryIdentifier);
+  return true;
+}
+
+bool
 TabParent::RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel,
                                                 const bool& aActive)
 {
   if (aAudioChannel >= NUMBER_OF_AUDIO_CHANNELS) {
     return false;
   }
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
@@ -2699,24 +2726,28 @@ TabParent::ApzAwareEventRoutingToChild(S
     if (aOutApzResponse) {
       *aOutApzResponse = nsEventStatus_eIgnore;
     }
   }
 }
 
 bool
 TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
+                                      PRenderFrameParent* aRenderFrame,
                                       const nsString& aURL,
                                       const nsString& aName,
                                       const nsString& aFeatures,
-                                      bool* aOutWindowOpened)
+                                      bool* aOutWindowOpened,
+                                      TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                      uint64_t* aLayersId)
 {
   BrowserElementParent::OpenWindowResult opened =
     BrowserElementParent::OpenWindowOOP(TabParent::GetFrom(aOpener),
-                                        this, aURL, aName, aFeatures);
+                                        this, aRenderFrame, aURL, aName, aFeatures,
+                                        aTextureFactoryIdentifier, aLayersId);
   *aOutWindowOpened = (opened == BrowserElementParent::OPEN_WINDOW_ADDED);
   return true;
 }
 
 bool
 TabParent::RecvRespondStartSwipeEvent(const uint64_t& aInputBlockId,
                                       const bool& aStartSwipe)
 {
@@ -2916,17 +2947,17 @@ class LayerTreeUpdateObserver : public C
     NS_DispatchToMainThread(runnable);
   }
 };
 
 bool
 TabParent::RequestNotifyLayerTreeReady()
 {
   RenderFrameParent* frame = GetRenderFrame();
-  if (!frame) {
+  if (!frame || !frame->IsInitted()) {
     mNeedLayerTreeReadyNotification = true;
   } else {
     CompositorBridgeParent::RequestNotifyLayerTreeReady(
       frame->GetLayersId(),
       new LayerTreeUpdateObserver());
   }
   return true;
 }
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -162,20 +162,23 @@ public:
   virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
 
   virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
 
   virtual bool
   RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) override;
 
   virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
+                                          PRenderFrameParent* aRenderFrame,
                                           const nsString& aURL,
                                           const nsString& aName,
                                           const nsString& aFeatures,
-                                          bool* aOutWindowOpened) override;
+                                          bool* aOutWindowOpened,
+                                          TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                                          uint64_t* aLayersId) override;
 
   virtual bool
   RecvSyncMessage(const nsString& aMessage,
                   const ClonedMessageData& aData,
                   InfallibleTArray<CpowEntry>&& aCpows,
                   const IPC::Principal& aPrincipal,
                   nsTArray<ipc::StructuredCloneData>* aRetVal) override;
 
@@ -545,16 +548,19 @@ public:
   // reload the URI associated with the given channel.
   void OnStartSignedPackageRequest(nsIChannel* aChannel,
                                    const nsACString& aPackageId);
 
   void AudioChannelChangeNotification(nsPIDOMWindowOuter* aWindow,
                                       AudioChannel aAudioChannel,
                                       float aVolume,
                                       bool aMuted);
+  bool SetRenderFrame(PRenderFrameParent* aRFParent);
+  bool GetRenderFrameInfo(TextureFactoryIdentifier* aTextureFactoryIdentifier,
+                          uint64_t* aLayersId);
 
 protected:
   bool ReceiveMessage(const nsString& aMessage,
                       bool aSync,
                       ipc::StructuredCloneData* aData,
                       mozilla::jsipc::CpowHolder* aCpows,
                       nsIPrincipal* aPrincipal,
                       nsTArray<ipc::StructuredCloneData>* aJSONRetVal = nullptr);
@@ -571,20 +577,16 @@ protected:
   nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
 
   virtual PRenderFrameParent* AllocPRenderFrameParent() override;
 
   virtual bool DeallocPRenderFrameParent(PRenderFrameParent* aFrame) override;
 
   virtual bool RecvRemotePaintIsReady() override;
 
-  virtual bool RecvGetRenderFrameInfo(PRenderFrameParent* aRenderFrame,
-                                      TextureFactoryIdentifier* aTextureFactoryIdentifier,
-                                      uint64_t* aLayersId) override;
-
   virtual bool RecvSetDimensions(const uint32_t& aFlags,
                                  const int32_t& aX, const int32_t& aY,
                                  const int32_t& aCx, const int32_t& aCy) override;
 
   virtual bool RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel,
                                                     const bool& aActive) override;
 
   bool InitBrowserConfiguration(const nsCString& aURI,
--- a/dom/media/android/AndroidMediaPluginHost.cpp
+++ b/dom/media/android/AndroidMediaPluginHost.cpp
@@ -169,37 +169,18 @@ static const char* GetOmxLibraryName()
 
   if (!IsOmxSupported())
     return nullptr;
 
 #if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
   if (version >= 17) {
     return "libomxpluginkk.so";
   }
-  else if (version == 13 || version == 12 || version == 11) {
-    return "libomxpluginhc.so";
-  }
-  else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.6")) {
-    // Gingerbread versions from 2.3.6 and above have a different DataSource
-    // layout to those on 2.3.5 and below.
-    return "libomxplugingb.so";
-  }
-  else if (version == 10 && release_version >= NS_LITERAL_STRING("2.3.4") &&
-           device.Find("HTC") == 0) {
-    // HTC devices running Gingerbread 2.3.4+ (HTC Desire HD, HTC Evo Design, etc) seem to
-    // use a newer version of Gingerbread libstagefright than other 2.3.4 devices.
-    return "libomxplugingb.so";
-  }
-  else if (version == 9 || (version == 10 && release_version <= NS_LITERAL_STRING("2.3.5"))) {
-    // Gingerbread versions from 2.3.5 and below have a different DataSource
-    // than 2.3.6 and above.
-    return "libomxplugingb235.so";
-  }
-  else if (version < 9) {
-    // Below Gingerbread not supported
+  else if (version < 14) {
+    // Below Honeycomb not supported
     return nullptr;
   }
 
   // Ice Cream Sandwich and Jellybean
   return "libomxplugin.so";
 
 #elif defined(ANDROID) && defined(MOZ_WIDGET_GONK)
   return "libomxplugin.so";
--- a/dom/media/gmp/GMPMessageUtils.h
+++ b/dom/media/gmp/GMPMessageUtils.h
@@ -158,17 +158,17 @@ template <>
 struct ParamTraits<GMPVideoCodec>
 {
   typedef GMPVideoCodec paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mGMPApiVersion);
     WriteParam(aMsg, aParam.mCodecType);
-    WriteParam(aMsg, nsAutoCString(aParam.mPLName));
+    WriteParam(aMsg, static_cast<const nsCString&>(nsDependentCString(aParam.mPLName)));
     WriteParam(aMsg, aParam.mPLType);
     WriteParam(aMsg, aParam.mWidth);
     WriteParam(aMsg, aParam.mHeight);
     WriteParam(aMsg, aParam.mStartBitrate);
     WriteParam(aMsg, aParam.mMaxBitrate);
     WriteParam(aMsg, aParam.mMinBitrate);
     WriteParam(aMsg, aParam.mMaxFramerate);
     WriteParam(aMsg, aParam.mFrameDroppingOn);
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -775,17 +775,16 @@ void
 TrackBuffersManager::RejectAppend(nsresult aRejectValue, const char* aName)
 {
   MSE_DEBUG("rv=%d", aRejectValue);
   if (mDetached) {
     // We've been detached.
     return;
   }
   MOZ_DIAGNOSTIC_ASSERT(mCurrentTask && mCurrentTask->GetType() == SourceBufferTask::Type::AppendBuffer);
-  MOZ_DIAGNOSTIC_ASSERT(mSourceBufferAttributes);
 
   mCurrentTask->As<AppendBufferTask>()->mPromise.Reject(aRejectValue, __func__);
   mSourceBufferAttributes = nullptr;
   mCurrentTask = nullptr;
   ProcessTasks();
 }
 
 void
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerJob.cpp
@@ -0,0 +1,231 @@
+/* -*- 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 "ServiceWorkerJob.h"
+
+#include "nsProxyRelease.h"
+#include "nsThreadUtils.h"
+#include "Workers.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+ServiceWorkerJob::Type
+ServiceWorkerJob::GetType() const
+{
+  return mType;
+}
+
+ServiceWorkerJob::State
+ServiceWorkerJob::GetState() const
+{
+  return mState;
+}
+
+bool
+ServiceWorkerJob::Canceled() const
+{
+  return mCanceled;
+}
+
+bool
+ServiceWorkerJob::ResultCallbacksInvoked() const
+{
+  return mResultCallbacksInvoked;
+}
+
+bool
+ServiceWorkerJob::IsEquivalentTo(ServiceWorkerJob* aJob) const
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aJob);
+  return mType == aJob->mType &&
+         mScope.Equals(aJob->mScope) &&
+         mScriptSpec.Equals(aJob->mScriptSpec) &&
+         mPrincipal->Equals(aJob->mPrincipal);
+}
+
+void
+ServiceWorkerJob::AppendResultCallback(Callback* aCallback)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mState != State::Finished);
+  MOZ_ASSERT(aCallback);
+  MOZ_ASSERT(mFinalCallback != aCallback);
+  MOZ_ASSERT(!mResultCallbackList.Contains(aCallback));
+  MOZ_ASSERT(!mResultCallbacksInvoked);
+  mResultCallbackList.AppendElement(aCallback);
+}
+
+void
+ServiceWorkerJob::StealResultCallbacksFrom(ServiceWorkerJob* aJob)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aJob);
+  MOZ_ASSERT(aJob->mState == State::Initial);
+
+  // Take the callbacks from the other job immediately to avoid the
+  // any possibility of them existing on both jobs at once.
+  nsTArray<RefPtr<Callback>> callbackList;
+  callbackList.SwapElements(aJob->mResultCallbackList);
+
+  for (RefPtr<Callback>& callback : callbackList) {
+    // Use AppendResultCallback() so that assertion checking is performed on
+    // each callback.
+    AppendResultCallback(callback);
+  }
+}
+
+void
+ServiceWorkerJob::Start(Callback* aFinalCallback)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(!mCanceled);
+
+  MOZ_ASSERT(aFinalCallback);
+  MOZ_ASSERT(!mFinalCallback);
+  MOZ_ASSERT(!mResultCallbackList.Contains(aFinalCallback));
+  mFinalCallback = aFinalCallback;
+
+  MOZ_ASSERT(mState == State::Initial);
+  mState = State::Started;
+
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewRunnableMethod(this, &ServiceWorkerJob::AsyncExecute);
+
+  // We may have to wait for the PBackground actor to be initialized
+  // before proceeding.  We should always be able to get a ServiceWorkerManager,
+  // however, since Start() should not be called during shutdown.
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (!swm->HasBackgroundActor()) {
+    swm->AppendPendingOperation(runnable);
+    return;
+  }
+
+  // Otherwise start asynchronously.  We should never run a job synchronously.
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+    NS_DispatchToMainThread(runnable.forget())));
+}
+
+void
+ServiceWorkerJob::Cancel()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(!mCanceled);
+  mCanceled = true;
+}
+
+ServiceWorkerJob::ServiceWorkerJob(Type aType,
+                                   nsIPrincipal* aPrincipal,
+                                   const nsACString& aScope,
+                                   const nsACString& aScriptSpec)
+  : mType(aType)
+  , mPrincipal(aPrincipal)
+  , mScope(aScope)
+  , mScriptSpec(aScriptSpec)
+  , mState(State::Initial)
+  , mCanceled(false)
+  , mResultCallbacksInvoked(false)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mPrincipal);
+  MOZ_ASSERT(!mScope.IsEmpty());
+  // Some job types may have an empty script spec
+}
+
+ServiceWorkerJob::~ServiceWorkerJob()
+{
+  AssertIsOnMainThread();
+  // Jobs must finish or never be started.  Destroying an actively running
+  // job is an error.
+  MOZ_ASSERT(mState != State::Started);
+  MOZ_ASSERT_IF(mState == State::Finished, mResultCallbacksInvoked);
+}
+
+void
+ServiceWorkerJob::InvokeResultCallbacks(ErrorResult& aRv)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mState == State::Started);
+
+  MOZ_ASSERT(!mResultCallbacksInvoked);
+  mResultCallbacksInvoked = true;
+
+  nsTArray<RefPtr<Callback>> callbackList;
+  callbackList.SwapElements(mResultCallbackList);
+
+  for (RefPtr<Callback>& callback : callbackList) {
+    // The callback might consume an exception on the ErrorResult, so we need
+    // to clone in order to maintain the error for the next callback.
+    ErrorResult rv;
+    aRv.CloneTo(rv);
+
+    callback->JobFinished(this, rv);
+
+    // The callback might not consume the error.
+    rv.SuppressException();
+  }
+}
+
+void
+ServiceWorkerJob::InvokeResultCallbacks(nsresult aRv)
+{
+  ErrorResult converted(aRv);
+  InvokeResultCallbacks(converted);
+}
+
+void
+ServiceWorkerJob::Finish(ErrorResult& aRv)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mState == State::Started);
+
+  // Ensure that we only surface SecurityErr, TypeErr or InvalidStateErr to script.
+  if (aRv.Failed() && !aRv.ErrorCodeIs(NS_ERROR_DOM_SECURITY_ERR) &&
+                      !aRv.ErrorCodeIs(NS_ERROR_DOM_TYPE_ERR) &&
+                      !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR)) {
+
+    // Remove the old error code so we can replace it with a TypeError.
+    aRv.SuppressException();
+
+    NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
+    NS_ConvertUTF8toUTF16 scope(mScope);
+
+    // Throw the type error with a generic error message.
+    aRv.ThrowTypeError<MSG_SW_INSTALL_ERROR>(scriptSpec, scope);
+  }
+
+  // The final callback may drop the last ref to this object.
+  RefPtr<ServiceWorkerJob> kungFuDeathGrip = this;
+
+  if (!mResultCallbacksInvoked) {
+    InvokeResultCallbacks(aRv);
+  }
+
+  mState = State::Finished;
+
+  mFinalCallback->JobFinished(this, aRv);
+  mFinalCallback = nullptr;
+
+  // The callback might not consume the error.
+  aRv.SuppressException();
+
+  // Async release this object to ensure that our caller methods complete
+  // as well.
+  NS_ReleaseOnMainThread(kungFuDeathGrip.forget(), true /* always proxy */);
+}
+
+void
+ServiceWorkerJob::Finish(nsresult aRv)
+{
+  ErrorResult converted(aRv);
+  Finish(converted);
+}
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerJob.h
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_workers_serviceworkerjob_h
+#define mozilla_dom_workers_serviceworkerjob_h
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+class nsIPrincipal;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+namespace workers {
+
+class ServiceWorkerJob
+{
+public:
+  // Implement this interface to receive notification when a job completes.
+  class Callback
+  {
+  public:
+    // Called once when the job completes.  If the job is started, then this
+    // will be called.  If a job is never executed due to browser shutdown,
+    // then this method will never be called.  This method is always called
+    // on the main thread asynchronously after Start() completes.
+    virtual void JobFinished(ServiceWorkerJob* aJob, ErrorResult& aStatus) = 0;
+
+    NS_IMETHOD_(MozExternalRefCountType)
+    AddRef(void) = 0;
+
+    NS_IMETHOD_(MozExternalRefCountType)
+    Release(void) = 0;
+  };
+
+  enum class Type
+  {
+    Register,
+    Update,
+    Unregister
+  };
+
+  enum class State
+  {
+    Initial,
+    Started,
+    Finished
+  };
+
+  Type
+  GetType() const;
+
+  State
+  GetState() const;
+
+  // Determine if the job has been canceled.  This does not change the
+  // current State, but indicates that the job should progress to Finished
+  // as soon as possible.
+  bool
+  Canceled() const;
+
+  // Determine if the result callbacks have already been called.  This is
+  // equivalent to the spec checked to see if the job promise has settled.
+  bool
+  ResultCallbacksInvoked() const;
+
+  bool
+  IsEquivalentTo(ServiceWorkerJob* aJob) const;
+
+  // Add a callback that will be invoked when the job's result is available.
+  // Some job types will invoke this before the job is actually finished.
+  // If an early callback does not occur, then it will be called automatically
+  // when Finish() is called.  These callbacks will be invoked while the job
+  // state is Started.
+  void
+  AppendResultCallback(Callback* aCallback);
+
+  // This takes ownership of any result callbacks associated with the given job
+  // and then appends them to this job's callback list.
+  void
+  StealResultCallbacksFrom(ServiceWorkerJob* aJob);
+
+  // Start the job.  All work will be performed asynchronously on
+  // the main thread.  The Finish() method must be called exactly
+  // once after this point.  A final callback must be provided.  It
+  // will be invoked after all other callbacks have been processed.
+  void
+  Start(Callback* aFinalCallback);
+
+  // Set an internal flag indicating that a started job should finish as
+  // soon as possible.
+  void
+  Cancel();
+
+protected:
+  ServiceWorkerJob(Type aType,
+                   nsIPrincipal* aPrincipal,
+                   const nsACString& aScope,
+                   const nsACString& aScriptSpec);
+
+  virtual ~ServiceWorkerJob();
+
+  // Invoke the result callbacks immediately.  The job must be in the
+  // Started state.  The callbacks are cleared after being invoked,
+  // so subsequent method calls have no effect.
+  void
+  InvokeResultCallbacks(ErrorResult& aRv);
+
+  // Convenience method that converts to ErrorResult and calls real method.
+  void
+  InvokeResultCallbacks(nsresult aRv);
+
+  // Indicate that the job has completed.  The must be called exactly
+  // once after Start() has initiated job execution.  It may not be
+  // called until Start() has returned.
+  void
+  Finish(ErrorResult& aRv);
+
+  // Convenience method that converts to ErrorResult and calls real method.
+  void
+  Finish(nsresult aRv);
+
+  // Specific job types should define AsyncExecute to begin their work.
+  // All errors and successes must result in Finish() being called.
+  virtual void
+  AsyncExecute() = 0;
+
+  const Type mType;
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  const nsCString mScope;
+  const nsCString mScriptSpec;
+
+private:
+  RefPtr<Callback> mFinalCallback;
+  nsTArray<RefPtr<Callback>> mResultCallbackList;
+  State mState;
+  bool mCanceled;
+  bool mResultCallbacksInvoked;
+
+public:
+  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerJob)
+};
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_workers_serviceworkerjob_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerJobQueue.cpp
@@ -0,0 +1,134 @@
+/* -*- 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 "ServiceWorkerJobQueue.h"
+
+#include "ServiceWorkerJob.h"
+#include "Workers.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+class ServiceWorkerJobQueue::Callback final : public ServiceWorkerJob::Callback
+{
+  RefPtr<ServiceWorkerJobQueue> mQueue;
+
+  ~Callback()
+  {
+  }
+
+public:
+  explicit Callback(ServiceWorkerJobQueue* aQueue)
+    : mQueue(aQueue)
+  {
+    AssertIsOnMainThread();
+    MOZ_ASSERT(mQueue);
+  }
+
+  virtual void
+  JobFinished(ServiceWorkerJob* aJob, ErrorResult& aStatus) override
+  {
+    AssertIsOnMainThread();
+    mQueue->JobFinished(aJob);
+  }
+
+  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerJobQueue::Callback, override)
+};
+
+ServiceWorkerJobQueue::~ServiceWorkerJobQueue()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mJobList.IsEmpty());
+}
+
+void
+ServiceWorkerJobQueue::JobFinished(ServiceWorkerJob* aJob)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aJob);
+
+  // XXX There are some corner cases where jobs can double-complete.  Until
+  // we track all these down we do a non-fatal assert in debug builds and
+  // a runtime check to verify the queue is in the correct state.
+  NS_ASSERTION(!mJobList.IsEmpty(),
+               "Job queue should contain the job that just completed.");
+  NS_ASSERTION(mJobList.SafeElementAt(0, nullptr) == aJob,
+               "Job queue should contain the job that just completed.");
+  if (NS_WARN_IF(mJobList.SafeElementAt(0, nullptr) != aJob)) {
+    return;
+  }
+
+  mJobList.RemoveElementAt(0);
+
+  if (mJobList.IsEmpty()) {
+    return;
+  }
+
+  RunJob();
+}
+
+void
+ServiceWorkerJobQueue::RunJob()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(!mJobList.IsEmpty());
+  MOZ_ASSERT(mJobList[0]->GetState() == ServiceWorkerJob::State::Initial);
+
+  RefPtr<Callback> callback = new Callback(this);
+  mJobList[0]->Start(callback);
+}
+
+ServiceWorkerJobQueue::ServiceWorkerJobQueue()
+{
+  AssertIsOnMainThread();
+}
+
+void
+ServiceWorkerJobQueue::ScheduleJob(ServiceWorkerJob* aJob)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aJob);
+  MOZ_ASSERT(!mJobList.Contains(aJob));
+
+  if (mJobList.IsEmpty()) {
+    mJobList.AppendElement(aJob);
+    RunJob();
+    return;
+  }
+
+  MOZ_ASSERT(mJobList[0]->GetState() == ServiceWorkerJob::State::Started);
+
+  RefPtr<ServiceWorkerJob>& tailJob = mJobList[mJobList.Length() - 1];
+  if (!tailJob->ResultCallbacksInvoked() && aJob->IsEquivalentTo(tailJob)) {
+    tailJob->StealResultCallbacksFrom(aJob);
+    return;
+  }
+
+  mJobList.AppendElement(aJob);
+}
+
+void
+ServiceWorkerJobQueue::CancelAll()
+{
+  AssertIsOnMainThread();
+
+  for (RefPtr<ServiceWorkerJob>& job : mJobList) {
+    job->Cancel();
+  }
+
+  // Remove jobs that are queued but not started since they should never
+  // run after being canceled.  This means throwing away all jobs except
+  // for the job at the front of the list.
+  if (!mJobList.IsEmpty()) {
+    MOZ_ASSERT(mJobList[0]->GetState() == ServiceWorkerJob::State::Started);
+    mJobList.TruncateLength(1);
+  }
+}
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerJobQueue.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_workers_serviceworkerjobqueue_h
+#define mozilla_dom_workers_serviceworkerjobqueue_h
+
+#include "mozilla/RefPtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+class ServiceWorkerJob;
+
+class ServiceWorkerJobQueue final
+{
+  class Callback;
+
+  nsTArray<RefPtr<ServiceWorkerJob>> mJobList;
+
+  ~ServiceWorkerJobQueue();
+
+  void
+  JobFinished(ServiceWorkerJob* aJob);
+
+  void
+  RunJob();
+
+public:
+  ServiceWorkerJobQueue();
+
+  void
+  ScheduleJob(ServiceWorkerJob* aJob);
+
+  void
+  CancelAll();
+
+  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerJobQueue)
+};
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_workers_serviceworkerjobqueue_h
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -59,22 +59,26 @@
 #include "nsProxyRelease.h"
 #include "nsQueryObject.h"
 #include "nsTArray.h"
 
 #include "RuntimeService.h"
 #include "ServiceWorker.h"
 #include "ServiceWorkerClient.h"
 #include "ServiceWorkerContainer.h"
+#include "ServiceWorkerJobQueue.h"
 #include "ServiceWorkerManagerChild.h"
 #include "ServiceWorkerPrivate.h"
+#include "ServiceWorkerRegisterJob.h"
 #include "ServiceWorkerRegistrar.h"
 #include "ServiceWorkerRegistration.h"
 #include "ServiceWorkerScriptCache.h"
 #include "ServiceWorkerEvents.h"
+#include "ServiceWorkerUnregisterJob.h"
+#include "ServiceWorkerUpdateJob.h"
 #include "SharedWorker.h"
 #include "WorkerInlines.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
 #ifndef MOZ_SIMPLEPUSH
 #include "mozilla/dom/TypedArray.h"
@@ -140,195 +144,22 @@ struct ServiceWorkerManager::Registratio
   // memmoves associated with inserting stuff in the middle of the array.
   nsTArray<nsCString> mOrderedScopes;
 
   // Scope to registration.
   // The scope should be a fully qualified valid URL.
   nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistrationInfo> mInfos;
 
   // Maps scopes to job queues.
-  nsClassHashtable<nsCStringHashKey, ServiceWorkerJobQueue> mJobQueues;
+  nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerJobQueue> mJobQueues;
 
   // Map scopes to scheduled update timers.
   nsInterfaceHashtable<nsCStringHashKey, nsITimer> mUpdateTimers;
 };
 
-struct ServiceWorkerManager::PendingOperation final
-{
-  nsCOMPtr<nsIRunnable> mRunnable;
-
-  ServiceWorkerJobQueue* mQueue;
-  RefPtr<ServiceWorkerJob> mJob;
-
-  ServiceWorkerRegistrationData mRegistration;
-};
-
-class ServiceWorkerJob : public nsISupports
-{
-  friend class ServiceWorkerJobQueue;
-
-public:
-  NS_DECL_ISUPPORTS
-
-  enum Type
-  {
-    RegisterJob,
-    UpdateJob,
-    InstallJob,
-    UnregisterJob
-  };
-
-  virtual void Start() = 0;
-
-  void
-  Cancel()
-  {
-    mQueue = nullptr;
-    mCanceled = true;
-  }
-
-  bool
-  IsRegisterOrInstallJob() const
-  {
-    return mJobType == RegisterJob || mJobType == UpdateJob ||
-      mJobType == InstallJob;
-  }
-
-protected:
-  // The queue keeps the jobs alive, so they can hold a rawptr back to the
-  // queue.
-  ServiceWorkerJobQueue* mQueue;
-
-  Type mJobType;
-  bool mCanceled;
-
-  explicit ServiceWorkerJob(ServiceWorkerJobQueue* aQueue, Type aJobType)
-    : mQueue(aQueue)
-    , mJobType(aJobType)
-    , mCanceled(false)
-  {}
-
-  virtual ~ServiceWorkerJob()
-  {}
-
-  void
-  Done(nsresult aStatus);
-};
-
-class ServiceWorkerJobQueue final
-{
-  friend class ServiceWorkerJob;
-
-  struct QueueData final
-  {
-    QueueData()
-      : mPopping(false)
-    { }
-
-    ~QueueData()
-    {
-      if (!mJobs.IsEmpty()) {
-        NS_WARNING("Pending/running jobs still around on shutdown!");
-      }
-    }
-
-    nsTArray<RefPtr<ServiceWorkerJob>> mJobs;
-    bool mPopping;
-  };
-
-  const nsCString mScopeKey;
-  QueueData mRegistrationJobQueue;
-  QueueData mInstallationJobQueue;
-
-public:
-  explicit ServiceWorkerJobQueue(const nsACString& aScopeKey)
-    : mScopeKey(aScopeKey)
-  {}
-
-  ~ServiceWorkerJobQueue()
-  { }
-
-  void
-  Append(ServiceWorkerJob* aJob)
-  {
-    MOZ_ASSERT(aJob);
-    QueueData& queue = GetQueue(aJob->mJobType);
-    MOZ_ASSERT(!queue.mJobs.Contains(aJob));
-
-    bool wasEmpty = queue.mJobs.IsEmpty();
-    queue.mJobs.AppendElement(aJob);
-    if (wasEmpty) {
-      aJob->Start();
-    }
-  }
-
-  void
-  CancelJobs();
-
-private:
-  void
-  CancelJobs(QueueData& aQueue);
-
-  // Internal helper function used to assign jobs to the correct queue.
-  QueueData&
-  GetQueue(ServiceWorkerJob::Type aType)
-  {
-    switch (aType) {
-    case ServiceWorkerJob::Type::RegisterJob:
-    case ServiceWorkerJob::Type::UpdateJob:
-    case ServiceWorkerJob::Type::UnregisterJob:
-      return mRegistrationJobQueue;
-    case ServiceWorkerJob::Type::InstallJob:
-      return mInstallationJobQueue;
-    default:
-      MOZ_CRASH("Invalid job queue type.");
-      return mRegistrationJobQueue;
-    }
-  }
-
-  bool
-  IsEmpty()
-  {
-    return mRegistrationJobQueue.mJobs.IsEmpty() &&
-      mInstallationJobQueue.mJobs.IsEmpty();
-  }
-
-  void
-  Pop(QueueData& aQueue)
-  {
-    MOZ_ASSERT(!aQueue.mPopping,
-               "Pop() called recursively, did you write a job which calls Done() synchronously from Start()?");
-
-    AutoRestore<bool> savePopping(aQueue.mPopping);
-    aQueue.mPopping = true;
-    MOZ_ASSERT(!aQueue.mJobs.IsEmpty());
-    aQueue.mJobs.RemoveElementAt(0);
-    if (!aQueue.mJobs.IsEmpty()) {
-      aQueue.mJobs[0]->Start();
-    } else if (IsEmpty()) {
-      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-      MOZ_ASSERT(swm);
-      swm->MaybeRemoveRegistrationInfo(mScopeKey);
-    }
-  }
-
-  void
-  Done(ServiceWorkerJob* aJob)
-  {
-    MOZ_ASSERT(aJob);
-    QueueData& queue = GetQueue(aJob->mJobType);
-    MOZ_ASSERT(!queue.mJobs.IsEmpty());
-    MOZ_ASSERT(queue.mJobs[0] == aJob);
-    if (NS_WARN_IF(queue.mJobs[0] != aJob)) {
-      return;
-    }
-    Pop(queue);
-  }
-};
-
 namespace {
 
 nsresult
 PopulateRegistrationData(nsIPrincipal* aPrincipal,
                          const ServiceWorkerRegistrationInfo* aRegistration,
                          ServiceWorkerRegistrationData& aData)
 {
   MOZ_ASSERT(aPrincipal);
@@ -377,35 +208,16 @@ public:
 private:
   ~TeardownRunnable() {}
 
   RefPtr<ServiceWorkerManagerChild> mActor;
 };
 
 } // namespace
 
-NS_IMPL_ISUPPORTS0(ServiceWorkerJob)
-
-void
-ServiceWorkerJob::Done(nsresult aStatus)
-{
-  if (NS_WARN_IF(NS_FAILED(aStatus))) {
-#ifdef DEBUG
-    nsAutoCString errorName;
-    GetErrorName(aStatus, errorName);
-#endif
-    NS_WARNING(nsPrintfCString("ServiceWorkerJob failed with error: %s",
-                               errorName.get()).get());
-  }
-
-  if (mQueue) {
-    mQueue->Done(this);
-  }
-}
-
 void
 ServiceWorkerRegistrationInfo::Clear()
 {
   if (mInstallingWorker) {
     mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
     mInstallingWorker->WorkerPrivate()->NoteDeadServiceWorkerInfo();
     mInstallingWorker = nullptr;
     // FIXME(nsm): Abort any inflight requests from installing worker.
@@ -447,17 +259,16 @@ ServiceWorkerRegistrationInfo::Clear()
 
 ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(const nsACString& aScope,
                                                              nsIPrincipal* aPrincipal)
   : mControlledDocumentsCounter(0)
   , mUpdateState(NoUpdate)
   , mLastUpdateCheckTime(0)
   , mScope(aScope)
   , mPrincipal(aPrincipal)
-  , mUpdating(false)
   , mPendingUninstall(false)
 {}
 
 ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
 {
   if (IsControllingDocuments()) {
     NS_WARNING("ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive.");
   }
@@ -630,136 +441,84 @@ ServiceWorkerManager::Init()
       rv = obs->AddObserver(this, PURGE_DOMAIN_DATA, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
       rv = obs->AddObserver(this, CLEAR_ORIGIN_DATA, false /* ownsWeak */);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
 }
 
-class ContinueLifecycleTask : public nsISupports
-{
-  NS_DECL_ISUPPORTS
-
-protected:
-  virtual ~ContinueLifecycleTask()
-  {}
-
-public:
-  virtual void ContinueAfterWorkerEvent(bool aSuccess) = 0;
-};
-
-NS_IMPL_ISUPPORTS0(ContinueLifecycleTask);
-
-class ServiceWorkerInstallJob;
-
-class ContinueInstallTask final : public ContinueLifecycleTask
+class ContinueActivateRunnable final : public LifeCycleEventCallback
 {
-  RefPtr<ServiceWorkerInstallJob> mJob;
-
-public:
-  explicit ContinueInstallTask(ServiceWorkerInstallJob* aJob)
-    : mJob(aJob)
-  {}
-
-  void ContinueAfterWorkerEvent(bool aSuccess) override;
-};
-
-class ContinueActivateTask final : public ContinueLifecycleTask
-{
-  RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
-  explicit ContinueActivateTask(ServiceWorkerRegistrationInfo* aReg)
-    : mRegistration(aReg)
-  {}
-
-  void
-  ContinueAfterWorkerEvent(bool aSuccess) override;
-};
-
-class ContinueLifecycleRunnable final : public LifeCycleEventCallback
-{
-  nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
   bool mSuccess;
 
 public:
-  explicit ContinueLifecycleRunnable(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask)
-    : mTask(aTask)
+  explicit ContinueActivateRunnable(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
+    : mRegistration(aRegistration)
     , mSuccess(false)
   {
     AssertIsOnMainThread();
   }
 
   void
   SetResult(bool aResult) override
   {
     mSuccess = aResult;
   }
 
   NS_IMETHOD
   Run() override
   {
     AssertIsOnMainThread();
-    mTask->ContinueAfterWorkerEvent(mSuccess);
+    mRegistration->FinishActivate(mSuccess);
+    mRegistration = nullptr;
     return NS_OK;
   }
 };
 
-class ServiceWorkerResolveWindowPromiseOnUpdateCallback final : public ServiceWorkerUpdateFinishCallback
+class ServiceWorkerResolveWindowPromiseOnRegisterCallback final : public ServiceWorkerJob::Callback
 {
   RefPtr<nsPIDOMWindowInner> mWindow;
   // The promise "returned" by the call to Update up to
   // navigator.serviceWorker.register().
   RefPtr<Promise> mPromise;
 
-  ~ServiceWorkerResolveWindowPromiseOnUpdateCallback()
+  ~ServiceWorkerResolveWindowPromiseOnRegisterCallback()
   {}
 
+  virtual void
+  JobFinished(ServiceWorkerJob* aJob, ErrorResult& aStatus) override
+  {
+    AssertIsOnMainThread();
+    MOZ_ASSERT(aJob);
+
+    if (aStatus.Failed()) {
+      mPromise->MaybeReject(aStatus);
+      return;
+    }
+
+    MOZ_ASSERT(aJob->GetType() == ServiceWorkerJob::Type::Register);
+    RefPtr<ServiceWorkerRegisterJob> registerJob =
+      static_cast<ServiceWorkerRegisterJob*>(aJob);
+    RefPtr<ServiceWorkerRegistrationInfo> reg = registerJob->GetRegistration();
+
+    RefPtr<ServiceWorkerRegistrationMainThread> swr =
+      mWindow->GetServiceWorkerRegistration(NS_ConvertUTF8toUTF16(reg->mScope));
+    mPromise->MaybeResolve(swr);
+  }
+
 public:
-  ServiceWorkerResolveWindowPromiseOnUpdateCallback(nsPIDOMWindowInner* aWindow,
-                                                    Promise* aPromise)
+  ServiceWorkerResolveWindowPromiseOnRegisterCallback(nsPIDOMWindowInner* aWindow,
+                                                      Promise* aPromise)
     : mWindow(aWindow)
     , mPromise(aPromise)
   {}
 
-  void
-  UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo) override
-  {
-    RefPtr<ServiceWorkerRegistrationMainThread> swr =
-      mWindow->GetServiceWorkerRegistration(NS_ConvertUTF8toUTF16(aInfo->mScope));
-    mPromise->MaybeResolve(swr);
-  }
-
-  void
-  UpdateFailed(ErrorResult& aStatus) override
-  {
-    mPromise->MaybeReject(aStatus);
-  }
-};
-
-class ContinueUpdateRunnable final : public LifeCycleEventCallback
-{
-  nsMainThreadPtrHandle<nsISupports> mJob;
-  bool mScriptEvaluationResult;
-public:
-  explicit ContinueUpdateRunnable(const nsMainThreadPtrHandle<nsISupports> aJob)
-    : mJob(aJob)
-    , mScriptEvaluationResult(false)
-  {
-    AssertIsOnMainThread();
-  }
-
-  void
-  SetResult(bool aResult)
-  {
-    mScriptEvaluationResult = aResult;
-  }
-
-  NS_IMETHOD Run();
+  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerResolveWindowPromiseOnRegisterCallback, override)
 };
 
 namespace {
 
 /**
  * The spec mandates slightly different behaviors for computing the scope
  * prefix string in case a Service-Worker-Allowed header is specified versus
  * when it's not available.
@@ -951,730 +710,16 @@ public:
 
 private:
   ~PropagateRemoveAllRunnable()
   {}
 };
 
 } // namespace
 
-class ServiceWorkerJobBase : public ServiceWorkerJob
-{
-public:
-  ServiceWorkerJobBase(ServiceWorkerJobQueue* aQueue,
-                       ServiceWorkerJob::Type aJobType,
-                       nsIPrincipal* aPrincipal,
-                       const nsACString& aScope,
-                       const nsACString& aScriptSpec,
-                       ServiceWorkerUpdateFinishCallback* aCallback,
-                       ServiceWorkerInfo* aServiceWorkerInfo)
-    : ServiceWorkerJob(aQueue, aJobType)
-    , mPrincipal(aPrincipal)
-    , mScope(aScope)
-    , mScriptSpec(aScriptSpec)
-    , mCallback(aCallback)
-    , mUpdateAndInstallInfo(aServiceWorkerInfo)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(aPrincipal);
-  }
-
-protected:
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-  const nsCString mScope;
-  const nsCString mScriptSpec;
-  RefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
-  RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
-  RefPtr<ServiceWorkerInfo> mUpdateAndInstallInfo;
-
-  ~ServiceWorkerJobBase()
-  { }
-
-  // Ensure that mRegistration is set for the job.  Also, if mRegistration was
-  // already set, ensure that a new registration object has not replaced it in
-  // the ServiceWorkerManager.  This can happen when jobs race such that the
-  // registration is cleared and recreated while an update job is executing.
-  nsresult
-  EnsureAndVerifyRegistration()
-  {
-    AssertIsOnMainThread();
-
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    if (NS_WARN_IF(!swm)) {
-      mRegistration = nullptr;
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    RefPtr<ServiceWorkerRegistrationInfo> registration =
-      swm->GetRegistration(mPrincipal, mScope);
-
-    if (NS_WARN_IF(!registration)) {
-      mRegistration = nullptr;
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    if (NS_WARN_IF(mRegistration && registration != mRegistration)) {
-      mRegistration = nullptr;
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    mRegistration = registration.forget();
-    return NS_OK;
-  }
-
-  void
-  Succeed()
-  {
-    AssertIsOnMainThread();
-    // We don't have a callback for soft updates.
-    if (mCallback) {
-      mCallback->UpdateSucceeded(mRegistration);
-      mCallback = nullptr;
-    }
-  }
-
-  // This MUST only be called when the job is still performing actions related
-  // to registration or update. After the spec resolves the update promise, use
-  // Done() with the failure code instead.
-  // Callers MUST hold a strong ref before calling this!
-  void
-  FailWithErrorResult(ErrorResult& aRv)
-  {
-    AssertIsOnMainThread();
-
-    // With cancellation support, we may only be running with one reference
-    // from another object like a stream loader or something.
-    RefPtr<ServiceWorkerJob> kungFuDeathGrip = this;
-
-    // Save off the plain error code to pass to Done() where its logged to
-    // stderr as a warning.
-    nsresult origStatus = static_cast<nsresult>(aRv.ErrorCodeAsInt());
-
-    // Ensure that we only surface SecurityErr, TypeErr or InvalidStateErr to script.
-    if (aRv.Failed() && !aRv.ErrorCodeIs(NS_ERROR_DOM_SECURITY_ERR) &&
-                        !aRv.ErrorCodeIs(NS_ERROR_DOM_TYPE_ERR) &&
-                        !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR)) {
-
-      // Remove the old error code so we can replace it with a TypeError.
-      aRv.SuppressException();
-
-      NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
-      NS_ConvertUTF8toUTF16 scope(mScope);
-
-      // Throw the type error with a generic error message.
-      aRv.ThrowTypeError<MSG_SW_INSTALL_ERROR>(scriptSpec, scope);
-    }
-
-    if (mCallback) {
-      mCallback->UpdateFailed(aRv);
-      mCallback = nullptr;
-    }
-    // In case the callback does not consume the exception
-    aRv.SuppressException();
-
-    mUpdateAndInstallInfo = nullptr;
-
-    if (!mRegistration) {
-      Done(origStatus);
-      return;
-    }
-
-    if (mRegistration->mInstallingWorker) {
-      nsresult rv = serviceWorkerScriptCache::PurgeCache(mPrincipal,
-                                                         mRegistration->mInstallingWorker->CacheName());
-      if (NS_FAILED(rv)) {
-        NS_WARNING("Failed to purge the installing worker cache.");
-      }
-    }
-
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    swm->MaybeRemoveRegistration(mRegistration);
-    // Ensures that the job can't do anything useful from this point on.
-    mRegistration = nullptr;
-    Done(origStatus);
-  }
-
-  void
-  Fail(nsresult aRv)
-  {
-    ErrorResult rv(aRv);
-    FailWithErrorResult(rv);
-  }
-};
-
-class ServiceWorkerInstallJob final : public ServiceWorkerJobBase
-{
-  friend class ContinueInstallTask;
-
-public:
-  enum InstallType {
-    UpdateSameScript,
-    OverwriteScript
-  };
-
-  ServiceWorkerInstallJob(ServiceWorkerJobQueue* aQueue,
-                          nsIPrincipal* aPrincipal,
-                          const nsACString& aScope,
-                          const nsACString& aScriptSpec,
-                          ServiceWorkerUpdateFinishCallback* aCallback,
-                          ServiceWorkerInfo* aServiceWorkerInfo,
-                          InstallType aType)
-    : ServiceWorkerJobBase(aQueue, Type::InstallJob, aPrincipal, aScope,
-                           aScriptSpec, aCallback, aServiceWorkerInfo)
-    , mType(aType)
-  {
-  }
-
-  void
-  Start()
-  {
-    AssertIsOnMainThread();
-    nsCOMPtr<nsIRunnable> r =
-      NS_NewRunnableMethod(this, &ServiceWorkerInstallJob::Install);
-    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
-  }
-
-  void
-  Install()
-  {
-    RefPtr<ServiceWorkerJob> kungFuDeathGrip = this;
-
-    if (mCanceled) {
-      return Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    nsresult rv = EnsureAndVerifyRegistration();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    // If we are trying to install an update for an existing script, then
-    // make sure we don't overwrite a recent script change or resurrect a
-    // dead registration.
-    if (mType == UpdateSameScript) {
-      RefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
-      if (!newest || !mScriptSpec.Equals(newest->ScriptSpec())) {
-        return Fail(NS_ERROR_DOM_ABORT_ERR);
-      }
-    }
-
-    // Begin [[Install]] atomic step 3.
-    if (mRegistration->mInstallingWorker) {
-      mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
-      mRegistration->mInstallingWorker->WorkerPrivate()->TerminateWorker();
-    }
-
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
-                                                   WhichServiceWorker::INSTALLING_WORKER);
-
-    mRegistration->mInstallingWorker = mUpdateAndInstallInfo.forget();
-    mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
-    mRegistration->NotifyListenersOnChange();
-
-    Succeed();
-
-    // The job should NOT call fail from this point on.
-
-    // Step 8 "Queue a task..." for updatefound.
-    nsCOMPtr<nsIRunnable> upr =
-      NS_NewRunnableMethodWithArg<RefPtr<ServiceWorkerRegistrationInfo>>(
-        swm,
-        &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations,
-        mRegistration);
-
-    NS_DispatchToMainThread(upr);
-
-    // Call ContinueAfterInstallEvent(false) on main thread if the SW
-    // script fails to load.
-    nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs<bool>
-      (this, &ServiceWorkerInstallJob::ContinueAfterInstallEvent, false);
-
-    nsMainThreadPtrHandle<ContinueLifecycleTask> installTask(
-      new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this)));
-    RefPtr<LifeCycleEventCallback> callback = new ContinueLifecycleRunnable(installTask);
-
-    // This triggers Step 4.7 "Queue a task to run the following substeps..."
-    // which sends the install event to the worker.
-    ServiceWorkerPrivate* workerPrivate =
-      mRegistration->mInstallingWorker->WorkerPrivate();
-    rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"),
-                                           callback, failRunnable);
-
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      ContinueAfterInstallEvent(false /* aSuccess */);
-    }
-  }
-
-  void
-  ContinueAfterInstallEvent(bool aInstallEventSuccess)
-  {
-    if (mCanceled) {
-      return Done(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    nsresult rv = EnsureAndVerifyRegistration();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    if (!mRegistration->mInstallingWorker) {
-      NS_WARNING("mInstallingWorker was null.");
-      return Done(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-
-    // "If installFailed is true"
-    if (NS_WARN_IF(!aInstallEventSuccess)) {
-      mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
-      mRegistration->mInstallingWorker = nullptr;
-      swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
-                                                     WhichServiceWorker::INSTALLING_WORKER);
-      swm->MaybeRemoveRegistration(mRegistration);
-      return Done(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    // "If registration's waiting worker is not null"
-    if (mRegistration->mWaitingWorker) {
-      mRegistration->mWaitingWorker->WorkerPrivate()->TerminateWorker();
-      mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
-
-      nsresult rv =
-        serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
-                                             mRegistration->mWaitingWorker->CacheName());
-      if (NS_FAILED(rv)) {
-        NS_WARNING("Failed to purge the old waiting cache.");
-      }
-    }
-
-    mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget();
-    mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
-    mRegistration->NotifyListenersOnChange();
-    swm->StoreRegistration(mPrincipal, mRegistration);
-    swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
-                                                   WhichServiceWorker::INSTALLING_WORKER | WhichServiceWorker::WAITING_WORKER);
-
-    Done(NS_OK);
-    // Activate() is invoked out of band of atomic.
-    mRegistration->TryToActivateAsync();
-  }
-
-private:
-  const InstallType mType;
-};
-
-class ServiceWorkerRegisterJob final : public ServiceWorkerJobBase,
-                                       public serviceWorkerScriptCache::CompareCallback
-{
-  friend class ContinueUpdateRunnable;
-
-  nsCOMPtr<nsILoadGroup> mLoadGroup;
-
-  ~ServiceWorkerRegisterJob()
-  { }
-
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // [[Register]]
-  ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
-                           nsIPrincipal* aPrincipal,
-                           const nsACString& aScope,
-                           const nsACString& aScriptSpec,
-                           ServiceWorkerUpdateFinishCallback* aCallback,
-                           nsILoadGroup* aLoadGroup)
-    : ServiceWorkerJobBase(aQueue, Type::RegisterJob, aPrincipal, aScope,
-                           aScriptSpec, aCallback, nullptr)
-    , mLoadGroup(aLoadGroup)
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(mLoadGroup);
-    MOZ_ASSERT(aCallback);
-  }
-
-  // [[Update]]
-  ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
-                           nsIPrincipal* aPrincipal,
-                           const nsACString& aScope,
-                           const nsACString& aScriptSpec,
-                           ServiceWorkerUpdateFinishCallback* aCallback)
-    : ServiceWorkerJobBase(aQueue, Type::UpdateJob, aPrincipal, aScope,
-                           aScriptSpec, aCallback, nullptr)
-  {
-    AssertIsOnMainThread();
-  }
-
-  void
-  Start() override
-  {
-    AssertIsOnMainThread();
-    MOZ_ASSERT(!mCanceled);
-
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    if (!swm->HasBackgroundActor()) {
-      nsCOMPtr<nsIRunnable> runnable =
-        NS_NewRunnableMethod(this, &ServiceWorkerRegisterJob::Start);
-      swm->AppendPendingOperation(runnable);
-      return;
-    }
-
-    if (mJobType == RegisterJob) {
-      MOZ_ASSERT(!mRegistration);
-      mRegistration = swm->GetRegistration(mPrincipal, mScope);
-
-      if (mRegistration) {
-        // If we are resurrecting an uninstalling registration, then persist
-        // it to disk again.  We preemptively removed it earlier during
-        // unregister so that closing the window by shutting down the browser
-        // results in the registration being gone on restart.
-        if (mRegistration->mPendingUninstall) {
-          swm->StoreRegistration(mPrincipal, mRegistration);
-        }
-        mRegistration->mPendingUninstall = false;
-        RefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
-        if (newest && mScriptSpec.Equals(newest->ScriptSpec())) {
-          Succeed();
-
-          // Done() must always be called async from Start()
-          nsCOMPtr<nsIRunnable> runnable =
-            NS_NewRunnableMethodWithArg<nsresult>(
-              this,
-              &ServiceWorkerRegisterJob::Done,
-              NS_OK);
-          MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(runnable));
-
-          return;
-        }
-      } else {
-        mRegistration = swm->CreateNewRegistration(mScope, mPrincipal);
-      }
-    } else {
-      MOZ_ASSERT(mJobType == UpdateJob);
-
-      nsresult rv = EnsureAndVerifyRegistration();
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        // Do nothing here, but since mRegistration is nullptr we will
-        // trigger the async Fail() call below.
-        MOZ_ASSERT(!mRegistration);
-      }
-
-      // "If registration's uninstalling flag is set, abort these steps."
-      if (mRegistration && mRegistration->mPendingUninstall) {
-        nsCOMPtr<nsIRunnable> runnable =
-          NS_NewRunnableMethodWithArg<nsresult>(
-            this,
-            &ServiceWorkerRegisterJob::Fail,
-            NS_ERROR_DOM_INVALID_STATE_ERR);
-          MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(runnable));
-
-        return;
-      }
-
-      // If a different script spec has been registered between when this update
-      // was scheduled and it running now, then simply abort.
-      RefPtr<ServiceWorkerInfo> newest = mRegistration ? mRegistration->Newest()
-                                                       : nullptr;
-      if (!mRegistration ||
-          (newest && !mScriptSpec.Equals(newest->ScriptSpec()))) {
-
-        // Done() must always be called async from Start()
-        nsCOMPtr<nsIRunnable> runnable =
-          NS_NewRunnableMethodWithArg<nsresult>(
-            this,
-            &ServiceWorkerRegisterJob::Fail,
-            NS_ERROR_DOM_ABORT_ERR);
-          MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(runnable));
-
-        return;
-      }
-    }
-
-    Update();
-  }
-
-  void
-  ComparisonResult(nsresult aStatus, bool aInCacheAndEqual,
-                   const nsAString& aNewCacheName,
-                   const nsACString& aMaxScope) override
-  {
-    RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
-
-    if (NS_WARN_IF(mCanceled)) {
-      Fail(NS_ERROR_DOM_ABORT_ERR);
-      return;
-    }
-
-    if (NS_WARN_IF(NS_FAILED(aStatus))) {
-      Fail(aStatus);
-      return;
-    }
-
-    nsresult rv = EnsureAndVerifyRegistration();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    if (aInCacheAndEqual) {
-      Succeed();
-      Done(NS_OK);
-      return;
-    }
-
-    AssertIsOnMainThread();
-    Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1);
-
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-
-    nsCOMPtr<nsIURI> scriptURI;
-    rv = NS_NewURI(getter_AddRefs(scriptURI), mScriptSpec);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      Fail(NS_ERROR_DOM_SECURITY_ERR);
-      return;
-    }
-    nsCOMPtr<nsIURI> maxScopeURI;
-    if (!aMaxScope.IsEmpty()) {
-      rv = NS_NewURI(getter_AddRefs(maxScopeURI), aMaxScope,
-                     nullptr, scriptURI);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        Fail(NS_ERROR_DOM_SECURITY_ERR);
-        return;
-      }
-    }
-
-    nsAutoCString defaultAllowedPrefix;
-    rv = GetRequiredScopeStringPrefix(scriptURI, defaultAllowedPrefix,
-                                      eUseDirectory);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      Fail(NS_ERROR_DOM_SECURITY_ERR);
-      return;
-    }
-    nsAutoCString maxPrefix(defaultAllowedPrefix);
-    if (maxScopeURI) {
-      rv = GetRequiredScopeStringPrefix(maxScopeURI, maxPrefix, eUsePath);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        Fail(NS_ERROR_DOM_SECURITY_ERR);
-        return;
-      }
-    }
-
-    if (!StringBeginsWith(mRegistration->mScope, maxPrefix)) {
-      nsXPIDLString message;
-      NS_ConvertUTF8toUTF16 reportScope(mRegistration->mScope);
-      NS_ConvertUTF8toUTF16 reportMaxPrefix(maxPrefix);
-      const char16_t* params[] = { reportScope.get(), reportMaxPrefix.get() };
-
-      rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                 "ServiceWorkerScopePathMismatch",
-                                                 params, message);
-      NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to format localized string");
-      swm->ReportToAllClients(mScope,
-                              message,
-                              EmptyString(),
-                              EmptyString(), 0, 0,
-                              nsIScriptError::errorFlag);
-      Fail(NS_ERROR_DOM_SECURITY_ERR);
-      return;
-    }
-
-    nsAutoCString scopeKey;
-    rv = swm->PrincipalToScopeKey(mRegistration->mPrincipal, scopeKey);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return Fail(NS_ERROR_FAILURE);
-    }
-
-    ServiceWorkerManager::RegistrationDataPerPrincipal* data;
-    if (!swm->mRegistrationInfos.Get(scopeKey, &data)) {
-      return Fail(NS_ERROR_FAILURE);
-    }
-
-    MOZ_ASSERT(!mUpdateAndInstallInfo);
-    mUpdateAndInstallInfo =
-      new ServiceWorkerInfo(mRegistration->mPrincipal, mRegistration->mScope,
-                            mScriptSpec, aNewCacheName);
-
-    RefPtr<ServiceWorkerJob> upcasted = this;
-    nsMainThreadPtrHandle<nsISupports> handle(
-        new nsMainThreadPtrHolder<nsISupports>(upcasted));
-    RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle);
-
-    ServiceWorkerPrivate* workerPrivate =
-      mUpdateAndInstallInfo->WorkerPrivate();
-    rv = workerPrivate->CheckScriptEvaluation(callback);
-
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-  }
-
-private:
-  // This will perform steps 27 and 28 from [[Update]]
-  // Remove the job from the registration queue and invoke [[Install]]
-  void
-  ContinueInstall(bool aScriptEvaluationResult)
-  {
-    AssertIsOnMainThread();
-
-    nsresult rv = EnsureAndVerifyRegistration();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    mRegistration->mUpdating = false;
-
-    RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
-    if (mCanceled) {
-      return Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    if (NS_WARN_IF(!aScriptEvaluationResult)) {
-      ErrorResult error;
-
-      NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
-      NS_ConvertUTF8toUTF16 scope(mRegistration->mScope);
-      error.ThrowTypeError<MSG_SW_SCRIPT_THREW>(scriptSpec, scope);
-      return FailWithErrorResult(error);
-    }
-
-    // For updates we want to make sure our install job does not end up
-    // changing the script for the registration.  Since a registration
-    // script change can be queued in an install job, we can not
-    // conclusively verify that the update install should proceed here.
-    // Instead, we have to pass a flag into our install job indicating
-    // if a script change is allowed or not.  This can then be used to
-    // check the current script after all previous install jobs have been
-    // flushed.
-    ServiceWorkerInstallJob::InstallType installType =
-      mJobType == UpdateJob ? ServiceWorkerInstallJob::UpdateSameScript
-                            : ServiceWorkerInstallJob::OverwriteScript;
-
-    RefPtr<ServiceWorkerInstallJob> job =
-      new ServiceWorkerInstallJob(mQueue, mPrincipal, mScope, mScriptSpec,
-                                  mCallback, mUpdateAndInstallInfo,
-                                  installType);
-    mQueue->Append(job);
-    Done(NS_OK);
-  }
-
-  void
-  Update()
-  {
-    AssertIsOnMainThread();
-
-    // Since Update() is called synchronously from Start(), we can assert this.
-    MOZ_ASSERT(!mCanceled);
-    MOZ_ASSERT(mRegistration);
-    nsCOMPtr<nsIRunnable> r =
-      NS_NewRunnableMethod(this, &ServiceWorkerRegisterJob::ContinueUpdate);
-    NS_DispatchToMainThread(r);
-
-    mRegistration->mUpdating = true;
-  }
-
-  // Aspects of (actually the whole algorithm) of [[Update]] after
-  // "Run the following steps in parallel."
-  void
-  ContinueUpdate()
-  {
-    AssertIsOnMainThread();
-    RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
-
-    if (mCanceled) {
-      return Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    nsresult rv = EnsureAndVerifyRegistration();
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return Fail(NS_ERROR_DOM_ABORT_ERR);
-    }
-
-    if (mRegistration->mInstallingWorker) {
-      mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
-      mRegistration->mInstallingWorker->WorkerPrivate()->TerminateWorker();
-      mRegistration->mInstallingWorker = nullptr;
-    }
-
-    RefPtr<ServiceWorkerInfo> workerInfo = mRegistration->Newest();
-    nsAutoString cacheName;
-
-    // 9.2.20 If newestWorker is not null, and newestWorker's script url is
-    // equal to registration's registering script url and response is a
-    // byte-for-byte match with the script resource of newestWorker...
-    if (workerInfo && workerInfo->ScriptSpec().Equals(mScriptSpec)) {
-      cacheName = workerInfo->CacheName();
-    }
-
-    rv = serviceWorkerScriptCache::Compare(mRegistration, mPrincipal, cacheName,
-                                           NS_ConvertUTF8toUTF16(mScriptSpec),
-                                           this, mLoadGroup);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return Fail(rv);
-    }
-  }
-
-  void
-  Done(nsresult aStatus)
-  {
-    AssertIsOnMainThread();
-
-    if (mRegistration) {
-      mRegistration->mUpdating = false;
-    }
-
-    ServiceWorkerJob::Done(aStatus);
-  }
-};
-
-NS_IMPL_ISUPPORTS_INHERITED0(ServiceWorkerRegisterJob, ServiceWorkerJob);
-
-void
-ServiceWorkerJobQueue::CancelJobs()
-{
-  // The order doesn't matter. Cancel() just sets a flag on these jobs.
-  CancelJobs(mRegistrationJobQueue);
-  CancelJobs(mInstallationJobQueue);
-}
-
-void
-ServiceWorkerJobQueue::CancelJobs(QueueData& aQueue)
-{
-  if (aQueue.mJobs.IsEmpty()) {
-    return;
-  }
-
-  // We have to treat the first job specially. It is the running job and needs
-  // to be notified correctly.  Even if the job continues some work in the
-  // background, this still needs to be done to let the job know its no longer
-  // in the queue.
-  aQueue.mJobs[0]->Cancel();
-
-  // Get rid of everything. Non-main thread objects may still be holding a ref
-  // to the running register job. Since we called Cancel() on it, the job's
-  // main thread functions will just exit.
-  aQueue.mJobs.Clear();
-}
-
-NS_IMETHODIMP
-ContinueUpdateRunnable::Run()
-{
-  AssertIsOnMainThread();
-  RefPtr<ServiceWorkerJob> job = static_cast<ServiceWorkerJob*>(mJob.get());
-  RefPtr<ServiceWorkerRegisterJob> upjob = static_cast<ServiceWorkerRegisterJob*>(job.get());
-  upjob->ContinueInstall(mScriptEvaluationResult);
-  return NS_OK;
-}
-
-void
-ContinueInstallTask::ContinueAfterWorkerEvent(bool aSuccess)
-{
-  // This does not start the job immediately if there are other jobs in the
-  // queue, which captures the "atomic" behaviour we want.
-  mJob->ContinueAfterInstallEvent(aSuccess);
-}
-
 // This function implements parts of the step 3 of the following algorithm:
 // https://w3c.github.io/webappsec/specs/powerfulfeatures/#settings-secure
 static bool
 IsFromAuthenticatedOrigin(nsIDocument* aDoc)
 {
   MOZ_ASSERT(aDoc);
   nsCOMPtr<nsIDocument> doc(aDoc);
   nsCOMPtr<nsIContentSecurityManager> csm = do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);
@@ -1818,69 +863,54 @@ ServiceWorkerManager::Register(mozIDOMWi
   nsAutoCString scopeKey;
   rv = PrincipalToScopeKey(documentPrincipal, scopeKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   AddRegisteringDocument(cleanedScope, doc);
 
-  ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scopeKey, cleanedScope);
-  MOZ_ASSERT(queue);
-
-  RefPtr<ServiceWorkerResolveWindowPromiseOnUpdateCallback> cb =
-    new ServiceWorkerResolveWindowPromiseOnUpdateCallback(window, promise);
+  RefPtr<ServiceWorkerJobQueue> queue = GetOrCreateJobQueue(scopeKey,
+                                                            cleanedScope);
+
+  RefPtr<ServiceWorkerResolveWindowPromiseOnRegisterCallback> cb =
+    new ServiceWorkerResolveWindowPromiseOnRegisterCallback(window, promise);
 
   nsCOMPtr<nsILoadGroup> docLoadGroup = doc->GetDocumentLoadGroup();
   RefPtr<WorkerLoadInfo::InterfaceRequestor> ir =
     new WorkerLoadInfo::InterfaceRequestor(documentPrincipal, docLoadGroup);
   ir->MaybeAddTabChild(docLoadGroup);
 
   // Create a load group that is separate from, yet related to, the document's load group.
   // This allows checks for interfaces like nsILoadContext to yield the values used by the
   // the document, yet will not cancel the update job if the document's load group is cancelled.
   nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
   MOZ_ALWAYS_SUCCEEDS(loadGroup->SetNotificationCallbacks(ir));
 
   RefPtr<ServiceWorkerRegisterJob> job =
-    new ServiceWorkerRegisterJob(queue, documentPrincipal, cleanedScope, spec,
-                                 cb, loadGroup);
-  queue->Append(job);
+    new ServiceWorkerRegisterJob(documentPrincipal, cleanedScope, spec,
+                                 loadGroup);
+  job->AppendResultCallback(cb);
+  queue->ScheduleJob(job);
 
   AssertIsOnMainThread();
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_REGISTRATIONS, 1);
 
   promise.forget(aPromise);
   return NS_OK;
 }
 
 void
-ServiceWorkerManager::AppendPendingOperation(ServiceWorkerJobQueue* aQueue,
-                                             ServiceWorkerJob* aJob)
-{
-  MOZ_ASSERT(!mActor);
-  MOZ_ASSERT(aQueue);
-  MOZ_ASSERT(aJob);
-
-  if (!mShuttingDown) {
-    PendingOperation* opt = mPendingOperations.AppendElement();
-    opt->mQueue = aQueue;
-    opt->mJob = aJob;
-  }
-}
-
-void
 ServiceWorkerManager::AppendPendingOperation(nsIRunnable* aRunnable)
 {
   MOZ_ASSERT(!mActor);
   MOZ_ASSERT(aRunnable);
 
   if (!mShuttingDown) {
-    PendingOperation* opt = mPendingOperations.AppendElement();
-    opt->mRunnable = aRunnable;
+    mPendingOperations.AppendElement(aRunnable);
   }
 }
 
 void
 ServiceWorkerRegistrationInfo::TryToActivateAsync()
 {
   nsCOMPtr<nsIRunnable> r =
   NS_NewRunnableMethod(this,
@@ -1897,22 +927,16 @@ ServiceWorkerRegistrationInfo::TryToActi
   if (!IsControllingDocuments() ||
       // Waiting worker will be removed if the registration is removed
       (mWaitingWorker && mWaitingWorker->SkipWaitingFlag())) {
     Activate();
   }
 }
 
 void
-ContinueActivateTask::ContinueAfterWorkerEvent(bool aSuccess)
-{
-  mRegistration->FinishActivate(aSuccess);
-}
-
-void
 ServiceWorkerRegistrationInfo::PurgeActiveWorker()
 {
   RefPtr<ServiceWorkerInfo> exitingWorker = mActiveWorker.forget();
   if (!exitingWorker)
     return;
 
   // FIXME(jaoo): Bug 1170543 - Wait for exitingWorker to finish and terminate it.
   exitingWorker->UpdateState(ServiceWorkerState::Redundant);
@@ -1953,22 +977,22 @@ ServiceWorkerRegistrationInfo::Activate(
       swm, &ServiceWorkerManager::FireControllerChange, this);
   NS_DispatchToMainThread(controllerChangeRunnable);
 
   nsCOMPtr<nsIRunnable> failRunnable =
     NS_NewRunnableMethodWithArg<bool>(this,
                                       &ServiceWorkerRegistrationInfo::FinishActivate,
                                       false /* success */);
 
-  nsMainThreadPtrHandle<ContinueLifecycleTask> continueActivateTask(
-    new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueActivateTask(this)));
-  RefPtr<LifeCycleEventCallback> callback =
-    new ContinueLifecycleRunnable(continueActivateTask);
+  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
+    new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(this));
+  RefPtr<LifeCycleEventCallback> callback = new ContinueActivateRunnable(handle);
 
   ServiceWorkerPrivate* workerPrivate = mActiveWorker->WorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
   nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("activate"),
                                                   callback, failRunnable);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(failRunnable));
     return;
   }
 }
 
@@ -2460,134 +1484,56 @@ ServiceWorkerManager::GetActiveWorkerInf
 
   if (!registration) {
     return nullptr;
   }
 
   return registration->mActiveWorker;
 }
 
-class ServiceWorkerUnregisterJob final : public ServiceWorkerJob
+namespace {
+
+class UnregisterJobCallback final : public ServiceWorkerJob::Callback
 {
-  RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
-  const nsCString mScope;
   nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-  const bool mSendToParent;
-
-  ~ServiceWorkerUnregisterJob()
-  {}
+
+  ~UnregisterJobCallback()
+  {
+  }
 
 public:
-  ServiceWorkerUnregisterJob(ServiceWorkerJobQueue* aQueue,
-                             const nsACString& aScope,
-                             nsIServiceWorkerUnregisterCallback* aCallback,
-                             nsIPrincipal* aPrincipal,
-                             bool aSendToParent = true)
-    : ServiceWorkerJob(aQueue, Type::UnregisterJob)
-    , mScope(aScope)
-    , mCallback(aCallback)
-    , mPrincipal(aPrincipal)
-    , mSendToParent(aSendToParent)
+  explicit UnregisterJobCallback(nsIServiceWorkerUnregisterCallback* aCallback)
+    : mCallback(aCallback)
   {
     AssertIsOnMainThread();
+    MOZ_ASSERT(mCallback);
   }
 
   void
-  Start() override
-  {
-    AssertIsOnMainThread();
-    nsCOMPtr<nsIRunnable> r =
-      NS_NewRunnableMethod(this, &ServiceWorkerUnregisterJob::UnregisterAndDone);
-    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r));
-  }
-
-private:
-  // You probably want UnregisterAndDone().
-  nsresult
-  Unregister()
+  JobFinished(ServiceWorkerJob* aJob, ErrorResult& aStatus)
   {
     AssertIsOnMainThread();
-
-    if (mCanceled) {
-      return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
-    }
-
-    PrincipalInfo principalInfo;
-    if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(mPrincipal,
-                                                      &principalInfo)))) {
-      return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
-    }
-
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-
-    nsAutoCString scopeKey;
-    nsresult rv = swm->PrincipalToScopeKey(mPrincipal, scopeKey);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
-    }
-
-    // "Let registration be the result of running [[Get Registration]]
-    // algorithm passing scope as the argument."
-    ServiceWorkerManager::RegistrationDataPerPrincipal* data;
-    if (!swm->mRegistrationInfos.Get(scopeKey, &data)) {
-      // "If registration is null, then, resolve promise with false."
-      return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
-    }
-
-    RefPtr<ServiceWorkerRegistrationInfo> registration;
-    if (!data->mInfos.Get(mScope, getter_AddRefs(registration))) {
-      // "If registration is null, then, resolve promise with false."
-      return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
+    MOZ_ASSERT(aJob);
+
+    if (aStatus.Failed()) {
+      mCallback->UnregisterFailed();
+      return;
     }
 
-    MOZ_ASSERT(registration);
-
-    // Note, we send the message to remove the registration from disk now even
-    // though we may only set the mPendingUninstall flag below.  This is
-    // necessary to ensure the registration is removed if the controlled
-    // clients are closed by shutting down the browser.  If the registration
-    // is resurrected by clearing mPendingUninstall then it should be saved
-    // to disk again.
-    if (mSendToParent && !registration->mPendingUninstall && swm->mActor) {
-      swm->mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(mScope));
-    }
-
-    // "Set registration's uninstalling flag."
-    registration->mPendingUninstall = true;
-    // "Resolve promise with true"
-    rv = mCallback ? mCallback->UnregisterSucceeded(true) : NS_OK;
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    // "If no service worker client is using registration..."
-    if (!registration->IsControllingDocuments()) {
-      // "If registration's uninstalling flag is set.."
-      if (!registration->mPendingUninstall) {
-        return NS_OK;
-      }
-
-      // "Invoke [[Clear Registration]]..."
-      swm->RemoveRegistration(registration);
-    }
-
-    return NS_OK;
-  }
-
-  // The unregister job is done irrespective of success or failure of any sort.
-  void
-  UnregisterAndDone()
-  {
-    nsresult rv = Unregister();
-    Unused << NS_WARN_IF(NS_FAILED(rv));
-    Done(rv);
-  }
+    MOZ_ASSERT(aJob->GetType() == ServiceWorkerJob::Type::Unregister);
+    RefPtr<ServiceWorkerUnregisterJob> unregisterJob =
+      static_cast<ServiceWorkerUnregisterJob*>(aJob);
+    mCallback->UnregisterSucceeded(unregisterJob->GetResult());
+  }
+
+  NS_INLINE_DECL_REFCOUNTING(UnregisterJobCallback)
 };
 
+} // anonymous namespace
+
 NS_IMETHODIMP
 ServiceWorkerManager::Unregister(nsIPrincipal* aPrincipal,
                                  nsIServiceWorkerUnregisterCallback* aCallback,
                                  const nsAString& aScope)
 {
   AssertIsOnMainThread();
 
   if (!aPrincipal) {
@@ -2608,28 +1554,27 @@ ServiceWorkerManager::Unregister(nsIPrin
 
   nsAutoCString scopeKey;
   rv = PrincipalToScopeKey(aPrincipal, scopeKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   NS_ConvertUTF16toUTF8 scope(aScope);
-  ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scopeKey, scope);
-  MOZ_ASSERT(queue);
+  RefPtr<ServiceWorkerJobQueue> queue = GetOrCreateJobQueue(scopeKey, scope);
 
   RefPtr<ServiceWorkerUnregisterJob> job =
-    new ServiceWorkerUnregisterJob(queue, scope, aCallback, aPrincipal);
-
-  if (mActor) {
-    queue->Append(job);
-    return NS_OK;
-  }
-
-  AppendPendingOperation(queue, job);
+    new ServiceWorkerUnregisterJob(aPrincipal, scope, true /* send to parent */);
+
+  if (aCallback) {
+    RefPtr<UnregisterJobCallback> cb = new UnregisterJobCallback(aCallback);
+    job->AppendResultCallback(cb);
+  }
+
+  queue->ScheduleJob(job);
   return NS_OK;
 }
 
 nsresult
 ServiceWorkerManager::NotifyUnregister(nsIPrincipal* aPrincipal,
                                        const nsAString& aScope)
 {
   AssertIsOnMainThread();
@@ -2649,49 +1594,45 @@ ServiceWorkerManager::NotifyUnregister(n
 
   nsAutoCString scopeKey;
   rv = PrincipalToScopeKey(aPrincipal, scopeKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   NS_ConvertUTF16toUTF8 scope(aScope);
-  ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scopeKey, scope);
-  MOZ_ASSERT(queue);
+  RefPtr<ServiceWorkerJobQueue> queue = GetOrCreateJobQueue(scopeKey, scope);
 
   RefPtr<ServiceWorkerUnregisterJob> job =
-    new ServiceWorkerUnregisterJob(queue, scope, nullptr, aPrincipal, false);
-
-  if (mActor) {
-    queue->Append(job);
-    return NS_OK;
-  }
-
-  AppendPendingOperation(queue, job);
+    new ServiceWorkerUnregisterJob(aPrincipal, scope,
+                                    false /* send to parent */);
+
+  queue->ScheduleJob(job);
   return NS_OK;
 }
 
-ServiceWorkerJobQueue*
+already_AddRefed<ServiceWorkerJobQueue>
 ServiceWorkerManager::GetOrCreateJobQueue(const nsACString& aKey,
                                           const nsACString& aScope)
 {
   MOZ_ASSERT(!aKey.IsEmpty());
   ServiceWorkerManager::RegistrationDataPerPrincipal* data;
   if (!mRegistrationInfos.Get(aKey, &data)) {
     data = new RegistrationDataPerPrincipal();
     mRegistrationInfos.Put(aKey, data);
   }
 
-  ServiceWorkerJobQueue* queue;
-  if (!data->mJobQueues.Get(aScope, &queue)) {
-    queue = new ServiceWorkerJobQueue(aKey);
-    data->mJobQueues.Put(aScope, queue);
-  }
-
-  return queue;
+  RefPtr<ServiceWorkerJobQueue> queue;
+  if (!data->mJobQueues.Get(aScope, getter_AddRefs(queue))) {
+    RefPtr<ServiceWorkerJobQueue> newQueue = new ServiceWorkerJobQueue();
+    queue = newQueue;
+    data->mJobQueues.Put(aScope, newQueue.forget());
+  }
+
+  return queue.forget();
 }
 
 /* static */
 already_AddRefed<ServiceWorkerManager>
 ServiceWorkerManager::GetInstance()
 {
   // Note: We don't simply check gInstance for null-ness here, since otherwise
   // this can resurrect the ServiceWorkerManager pretty late during shutdown.
@@ -3064,27 +2005,20 @@ ServiceWorkerManager::ActorCreated(mozil
 
   PServiceWorkerManagerChild* actor =
     aActor->SendPServiceWorkerManagerConstructor();
 
   mActor = static_cast<ServiceWorkerManagerChild*>(actor);
 
   // Flush the pending requests.
   for (uint32_t i = 0, len = mPendingOperations.Length(); i < len; ++i) {
-    MOZ_ASSERT(mPendingOperations[i].mRunnable ||
-               (mPendingOperations[i].mJob && mPendingOperations[i].mQueue));
-
-    if (mPendingOperations[i].mRunnable) {
-      nsresult rv = NS_DispatchToCurrentThread(mPendingOperations[i].mRunnable);
-      if (NS_FAILED(rv)) {
-        NS_WARNING("Failed to dispatch a runnable.");
-        return;
-      }
-    } else {
-      mPendingOperations[i].mQueue->Append(mPendingOperations[i].mJob);
+    MOZ_ASSERT(mPendingOperations[i]);
+    nsresult rv = NS_DispatchToCurrentThread(mPendingOperations[i].forget());
+    if (NS_FAILED(rv)) {
+      NS_WARNING("Failed to dispatch a runnable.");
     }
   }
 
   mPendingOperations.Clear();
 }
 
 void
 ServiceWorkerManager::StoreRegistration(
@@ -3958,27 +2892,65 @@ ServiceWorkerManager::SoftUpdate(const P
   if (!newest) {
     return;
   }
 
   // "If the registration queue for registration is empty, invoke Update algorithm,
   // or its equivalent, with client, registration as its argument."
   // TODO(catalinb): We don't implement the force bypass cache flag.
   // See: https://github.com/slightlyoff/ServiceWorker/issues/759
-  if (!registration->mUpdating) {
-    ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scopeKey, aScope);
-    MOZ_ASSERT(queue);
-
-    RefPtr<ServiceWorkerRegisterJob> job =
-      new ServiceWorkerRegisterJob(queue, principal, registration->mScope,
-                                   newest->ScriptSpec(), nullptr);
-    queue->Append(job);
-  }
+  RefPtr<ServiceWorkerJobQueue> queue = GetOrCreateJobQueue(scopeKey,
+                                                            aScope);
+
+  RefPtr<ServiceWorkerUpdateJob> job =
+    new ServiceWorkerUpdateJob(principal, registration->mScope,
+                               newest->ScriptSpec(), nullptr);
+  queue->ScheduleJob(job);
 }
 
+namespace {
+
+class UpdateJobCallback final : public ServiceWorkerJob::Callback
+{
+  RefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
+
+  ~UpdateJobCallback()
+  {
+  }
+
+public:
+  explicit UpdateJobCallback(ServiceWorkerUpdateFinishCallback* aCallback)
+    : mCallback(aCallback)
+  {
+    AssertIsOnMainThread();
+    MOZ_ASSERT(mCallback);
+  }
+
+  void
+  JobFinished(ServiceWorkerJob* aJob, ErrorResult& aStatus)
+  {
+    AssertIsOnMainThread();
+    MOZ_ASSERT(aJob);
+
+    if (aStatus.Failed()) {
+      mCallback->UpdateFailed(aStatus);
+      return;
+    }
+
+    MOZ_ASSERT(aJob->GetType() == ServiceWorkerJob::Type::Update);
+    RefPtr<ServiceWorkerUpdateJob> updateJob =
+      static_cast<ServiceWorkerUpdateJob*>(aJob);
+    RefPtr<ServiceWorkerRegistrationInfo> reg = updateJob->GetRegistration();
+    mCallback->UpdateSucceeded(reg);
+  }
+
+  NS_INLINE_DECL_REFCOUNTING(UpdateJobCallback)
+};
+} // anonymous namespace
+
 void
 ServiceWorkerManager::Update(nsIPrincipal* aPrincipal,
                              const nsACString& aScope,
                              ServiceWorkerUpdateFinishCallback* aCallback)
 {
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aCallback);
 
@@ -4003,26 +2975,28 @@ ServiceWorkerManager::Update(nsIPrincipa
     aCallback->UpdateFailed(error);
 
     // In case the callback does not consume the exception
     error.SuppressException();
 
     return;
   }
 
-  ServiceWorkerJobQueue* queue =
-    GetOrCreateJobQueue(scopeKey, aScope);
-  MOZ_ASSERT(queue);
+  RefPtr<ServiceWorkerJobQueue> queue = GetOrCreateJobQueue(scopeKey, aScope);
 
   // "Invoke Update algorithm, or its equivalent, with client, registration as
   // its argument."
-  RefPtr<ServiceWorkerRegisterJob> job =
-    new ServiceWorkerRegisterJob(queue, aPrincipal, registration->mScope,
-                                 newest->ScriptSpec(), aCallback);
-  queue->Append(job);
+  RefPtr<ServiceWorkerUpdateJob> job =
+    new ServiceWorkerUpdateJob(aPrincipal, registration->mScope,
+                               newest->ScriptSpec(), nullptr);
+
+  RefPtr<UpdateJobCallback> cb = new UpdateJobCallback(aCallback);
+  job->AppendResultCallback(cb);
+
+  queue->ScheduleJob(job);
 }
 
 namespace {
 
 static void
 FireControllerChangeOnDocument(nsIDocument* aDocument)
 {
   AssertIsOnMainThread();
@@ -4462,20 +3436,20 @@ ServiceWorkerManager::GetAllRegistration
 // MUST ONLY BE CALLED FROM Remove(), RemoveAll() and RemoveAllRegistrations()!
 void
 ServiceWorkerManager::ForceUnregister(RegistrationDataPerPrincipal* aRegistrationData,
                                       ServiceWorkerRegistrationInfo* aRegistration)
 {
   MOZ_ASSERT(aRegistrationData);
   MOZ_ASSERT(aRegistration);
 
-  ServiceWorkerJobQueue* queue;
-  aRegistrationData->mJobQueues.Get(aRegistration->mScope, &queue);
+  RefPtr<ServiceWorkerJobQueue> queue;
+  aRegistrationData->mJobQueues.Get(aRegistration->mScope, getter_AddRefs(queue));
   if (queue) {
-    queue->CancelJobs();
+    queue->CancelAll();
   }
 
   nsCOMPtr<nsITimer> timer =
     aRegistrationData->mUpdateTimers.Get(aRegistration->mScope);
   if (timer) {
     timer->Cancel();
     aRegistrationData->mUpdateTimers.Remove(aRegistration->mScope);
   }
@@ -4777,18 +3751,18 @@ ServiceWorkerManager::Observe(nsISupport
     for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
       for (auto it2 = it1.UserData()->mUpdateTimers.Iter(); !it2.Done(); it2.Next()) {
         nsCOMPtr<nsITimer> timer = it2.UserData();
         timer->Cancel();
       }
       it1.UserData()->mUpdateTimers.Clear();
 
       for (auto it2 = it1.UserData()->mJobQueues.Iter(); !it2.Done(); it2.Next()) {
-        ServiceWorkerJobQueue* queue = it2.UserData();
-        queue->CancelJobs();
+        RefPtr<ServiceWorkerJobQueue> queue = it2.UserData();
+        queue->CancelAll();
       }
       it1.UserData()->mJobQueues.Clear();
     }
 
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
 
@@ -5125,16 +4099,37 @@ ServiceWorkerManager::UpdateTimerFired(n
   }
 
   PrincipalOriginAttributes attrs =
     BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
 
   SoftUpdate(attrs, aScope);
 }
 
+void
+ServiceWorkerManager::MaybeSendUnregister(nsIPrincipal* aPrincipal,
+                                          const nsACString& aScope)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aPrincipal);
+  MOZ_ASSERT(!aScope.IsEmpty());
+
+  if (!mActor) {
+    return;
+  }
+
+  PrincipalInfo principalInfo;
+  nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  Unused << mActor->SendUnregister(principalInfo, NS_ConvertUTF8toUTF16(aScope));
+}
+
 NS_IMPL_ISUPPORTS(ServiceWorkerInfo, nsIServiceWorkerInfo)
 
 NS_IMETHODIMP
 ServiceWorkerInfo::GetScriptSpec(nsAString& aScriptSpec)
 {
   AssertIsOnMainThread();
   CopyUTF8toUTF16(mScriptSpec, aScriptSpec);
   return NS_OK;
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -42,17 +42,16 @@ namespace dom {
 
 class ServiceWorkerRegistrationListener;
 
 namespace workers {
 
 class ServiceWorker;
 class ServiceWorkerClientInfo;
 class ServiceWorkerInfo;
-class ServiceWorkerJob;
 class ServiceWorkerJobQueue;
 class ServiceWorkerManagerChild;
 class ServiceWorkerPrivate;
 
 class ServiceWorkerRegistrationInfo final
   : public nsIServiceWorkerRegistrationInfo
 {
   uint32_t mControlledDocumentsCounter;
@@ -77,22 +76,16 @@ public:
   nsCOMPtr<nsIPrincipal> mPrincipal;
 
   RefPtr<ServiceWorkerInfo> mActiveWorker;
   RefPtr<ServiceWorkerInfo> mWaitingWorker;
   RefPtr<ServiceWorkerInfo> mInstallingWorker;
 
   nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> mListeners;
 
-  // According to the spec, Soft Update shouldn't queue an update job
-  // if the registration queue is not empty. Because our job queue
-  // works slightly different, we use a flag to determine if the registration
-  // is already updating.
-  bool mUpdating;
-
   // When unregister() is called on a registration, it is not immediately
   // removed since documents may be controlled. It is marked as
   // pendingUninstall and when all controlling documents go away, removed.
   bool mPendingUninstall;
 
   ServiceWorkerRegistrationInfo(const nsACString& aScope,
                                 nsIPrincipal* aPrincipal);
 
@@ -322,23 +315,20 @@ public:
 class ServiceWorkerManager final
   : public nsIServiceWorkerManager
   , public nsIIPCBackgroundChildCreateCallback
   , public nsIObserver
 {
   friend class GetReadyPromiseRunnable;
   friend class GetRegistrationsRunnable;
   friend class GetRegistrationRunnable;
-  friend class ServiceWorkerJobQueue;
-  friend class ServiceWorkerInstallJob;
-  friend class ServiceWorkerRegisterJob;
-  friend class ServiceWorkerJobBase;
-  friend class ServiceWorkerScriptJobBase;
+  friend class ServiceWorkerJob;
   friend class ServiceWorkerRegistrationInfo;
   friend class ServiceWorkerUnregisterJob;
+  friend class ServiceWorkerUpdateJob;
   friend class UpdateTimerCallback;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERMANAGER
   NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
   NS_DECL_NSIOBSERVER
 
@@ -507,17 +497,17 @@ public:
 
 private:
   ServiceWorkerManager();
   ~ServiceWorkerManager();
 
   void
   Init();
 
-  ServiceWorkerJobQueue*
+  already_AddRefed<ServiceWorkerJobQueue>
   GetOrCreateJobQueue(const nsACString& aOriginSuffix,
                       const nsACString& aScope);
 
   void
   MaybeRemoveRegistrationInfo(const nsACString& aScopeKey);
 
   already_AddRefed<ServiceWorkerRegistrationInfo>
   GetRegistration(const nsACString& aScopeKey,
@@ -622,18 +612,16 @@ private:
       : mURI(aURI), mPromise(aPromise)
     {}
 
     nsCOMPtr<nsIURI> mURI;
     RefPtr<Promise> mPromise;
   };
 
   void AppendPendingOperation(nsIRunnable* aRunnable);
-  void AppendPendingOperation(ServiceWorkerJobQueue* aQueue,
-                              ServiceWorkerJob* aJob);
 
   bool HasBackgroundActor() const
   {
     return !!mActor;
   }
 
   nsClassHashtable<nsISupportsHashKey, PendingReadyPromise> mPendingReadyPromises;
 
@@ -641,18 +629,17 @@ private:
   MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
 
   // Removes all service worker registrations that matches the given pattern.
   void
   RemoveAllRegistrations(OriginAttributesPattern* aPattern);
 
   RefPtr<ServiceWorkerManagerChild> mActor;
 
-  struct PendingOperation;
-  nsTArray<PendingOperation> mPendingOperations;
+  nsTArray<nsCOMPtr<nsIRunnable>> mPendingOperations;
 
   bool mShuttingDown;
 
   nsTArray<nsCOMPtr<nsIServiceWorkerManagerListener>> mListeners;
 
   void
   NotifyListenersOnRegister(nsIServiceWorkerRegistrationInfo* aRegistration);
 
@@ -672,15 +659,18 @@ private:
   RemoveNavigationInterception(const nsACString& aScope,
                                nsIInterceptedChannel* aChannel);
 
   void
   ScheduleUpdateTimer(nsIPrincipal* aPrincipal, const nsACString& aScope);
 
   void
   UpdateTimerFired(nsIPrincipal* aPrincipal, const nsACString& aScope);
+
+  void
+  MaybeSendUnregister(nsIPrincipal* aPrincipal, const nsACString& aScope);
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworkermanager_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerRegisterJob.cpp
@@ -0,0 +1,67 @@
+/* -*- 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 "ServiceWorkerRegisterJob.h"
+
+#include "Workers.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(nsIPrincipal* aPrincipal,
+                                                   const nsACString& aScope,
+                                                   const nsACString& aScriptSpec,
+                                                   nsILoadGroup* aLoadGroup)
+  : ServiceWorkerUpdateJob(Type::Register, aPrincipal, aScope, aScriptSpec,
+                           aLoadGroup)
+{
+}
+
+void
+ServiceWorkerRegisterJob::AsyncExecute()
+{
+  AssertIsOnMainThread();
+
+  if (Canceled()) {
+    FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  RefPtr<ServiceWorkerRegistrationInfo> registration =
+    swm->GetRegistration(mPrincipal, mScope);
+
+  if (registration) {
+    // If we are resurrecting an uninstalling registration, then persist
+    // it to disk again.  We preemptively removed it earlier during
+    // unregister so that closing the window by shutting down the browser
+    // results in the registration being gone on restart.
+    if (registration->mPendingUninstall) {
+      swm->StoreRegistration(mPrincipal, registration);
+    }
+    registration->mPendingUninstall = false;
+    RefPtr<ServiceWorkerInfo> newest = registration->Newest();
+    if (newest && mScriptSpec.Equals(newest->ScriptSpec())) {
+      SetRegistration(registration);
+      Finish(NS_OK);
+      return;
+    }
+  } else {
+    registration = swm->CreateNewRegistration(mScope, mPrincipal);
+  }
+
+  SetRegistration(registration);
+  Update();
+}
+
+ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob()
+{
+}
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerRegisterJob.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_workers_serviceworkerregisterjob_h
+#define mozilla_dom_workers_serviceworkerregisterjob_h
+
+#include "ServiceWorkerUpdateJob.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+// The register job.  This implements the steps in the spec Register algorithm,
+// but then uses ServiceWorkerUpdateJob to implement the Update and Install
+// spec algorithms.
+class ServiceWorkerRegisterJob final : public ServiceWorkerUpdateJob
+{
+public:
+  ServiceWorkerRegisterJob(nsIPrincipal* aPrincipal,
+                           const nsACString& aScope,
+                           const nsACString& aScriptSpec,
+                           nsILoadGroup* aLoadGroup);
+
+private:
+  // Implement the Register algorithm steps and then call the parent class
+  // Update() to complete the job execution.
+  virtual void
+  AsyncExecute() override;
+
+  virtual ~ServiceWorkerRegisterJob();
+};
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_workers_serviceworkerregisterjob_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerUnregisterJob.cpp
@@ -0,0 +1,89 @@
+/* -*- 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 "ServiceWorkerUnregisterJob.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+
+ServiceWorkerUnregisterJob::ServiceWorkerUnregisterJob(nsIPrincipal* aPrincipal,
+                                                       const nsACString& aScope,
+                                                       bool aSendToParent)
+  : ServiceWorkerJob(Type::Unregister, aPrincipal, aScope, EmptyCString())
+  , mResult(false)
+  , mSendToParent(aSendToParent)
+{
+}
+
+bool
+ServiceWorkerUnregisterJob::GetResult() const
+{
+  AssertIsOnMainThread();
+  return mResult;
+}
+
+ServiceWorkerUnregisterJob::~ServiceWorkerUnregisterJob()
+{
+}
+
+void
+ServiceWorkerUnregisterJob::AsyncExecute()
+{
+  AssertIsOnMainThread();
+
+  if (Canceled()) {
+    Finish(NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+
+  // Step 1 of the Unregister algorithm requires checking that the
+  // client origin matches the scope's origin.  We perform this in
+  // registration->update() method directly since we don't have that
+  // client information available here.
+
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+  // "Let registration be the result of running [[Get Registration]]
+  // algorithm passing scope as the argument."
+  RefPtr<ServiceWorkerRegistrationInfo> registration =
+    swm->GetRegistration(mPrincipal, mScope);
+  if (!registration) {
+    // "If registration is null, then, resolve promise with false."
+    Finish(NS_OK);
+    return;
+  }
+
+  // Note, we send the message to remove the registration from disk now even
+  // though we may only set the mPendingUninstall flag below.  This is
+  // necessary to ensure the registration is removed if the controlled
+  // clients are closed by shutting down the browser.  If the registration
+  // is resurrected by clearing mPendingUninstall then it should be saved
+  // to disk again.
+  if (mSendToParent && !registration->mPendingUninstall) {
+    swm->MaybeSendUnregister(mPrincipal, mScope);
+  }
+
+  // "Set registration's uninstalling flag."
+  registration->mPendingUninstall = true;
+
+  // "Resolve promise with true"
+  mResult = true;
+  InvokeResultCallbacks(NS_OK);
+
+  // "If no service worker client is using registration..."
+  if (!registration->IsControllingDocuments()) {
+    // "Invoke [[Clear Registration]]..."
+    swm->RemoveRegistration(registration);
+  }
+
+  Finish(NS_OK);
+}
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerUnregisterJob.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_workers_serviceworkerunregisterjob_h
+#define mozilla_dom_workers_serviceworkerunregisterjob_h
+
+#include "ServiceWorkerJob.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+class ServiceWorkerUnregisterJob final : public ServiceWorkerJob
+{
+public:
+  ServiceWorkerUnregisterJob(nsIPrincipal* aPrincipal,
+                             const nsACString& aScope,
+                             bool aSendToParent);
+
+  bool
+  GetResult() const;
+
+private:
+  virtual ~ServiceWorkerUnregisterJob();
+
+  virtual void
+  AsyncExecute() override;
+
+  bool mResult;
+  bool mSendToParent;
+};
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_workers_serviceworkerunregisterjob_h
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerUpdateJob.cpp
@@ -0,0 +1,514 @@
+/* -*- 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 "ServiceWorkerUpdateJob.h"
+
+#include "ServiceWorkerScriptCache.h"
+#include "Workers.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+class ServiceWorkerUpdateJob::CompareCallback final : public serviceWorkerScriptCache::CompareCallback
+{
+  RefPtr<ServiceWorkerUpdateJob> mJob;
+
+  ~CompareCallback()
+  {
+  }
+
+public:
+  explicit CompareCallback(ServiceWorkerUpdateJob* aJob)
+    : mJob(aJob)
+  {
+    MOZ_ASSERT(mJob);
+  }
+
+  virtual void
+  ComparisonResult(nsresult aStatus,
+                   bool aInCacheAndEqual,
+                   const nsAString& aNewCacheName,
+                   const nsACString& aMaxScope) override
+  {
+    mJob->ComparisonResult(aStatus, aInCacheAndEqual, aNewCacheName, aMaxScope);
+  }
+
+  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerUpdateJob::CompareCallback, override)
+};
+
+class ServiceWorkerUpdateJob::ContinueUpdateRunnable final : public LifeCycleEventCallback
+{
+  nsMainThreadPtrHandle<ServiceWorkerUpdateJob> mJob;
+  bool mSuccess;
+
+public:
+  explicit ContinueUpdateRunnable(const nsMainThreadPtrHandle<ServiceWorkerUpdateJob>& aJob)
+    : mJob(aJob)
+    , mSuccess(false)
+  {
+    AssertIsOnMainThread();
+  }
+
+  void
+  SetResult(bool aResult) override
+  {
+    mSuccess = aResult;
+  }
+
+  NS_IMETHOD
+  Run() override
+  {
+    AssertIsOnMainThread();
+    mJob->ContinueUpdateAfterScriptEval(mSuccess);
+    mJob = nullptr;
+    return NS_OK;
+  }
+};
+
+class ServiceWorkerUpdateJob::ContinueInstallRunnable final : public LifeCycleEventCallback
+{
+  nsMainThreadPtrHandle<ServiceWorkerUpdateJob> mJob;
+  bool mSuccess;
+
+public:
+  explicit ContinueInstallRunnable(const nsMainThreadPtrHandle<ServiceWorkerUpdateJob>& aJob)
+    : mJob(aJob)
+    , mSuccess(false)
+  {
+    AssertIsOnMainThread();
+  }
+
+  void
+  SetResult(bool aResult) override
+  {
+    mSuccess = aResult;
+  }
+
+  NS_IMETHOD
+  Run() override
+  {
+    AssertIsOnMainThread();
+    mJob->ContinueAfterInstallEvent(mSuccess);
+    mJob = nullptr;
+    return NS_OK;
+  }
+};
+
+ServiceWorkerUpdateJob::ServiceWorkerUpdateJob(nsIPrincipal* aPrincipal,
+                                               const nsACString& aScope,
+                                               const nsACString& aScriptSpec,
+                                               nsILoadGroup* aLoadGroup)
+  : ServiceWorkerJob(Type::Update, aPrincipal, aScope, aScriptSpec)
+  , mLoadGroup(aLoadGroup)
+{
+}
+
+already_AddRefed<ServiceWorkerRegistrationInfo>
+ServiceWorkerUpdateJob::GetRegistration() const
+{
+  AssertIsOnMainThread();
+  RefPtr<ServiceWorkerRegistrationInfo> ref = mRegistration;
+  return ref.forget();
+}
+
+ServiceWorkerUpdateJob::ServiceWorkerUpdateJob(Type aType,
+                                               nsIPrincipal* aPrincipal,
+                                               const nsACString& aScope,
+                                               const nsACString& aScriptSpec,
+                                               nsILoadGroup* aLoadGroup)
+  : ServiceWorkerJob(aType, aPrincipal, aScope, aScriptSpec)
+  , mLoadGroup(aLoadGroup)
+{
+}
+
+ServiceWorkerUpdateJob::~ServiceWorkerUpdateJob()
+{
+}
+
+void
+ServiceWorkerUpdateJob::FailUpdateJob(ErrorResult& aRv)
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(aRv.Failed());
+
+  // Cleanup after a failed installation.  This essentially implements
+  // step 12 of the Install algorithm.
+  //
+  //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm
+  //
+  // The spec currently only runs this after an install event fails,
+  // but we must handle many more internal errors.  So we check for
+  // cleanup on every non-successful exit.
+  if (mRegistration) {
+    if (mServiceWorker) {
+      mServiceWorker->UpdateState(ServiceWorkerState::Redundant);
+      serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
+                                           mServiceWorker->CacheName());
+    }
+
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+    if (mRegistration->mInstallingWorker) {
+      mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
+      serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
+                                           mRegistration->mInstallingWorker->CacheName());
+      mRegistration->mInstallingWorker = nullptr;
+      if (swm) {
+        swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
+                                                       WhichServiceWorker::INSTALLING_WORKER);
+      }
+    }
+
+    if (swm) {
+      swm->MaybeRemoveRegistration(mRegistration);
+    }
+  }
+
+  mServiceWorker = nullptr;
+  mRegistration = nullptr;
+
+  Finish(aRv);
+}
+
+void
+ServiceWorkerUpdateJob::FailUpdateJob(nsresult aRv)
+{
+  ErrorResult rv(aRv);
+  FailUpdateJob(rv);
+}
+
+void
+ServiceWorkerUpdateJob::AsyncExecute()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(GetType() == Type::Update);
+
+  if (Canceled()) {
+    FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+
+  // Begin step 1 of the Update algorithm.
+  //
+  //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#update-algorithm
+
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  RefPtr<ServiceWorkerRegistrationInfo> registration =
+    swm->GetRegistration(mPrincipal, mScope);
+
+  if (!registration || registration->mPendingUninstall) {
+    ErrorResult rv;
+    rv.ThrowTypeError<MSG_SW_UPDATE_BAD_REGISTRATION>(NS_ConvertUTF8toUTF16(mScope),
+                                                      NS_LITERAL_STRING("uninstalled"));
+    FailUpdateJob(rv);
+    return;
+  }
+
+  // If a Register job with a new script executed ahead of us in the job queue,
+  // then our update for the old script no longer makes sense.  Simply abort
+  // in this case.
+  RefPtr<ServiceWorkerInfo> newest = registration->Newest();
+  if (newest && !mScriptSpec.Equals(newest->ScriptSpec())) {
+    ErrorResult rv;
+    rv.ThrowTypeError<MSG_SW_UPDATE_BAD_REGISTRATION>(NS_ConvertUTF8toUTF16(mScope),
+                                                      NS_LITERAL_STRING("changed"));
+    FailUpdateJob(rv);
+    return;
+  }
+
+  SetRegistration(registration);
+  Update();
+}
+
+void
+ServiceWorkerUpdateJob::SetRegistration(ServiceWorkerRegistrationInfo* aRegistration)
+{
+  AssertIsOnMainThread();
+
+  MOZ_ASSERT(!mRegistration);
+  MOZ_ASSERT(aRegistration);
+  mRegistration = aRegistration;
+}
+
+void
+ServiceWorkerUpdateJob::Update()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(!Canceled());
+
+  // SetRegistration() must be called before Update().
+  MOZ_ASSERT(mRegistration);
+  MOZ_ASSERT(!mRegistration->mInstallingWorker);
+
+  // Begin the script download and comparison steps starting at step 5
+  // of the Update algorithm.
+
+  RefPtr<ServiceWorkerInfo> workerInfo = mRegistration->Newest();
+  nsAutoString cacheName;
+
+  // If the script has not changed, we need to perform a byte-for-byte
+  // comparison.
+  if (workerInfo && workerInfo->ScriptSpec().Equals(mScriptSpec)) {
+    cacheName = workerInfo->CacheName();
+  }
+
+  RefPtr<CompareCallback> callback = new CompareCallback(this);
+
+  nsresult rv =
+    serviceWorkerScriptCache::Compare(mRegistration, mPrincipal, cacheName,
+                                      NS_ConvertUTF8toUTF16(mScriptSpec),
+                                      callback, mLoadGroup);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    FailUpdateJob(rv);
+    return;
+  }
+}
+
+void
+ServiceWorkerUpdateJob::ComparisonResult(nsresult aStatus,
+                                         bool aInCacheAndEqual,
+                                         const nsAString& aNewCacheName,
+                                         const nsACString& aMaxScope)
+{
+  AssertIsOnMainThread();
+
+  if (NS_WARN_IF(Canceled())) {
+    FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+
+  // Handle failure of the download or comparison.  This is part of Update
+  // step 5 as "If the algorithm asynchronously completes with null, then:".
+  if (NS_WARN_IF(NS_FAILED(aStatus))) {
+    FailUpdateJob(aStatus);
+    return;
+  }
+
+  // The spec validates the response before performing the byte-for-byte check.
+  // Here we perform the comparison in another module and then validate the
+  // script URL and scope.  Make sure to do this validation before accepting
+  // an byte-for-byte match since the service-worker-allowed header might have
+  // changed since the last time it was installed.
+
+  // This is step 2 the "validate response" section of Update algorithm step 5.
+  // Step 1 is performed in the serviceWorkerScriptCache code.
+
+  nsCOMPtr<nsIURI> scriptURI;
+  nsresult rv = NS_NewURI(getter_AddRefs(scriptURI), mScriptSpec);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  nsCOMPtr<nsIURI> maxScopeURI;
+  if (!aMaxScope.IsEmpty()) {
+    rv = NS_NewURI(getter_AddRefs(maxScopeURI), aMaxScope,
+                   nullptr, scriptURI);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
+      return;
+    }
+  }
+
+  nsAutoCString defaultAllowedPrefix;
+  rv = GetRequiredScopeStringPrefix(scriptURI, defaultAllowedPrefix,
+                                    eUseDirectory);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  nsAutoCString maxPrefix(defaultAllowedPrefix);
+  if (maxScopeURI) {
+    rv = GetRequiredScopeStringPrefix(maxScopeURI, maxPrefix, eUsePath);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
+      return;
+    }
+  }
+
+  if (!StringBeginsWith(mRegistration->mScope, maxPrefix)) {
+    nsXPIDLString message;
+    NS_ConvertUTF8toUTF16 reportScope(mRegistration->mScope);
+    NS_ConvertUTF8toUTF16 reportMaxPrefix(maxPrefix);
+    const char16_t* params[] = { reportScope.get(), reportMaxPrefix.get() };
+
+    rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
+                                               "ServiceWorkerScopePathMismatch",
+                                               params, message);
+    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to format localized string");
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    swm->ReportToAllClients(mScope,
+                            message,
+                            EmptyString(),
+                            EmptyString(), 0, 0,
+                            nsIScriptError::errorFlag);
+    FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  // The response has been validated, so now we can consider if its a
+  // byte-for-byte match.  This is step 6 of the Update algorithm.
+  if (aInCacheAndEqual) {
+    Finish(NS_OK);
+    return;
+  }
+
+  Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1);
+
+  // Begin step 7 of the Update algorithm to evaluate the new script.
+
+  MOZ_ASSERT(!mServiceWorker);
+  mServiceWorker = new ServiceWorkerInfo(mRegistration->mPrincipal,
+                                         mRegistration->mScope,
+                                         mScriptSpec, aNewCacheName);
+
+  nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
+      new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(this));
+  RefPtr<LifeCycleEventCallback> callback = new ContinueUpdateRunnable(handle);
+
+  ServiceWorkerPrivate* workerPrivate = mServiceWorker->WorkerPrivate();
+  MOZ_ASSERT(workerPrivate);
+  rv = workerPrivate->CheckScriptEvaluation(callback);
+
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+}
+
+void
+ServiceWorkerUpdateJob::ContinueUpdateAfterScriptEval(bool aScriptEvaluationResult)
+{
+  AssertIsOnMainThread();
+
+  if (Canceled()) {
+    FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+
+  // Step 7.5 of the Update algorithm verifying that the script evaluated
+  // successfully.
+
+  if (NS_WARN_IF(!aScriptEvaluationResult)) {
+    ErrorResult error;
+
+    NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
+    NS_ConvertUTF8toUTF16 scope(mRegistration->mScope);
+    error.ThrowTypeError<MSG_SW_SCRIPT_THREW>(scriptSpec, scope);
+    FailUpdateJob(error);
+    return;
+  }
+
+  Install();
+}
+
+void
+ServiceWorkerUpdateJob::Install()
+{
+  AssertIsOnMainThread();
+  MOZ_ASSERT(!Canceled());
+
+  MOZ_ASSERT(!mRegistration->mInstallingWorker);
+
+  // Begin step 2 of the Install algorithm.
+  //
+  //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm
+
+  MOZ_ASSERT(mServiceWorker);
+  mRegistration->mInstallingWorker = mServiceWorker.forget();
+  mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
+  mRegistration->NotifyListenersOnChange();
+
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
+                                                 WhichServiceWorker::INSTALLING_WORKER);
+
+  // Step 6 of the Install algorithm resolving the job promise.
+  InvokeResultCallbacks(NS_OK);
+
+  // The job promise cannot be rejected after this point, but the job can
+  // still fail; e.g. if the install event handler throws, etc.
+
+  // fire the updatefound event
+  nsCOMPtr<nsIRunnable> upr =
+    NS_NewRunnableMethodWithArg<RefPtr<ServiceWorkerRegistrationInfo>>(
+      swm,
+      &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations,
+      mRegistration);
+  NS_DispatchToMainThread(upr);
+
+  // Call ContinueAfterInstallEvent(false) on main thread if the SW
+  // script fails to load.
+  nsCOMPtr<nsIRunnable> failRunnable = NS_NewRunnableMethodWithArgs<bool>
+    (this, &ServiceWorkerUpdateJob::ContinueAfterInstallEvent, false);
+
+  nsMainThreadPtrHandle<ServiceWorkerUpdateJob> handle(
+    new nsMainThreadPtrHolder<ServiceWorkerUpdateJob>(this));
+  RefPtr<LifeCycleEventCallback> callback = new ContinueInstallRunnable(handle);
+
+  // Send the install event to the worker thread
+  ServiceWorkerPrivate* workerPrivate =
+    mRegistration->mInstallingWorker->WorkerPrivate();
+  nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"),
+                                                  callback, failRunnable);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    ContinueAfterInstallEvent(false /* aSuccess */);
+  }
+}
+
+void
+ServiceWorkerUpdateJob::ContinueAfterInstallEvent(bool aInstallEventSuccess)
+{
+  if (Canceled()) {
+    return FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
+  }
+
+  MOZ_ASSERT(mRegistration->mInstallingWorker);
+
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+  // Continue executing the Install algorithm at step 12.
+
+  // "If installFailed is true"
+  if (NS_WARN_IF(!aInstallEventSuccess)) {
+    // The installing worker is cleaned up by FailUpdateJob().
+    FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
+    return;
+  }
+
+  // "If registration's waiting worker is not null"
+  if (mRegistration->mWaitingWorker) {
+    mRegistration->mWaitingWorker->WorkerPrivate()->TerminateWorker();
+    mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
+    serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
+                                         mRegistration->mWaitingWorker->CacheName());
+  }
+
+  mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget();
+  mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
+  mRegistration->NotifyListenersOnChange();
+  swm->StoreRegistration(mPrincipal, mRegistration);
+  swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
+                                                 WhichServiceWorker::INSTALLING_WORKER |
+                                                 WhichServiceWorker::WAITING_WORKER);
+
+  Finish(NS_OK);
+
+  // Step 20 calls for explicitly waiting for queued event tasks to fire.  Instead,
+  // we simply queue a runnable to execute Activate.  This ensures the events are
+  // flushed from the queue before proceeding.
+
+  // Step 22 of the Install algorithm.  Activate is executed after the completion
+  // of this job.  The controlling client and skipWaiting checks are performed
+  // in TryToActivate().
+  mRegistration->TryToActivateAsync();
+}
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/workers/ServiceWorkerUpdateJob.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_workers_serviceworkerupdatejob_h
+#define mozilla_dom_workers_serviceworkerupdatejob_h
+
+#include "ServiceWorkerJob.h"
+
+namespace mozilla {
+namespace dom {
+namespace workers {
+
+// A job class that performs the Update and Install algorithms from the
+// service worker spec.  This class is designed to be inherited and customized
+// as a different job type.  This is necessary because the register job
+// performs largely the same operations as the update job, but has a few
+// different starting steps.
+class ServiceWorkerUpdateJob : public ServiceWorkerJob
+{
+public:
+  // Construct an update job to be used only for updates.
+  ServiceWorkerUpdateJob(nsIPrincipal* aPrincipal,
+                         const nsACString& aScope,
+                         const nsACString& aScriptSpec,
+                         nsILoadGroup* aLoadGroup);
+
+  already_AddRefed<ServiceWorkerRegistrationInfo>
+  GetRegistration() const;
+
+protected:
+  // Construct an update job that is overriden as another job type.
+  ServiceWorkerUpdateJob(Type aType,
+                         nsIPrincipal* aPrincipal,
+                         const nsACString& aScope,
+                         const nsACString& aScriptSpec,
+                         nsILoadGroup* aLoadGroup);
+
+  virtual ~ServiceWorkerUpdateJob();
+
+  // FailUpdateJob() must be called if an update job needs Finish() with
+  // an error.
+  void
+  FailUpdateJob(ErrorResult& aRv);
+
+  void
+  FailUpdateJob(nsresult aRv);
+
+  // The entry point when the update job is being used directly.  Job
+  // types overriding this class should override this method to
+  // customize behavior.
+  virtual void
+  AsyncExecute() override;
+
+  // Set the registration to be operated on by Update() or to be immediately
+  // returned as a result of the job.  This must be called before Update().
+  void
+  SetRegistration(ServiceWorkerRegistrationInfo* aRegistration);
+
+  // Execute the bulk of the update job logic using the registration defined
+  // by a previous SetRegistration() call.  This can be called by the overriden
+  // AsyncExecute() to complete the job.  The Update() method will always call
+  // Finish().  This method corresponds to the spec Update algorithm.
+  void
+  Update();
+
+private:
+  class CompareCallback;
+  class ContinueUpdateRunnable;
+  class ContinueInstallRunnable;
+
+  // Utility method called after a script is loaded and compared to
+  // our current cached script.
+  void
+  ComparisonResult(nsresult aStatus,
+                   bool aInCacheAndEqual,
+                   const nsAString& aNewCacheName,
+                   const nsACString& aMaxScope);
+
+  // Utility method called after evaluating the worker script.
+  void
+  ContinueUpdateAfterScriptEval(bool aScriptEvaluationResult);
+
+  // Utility method corresponding to the spec Install algorithm.
+  void
+  Install();
+
+  // Utility method called after the install event is handled.
+  void
+  ContinueAfterInstallEvent(bool aInstallEventSuccess);
+
+  nsCOMPtr<nsILoadGroup> mLoadGroup;
+  RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
+  RefPtr<ServiceWorkerInfo> mServiceWorker;
+};
+
+} // namespace workers
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_workers_serviceworkerupdatejob_h
--- a/dom/workers/WorkerNavigator.cpp
+++ b/dom/workers/WorkerNavigator.cpp
@@ -21,16 +21,18 @@
 
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
 namespace mozilla {
 namespace dom {
 
+using namespace mozilla::dom::workers;
+
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerNavigator)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release)
 
 /* static */ already_AddRefed<WorkerNavigator>
 WorkerNavigator::Create(bool aOnLine)
 {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -97,16 +97,17 @@
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "ServiceWorkerEvents.h"
 #include "ServiceWorkerManager.h"
 #include "ServiceWorkerWindowClient.h"
 #include "SharedWorker.h"
 #include "WorkerDebuggerManager.h"
 #include "WorkerFeature.h"
+#include "WorkerNavigator.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 #include "WorkerThread.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
@@ -5893,18 +5894,20 @@ WorkerPrivate::SetTimeout(JSContext* aCx
   // Take care of the main argument.
   if (aHandler) {
     newInfo->mTimeoutCallable = JS::ObjectValue(*aHandler->Callable());
   }
   else if (!aStringHandler.IsEmpty()) {
     newInfo->mTimeoutString = aStringHandler;
   }
   else {
-    JS_ReportError(aCx, "Useless %s call (missing quotes around argument?)",
-                   aIsInterval ? "setInterval" : "setTimeout");
+    NS_NAMED_LITERAL_STRING(kSetInterval, "setInterval");
+    NS_NAMED_LITERAL_STRING(kSetTimeout, "setTimeout");
+    aRv.ThrowTypeError<MSG_USELESS_SETTIMEOUT>(aIsInterval ? kSetInterval
+                                                           : kSetTimeout);
     return 0;
   }
 
   // See if any of the optional arguments were passed.
   aTimeout = std::max(0, aTimeout);
   newInfo->mInterval = TimeDuration::FromMilliseconds(aTimeout);
 
   uint32_t argc = aArguments.Length();
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -232,26 +232,26 @@ WorkerGlobalScope::SetTimeout(JSContext*
                               ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), aTimeout,
                                     aArguments, false, aRv);
 }
 
 int32_t
-WorkerGlobalScope::SetTimeout(JSContext* /* unused */,
+WorkerGlobalScope::SetTimeout(JSContext* aCx,
                               const nsAString& aHandler,
                               const int32_t aTimeout,
                               const Sequence<JS::Value>& /* unused */,
                               ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   Sequence<JS::Value> dummy;
-  return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr,
-                                    aHandler, aTimeout, dummy, false, aRv);
+  return mWorkerPrivate->SetTimeout(aCx, nullptr, aHandler, aTimeout, dummy,
+                                    false, aRv);
 }
 
 void
 WorkerGlobalScope::ClearTimeout(int32_t aHandle)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   mWorkerPrivate->ClearTimeout(aHandle);
 }
@@ -268,31 +268,31 @@ WorkerGlobalScope::SetInterval(JSContext
   bool isInterval = aTimeout.WasPassed();
   int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
 
   return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), timeout,
                                     aArguments, isInterval, aRv);
 }
 
 int32_t
-WorkerGlobalScope::SetInterval(JSContext* /* unused */,
+WorkerGlobalScope::SetInterval(JSContext* aCx,
                                const nsAString& aHandler,
                                const Optional<int32_t>& aTimeout,
                                const Sequence<JS::Value>& /* unused */,
                                ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   Sequence<JS::Value> dummy;
 
   bool isInterval = aTimeout.WasPassed();
   int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
 
-  return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr,
-                                    aHandler, timeout, dummy, isInterval, aRv);
+  return mWorkerPrivate->SetTimeout(aCx, nullptr, aHandler, timeout, dummy,
+                                    isInterval, aRv);
 }
 
 void
 WorkerGlobalScope::ClearInterval(int32_t aHandle)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   mWorkerPrivate->ClearTimeout(aHandle);
 }
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -113,27 +113,26 @@ public:
 
   void
   ImportScripts(const Sequence<nsString>& aScriptURLs, ErrorResult& aRv);
 
   int32_t
   SetTimeout(JSContext* aCx, Function& aHandler, const int32_t aTimeout,
              const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
   int32_t
-  SetTimeout(JSContext* /* unused */, const nsAString& aHandler,
-             const int32_t aTimeout, const Sequence<JS::Value>& /* unused */,
-             ErrorResult& aRv);
+  SetTimeout(JSContext* aCx, const nsAString& aHandler, const int32_t aTimeout,
+             const Sequence<JS::Value>& /* unused */, ErrorResult& aRv);
   void
   ClearTimeout(int32_t aHandle);
   int32_t
   SetInterval(JSContext* aCx, Function& aHandler,
               const Optional<int32_t>& aTimeout,
               const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
   int32_t
-  SetInterval(JSContext* /* unused */, const nsAString& aHandler,
+  SetInterval(JSContext* aCx, const nsAString& aHandler,
               const Optional<int32_t>& aTimeout,
               const Sequence<JS::Value>& /* unused */, ErrorResult& aRv);
   void
   ClearInterval(int32_t aHandle);
 
   void
   Atob(const nsAString& aAtob, nsAString& aOutput, ErrorResult& aRv) const;
   void
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -61,25 +61,30 @@ UNIFIED_SOURCES += [
     'RegisterBindings.cpp',
     'RuntimeService.cpp',
     'ScriptLoader.cpp',
     'ServiceWorker.cpp',
     'ServiceWorkerClient.cpp',
     'ServiceWorkerClients.cpp',
     'ServiceWorkerContainer.cpp',
     'ServiceWorkerEvents.cpp',
+    'ServiceWorkerJob.cpp',
+    'ServiceWorkerJobQueue.cpp',
     'ServiceWorkerManager.cpp',
     'ServiceWorkerManagerChild.cpp',
     'ServiceWorkerManagerParent.cpp',
     'ServiceWorkerManagerService.cpp',
     'ServiceWorkerMessageEvent.cpp',
     'ServiceWorkerPrivate.cpp',
+    'ServiceWorkerRegisterJob.cpp',
     'ServiceWorkerRegistrar.cpp',
     'ServiceWorkerRegistration.cpp',
     'ServiceWorkerScriptCache.cpp',
+    'ServiceWorkerUnregisterJob.cpp',
+    'ServiceWorkerUpdateJob.cpp',
     'ServiceWorkerWindowClient.cpp',
     'SharedWorker.cpp',
     'URL.cpp',
     'WorkerDebuggerManager.cpp',
     'WorkerLocation.cpp',
     'WorkerNavigator.cpp',
     'WorkerPrivate.cpp',
     'WorkerRunnable.cpp',
--- a/gfx/2d/DrawTargetRecording.cpp
+++ b/gfx/2d/DrawTargetRecording.cpp
@@ -384,16 +384,20 @@ void
 DrawTargetRecording::FillGlyphs(ScaledFont *aFont,
                                 const GlyphBuffer &aBuffer,
                                 const Pattern &aPattern,
                                 const DrawOptions &aOptions,
                                 const GlyphRenderingOptions *aRenderingOptions)
 {
   EnsurePatternDependenciesStored(aPattern);
 
+  if (aFont->GetType() != FontType::DWRITE && aFont->GetType() != FontType::GDI) {
+    gfxDevCrash(LogReason::GetFontFileDataFailed) << "Unexpected ScaledFont type " << (int)aFont->GetType();
+  }
+
   if (!aFont->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))) {
   // TODO support font in b2g recordings
 #ifndef MOZ_WIDGET_GONK
     RecordedFontData fontData(aFont);
     RecordedFontDetails fontDetails;
     if (fontData.GetFontDetails(fontDetails)) {
       if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) {
         mRecorder->RecordEvent(fontData);
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -128,16 +128,18 @@ enum class LogReason : int {
   SourceSurfaceIncompatible,
   GlyphAllocFailedCairo,
   GlyphAllocFailedCG,
   InvalidRect,
   CannotDraw3D, // 20
   IncompatibleBasicTexturedEffect,
   InvalidFont,
   PAllocTextureBackendMismatch,
+  GetFontFileDataFailed,
+  MessageChannelCloseFailure,
   // End
   MustBeLessThanThis = 101,
 };
 
 struct BasicLogger
 {
   // For efficiency, this method exists and copies the logic of the
   // OutputMessage below.  If making any changes here, also make it
--- a/gfx/2d/SFNTData.cpp
+++ b/gfx/2d/SFNTData.cpp
@@ -111,44 +111,46 @@ private:
 /* static */
 UniquePtr<SFNTData>
 SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
 {
   MOZ_ASSERT(aFontData);
 
   // Check to see if this is a font collection.
   if (aDataLength < sizeof(TTCHeader)) {
-    gfxWarning() << "Font data too short.";
+    gfxDevCrash(LogReason::GetFontFileDataFailed) << "Font data too short: length = " << aDataLength;
     return nullptr;
   }
 
   const TTCHeader *ttcHeader = reinterpret_cast<const TTCHeader*>(aFontData);
   if (ttcHeader->ttcTag == TRUETYPE_TAG('t', 't', 'c', 'f')) {
     uint32_t numFonts = ttcHeader->numFonts;
     if (aDataLength < sizeof(TTCHeader) + (numFonts * sizeof(BigEndianUint32))) {
-      gfxWarning() << "Font data too short to contain full TTC Header.";
+      gfxDevCrash(LogReason::GetFontFileDataFailed) << "Font data too short to contain full TTC Header: numFonts = " << numFonts << "; length = " << aDataLength;
       return nullptr;
     }
 
     UniquePtr<SFNTData> sfntData(new SFNTData);
     const BigEndianUint32* offset =
       reinterpret_cast<const BigEndianUint32*>(aFontData + sizeof(TTCHeader));
     const BigEndianUint32* endOfOffsets = offset + numFonts;
     while (offset != endOfOffsets) {
       if (!sfntData->AddFont(aFontData, aDataLength, *offset)) {
+        gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to add font data from TTC";
         return nullptr;
       }
       ++offset;
     }
 
     return Move(sfntData);
   }
 
   UniquePtr<SFNTData> sfntData(new SFNTData);
   if (!sfntData->AddFont(aFontData, aDataLength, 0)) {
+    gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to add single font data";
     return nullptr;
   }
 
   return Move(sfntData);
 }
 
 /* static */
 uint64_t
@@ -218,25 +220,25 @@ SFNTData::GetIndexForU16Name(const mozil
 }
 
 bool
 SFNTData::AddFont(const uint8_t *aFontData, uint32_t aDataLength,
                   uint32_t aOffset)
 {
   uint32_t remainingLength = aDataLength - aOffset;
   if (remainingLength < sizeof(OffsetTable)) {
-    gfxWarning() << "Font data too short to contain OffsetTable " << aOffset;
+    gfxCriticalError() << "Font data too short to contain OffsetTable: offset = " << aOffset << "; length = " << aDataLength;
     return false;
   }
 
   const OffsetTable *offsetTable =
     reinterpret_cast<const OffsetTable*>(aFontData + aOffset);
   if (remainingLength <
       sizeof(OffsetTable) + (offsetTable->numTables * sizeof(TableDirEntry))) {
-    gfxWarning() << "Font data too short to contain tables.";
+    gfxCriticalError() << "Font data too short to contain tables. numTables = " << offsetTable->numTables << "; offset = " << aOffset << "; length = " << aDataLength;
     return false;
   }
 
   return mFonts.append(new Font(offsetTable, aFontData, aDataLength));
 }
 
 } // gfx
 } // mozilla
--- a/gfx/2d/ScaledFontWin.cpp
+++ b/gfx/2d/ScaledFontWin.cpp
@@ -35,43 +35,45 @@ ScaledFontWin::GetFontFileData(FontFileD
   // Check for a font collection first.
   uint32_t table = 0x66637474; // 'ttcf'
   uint32_t tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0);
   if (tableSize == GDI_ERROR) {
     // Try as if just a single font.
     table = 0;
     tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0);
     if (tableSize == GDI_ERROR) {
+      gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to get font data from GDI";
       return false;
     }
   }
 
   UniquePtr<uint8_t[]> fontData(new uint8_t[tableSize]);
 
   uint32_t sizeGot =
     ::GetFontData(dc.GetDC(), table, 0, fontData.get(), tableSize);
   if (sizeGot != tableSize) {
+    gfxDevCrash(LogReason::GetFontFileDataFailed) << "GDI did not return enough data for font: wanted " << tableSize << ", got " << sizeGot;
     return false;
   }
 
   // If it's a font collection then attempt to get the index.
   uint32_t index = 0;
   if (table != 0) {
     UniquePtr<SFNTData> sfntData = SFNTData::Create(fontData.get(),
                                                     tableSize);
     if (!sfntData) {
-      gfxWarning() << "Failed to create SFNTData for GetFontFileData.";
+      gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to create SFNTData for GetFontFileData.";
       return false;
     }
 
     // We cast here because for VS2015 char16_t != wchar_t, even though they are
     // both 16 bit.
     if (!sfntData->GetIndexForU16Name(
           reinterpret_cast<char16_t*>(mLogFont.lfFaceName), &index)) {
-      gfxWarning() << "Failed to get index for face name.";
+      gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to get index for face name.";
       return false;
     }
   }
 
   aDataCallback(fontData.get(), tableSize, index, mSize, aBaton);
   return true;
 }
 
--- a/gfx/gl/GLDefs.h
+++ b/gfx/gl/GLDefs.h
@@ -45,34 +45,44 @@
 #define LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA            0x87EE
 
 // EGL_ANDROID_image_crop
 #define LOCAL_EGL_IMAGE_CROP_LEFT_ANDROID               0x3148
 #define LOCAL_EGL_IMAGE_CROP_TOP_ANDROID                0x3149
 #define LOCAL_EGL_IMAGE_CROP_RIGHT_ANDROID              0x314A
 #define LOCAL_EGL_IMAGE_CROP_BOTTOM_ANDROID             0x314B
 
+// EGL_ANGLE_platform_angle
+#define LOCAL_EGL_PLATFORM_ANGLE_ANGLE                      0x3202
+#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE                 0x3203
+#define LOCAL_EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE    0x3204
+#define LOCAL_EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE    0x3205
+#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE         0x3206
+
+// EGL_ANGLE_platform_angle_d3d
+#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE              0x3207
+#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE             0x3208
+#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE            0x3209
+#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE   0x320A
+#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE       0x320B
+#define LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE  0x320C
+#define LOCAL_EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE  0x320F
+
+// EGL_ANGLE_direct3d_display
+#define LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE         ((EGLNativeDisplayType)-2)
+#define LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE              ((EGLNativeDisplayType)-3)
+
+// WGL_NV_DX_interop
+#define LOCAL_WGL_ACCESS_READ_ONLY                      0x0000
+#define LOCAL_WGL_ACCESS_READ_WRITE                     0x0001
+#define LOCAL_WGL_ACCESS_WRITE_DISCARD                  0x0002
+
 // Others
 #define LOCAL_EGL_PRESERVED_RESOURCES                   0x3030
 #define LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
-
-// ANGLE_platform_angle_d3d
-#define LOCAL_EGL_PLATFORM_ANGLE_ANGLE                  0x3201
-#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE             0x3202
-#define LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE  0x3206
-
 #define LOCAL_GL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
 #define LOCAL_GL_CONTEXT_LOST                           0x9242
 #define LOCAL_GL_CONTEXT_FLAGS_ARB                      0x2094
 #define LOCAL_GL_CONTEXT_CORE_PROFILE_BIT_ARB           0x00000001
 #define LOCAL_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB  0x00000002
 #define LOCAL_GL_CONTEXT_ROBUST_ACCESS_BIT_ARB          0x00000004
 
-
-#define LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE         ((EGLNativeDisplayType)-2)
-#define LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE              ((EGLNativeDisplayType)-3)
-
-// WGL_NV_DX_interop
-#define LOCAL_WGL_ACCESS_READ_ONLY                           0x0000
-#define LOCAL_WGL_ACCESS_READ_WRITE                          0x0001
-#define LOCAL_WGL_ACCESS_WRITE_DISCARD                       0x0002
-
 #endif
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -109,25 +109,34 @@ LoadLibraryForEGLOnWindows(const nsAStri
     return lib;
 }
 
 #endif // XP_WIN
 
 static EGLDisplay
 GetAndInitWARPDisplay(GLLibraryEGL& egl, void* displayType)
 {
-    EGLint attrib_list[] = {  LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE,
-                              LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE,
+    EGLint attrib_list[] = {  LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
+                              LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
+                              // Requires:
+                              LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+                              LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
                               LOCAL_EGL_NONE };
     EGLDisplay display = egl.fGetPlatformDisplayEXT(LOCAL_EGL_PLATFORM_ANGLE_ANGLE,
                                                     displayType,
                                                     attrib_list);
 
-    if (display == EGL_NO_DISPLAY)
+    if (display == EGL_NO_DISPLAY) {
+        const EGLint err = egl.fGetError();
+        if (err != LOCAL_EGL_SUCCESS) {
+            printf_stderr("Unexpected error: 0x%04x", err);
+            MOZ_CRASH("Unexpected error.");
+        }
         return EGL_NO_DISPLAY;
+    }
 
     if (!egl.fInitialize(display, nullptr, nullptr))
         return EGL_NO_DISPLAY;
 
     return display;
 }
 
 static bool
@@ -370,27 +379,25 @@ GLLibraryEGL::EnsureInitialized(bool for
     // Check the ANGLE support the system has
     nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
     mIsANGLE = IsExtensionSupported(ANGLE_platform_angle);
 
     EGLDisplay chosenDisplay = nullptr;
 
     if (IsExtensionSupported(ANGLE_platform_angle_d3d)) {
         bool accelAngleSupport = IsAccelAngleSupported(gfxInfo);
-        bool warpAngleSupport = gfxPlatform::CanUseDirect3D11ANGLE();
 
         bool shouldTryAccel = forceAccel || accelAngleSupport;
-        bool shouldTryWARP = !shouldTryAccel && warpAngleSupport;
+        bool shouldTryWARP = !shouldTryAccel;
         if (gfxPrefs::WebGLANGLEForceWARP()) {
             shouldTryWARP = true;
             shouldTryAccel = false;
         }
 
-        // Fallback to a WARP display if non-WARP is blacklisted,
-        // or if WARP is forced
+        // Fallback to a WARP display if non-WARP is blacklisted, or if WARP is forced.
         if (shouldTryWARP) {
             chosenDisplay = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY);
             if (chosenDisplay) {
                 mIsWARP = true;
             }
         }
 
         if (!chosenDisplay) {
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1072,16 +1072,24 @@ APZCTreeManager::ProcessMouseEvent(Widge
   nsEventStatus status = ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId);
 
   aEvent.refPoint.x = input.mOrigin.x;
   aEvent.refPoint.y = input.mOrigin.y;
   aEvent.mFlags.mHandledByAPZ = true;
   return status;
 }
 
+void
+APZCTreeManager::ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY)
+{
+  if (mApzcForInputBlock) {
+    mApzcForInputBlock->HandleTouchVelocity(aTimestampMs, aSpeedY);
+  }
+}
+
 nsEventStatus
 APZCTreeManager::ProcessWheelEvent(WidgetWheelEvent& aEvent,
                                    ScrollableLayerGuid* aOutTargetGuid,
                                    uint64_t* aOutInputBlockId)
 {
   ScrollWheelInput::ScrollMode scrollMode = ScrollWheelInput::SCROLLMODE_INSTANT;
   if (gfxPrefs::SmoothScrollEnabled() &&
       ((aEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE &&
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -437,16 +437,24 @@ public:
      used by other production code.
   */
   RefPtr<HitTestingTreeNode> GetRootNode() const;
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint,
                                                          HitTestResult* aOutHitResult,
                                                          bool* aOutHitScrollbar = nullptr);
   ScreenToParentLayerMatrix4x4 GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const;
   ParentLayerToScreenMatrix4x4 GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const;
+
+  /**
+   * Process touch velocity.
+   * Sometimes the touch move event will have a velocity even though no scrolling
+   * is occurring such as when the toolbar is being hidden/shown in Fennec.
+   * This function can be called to have the y axis' velocity queue updated.
+   */
+  void ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY);
 private:
   typedef bool (*GuidComparator)(const ScrollableLayerGuid&, const ScrollableLayerGuid&);
 
   /* Helpers */
   void AttachNodeToTree(HitTestingTreeNode* aNode,
                         HitTestingTreeNode* aParent,
                         HitTestingTreeNode* aNextSibling);
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1231,16 +1231,21 @@ nsEventStatus AsyncPanZoomController::Ha
     break;
   }
   default: NS_WARNING("Unhandled input event"); break;
   }
 
   return rv;
 }
 
+void AsyncPanZoomController::HandleTouchVelocity(uint32_t aTimesampMs, float aSpeedY)
+{
+  mY.HandleTouchVelocity(aTimesampMs, aSpeedY);
+}
+
 nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent) {
   APZC_LOG("%p got a touch-start in state %d\n", this, mState);
   mPanDirRestricted = false;
   ParentLayerPoint point = GetFirstTouchPoint(aEvent);
 
   switch (mState) {
     case FLING:
     case ANIMATING_ZOOM:
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -259,16 +259,24 @@ public:
    * Currently some gestures are detected in GestureEventListener that calls
    * APZC back through this handler in order to avoid recursive calls to
    * APZC::HandleInputEvent() which is supposed to do the work for
    * ReceiveInputEvent().
    */
   nsEventStatus HandleGestureEvent(const InputData& aEvent);
 
   /**
+   * Handler for touch velocity.
+   * Sometimes the touch move event will have a velocity even though no scrolling
+   * is occurring such as when the toolbar is being hidden/shown in Fennec.
+   * This function can be called to have the y axis' velocity queue updated.
+   */
+  void HandleTouchVelocity(uint32_t aTimesampMs, float aSpeedY);
+
+  /**
    * Populates the provided object (if non-null) with the scrollable guid of this apzc.
    */
   void GetGuid(ScrollableLayerGuid* aGuidOut) const;
 
   /**
    * Returns the scrollable guid of this apzc.
    */
   ScrollableLayerGuid GetGuid() const;
--- a/gfx/layers/apz/src/Axis.cpp
+++ b/gfx/layers/apz/src/Axis.cpp
@@ -84,16 +84,31 @@ void Axis::UpdateWithTouchAtDevicePoint(
     // required time delta we use the corresponding distance delta as well.
     AXIS_LOG("%p|%s skipping velocity computation for small time delta %dms\n",
         mAsyncPanZoomController, Name(), (aTimestampMs - mVelocitySampleTimeMs));
     mPos = aPos;
     return;
   }
 
   float newVelocity = mAxisLocked ? 0.0f : (float)(mVelocitySamplePos - aPos + aAdditionalDelta) / (float)(aTimestampMs - mVelocitySampleTimeMs);
+
+  newVelocity = ApplyFlingCurveToVelocity(newVelocity);
+
+  AXIS_LOG("%p|%s updating velocity to %f with touch\n",
+    mAsyncPanZoomController, Name(), newVelocity);
+  mVelocity = newVelocity;
+  mPos = aPos;
+  mVelocitySampleTimeMs = aTimestampMs;
+  mVelocitySamplePos = aPos;
+
+  AddVelocityToQueue(aTimestampMs, mVelocity);
+}
+
+float Axis::ApplyFlingCurveToVelocity(float aVelocity) const {
+  float newVelocity = aVelocity;
   if (gfxPrefs::APZMaxVelocity() > 0.0f) {
     bool velocityIsNegative = (newVelocity < 0);
     newVelocity = fabs(newVelocity);
 
     float maxVelocity = ToLocalVelocity(gfxPrefs::APZMaxVelocity());
     newVelocity = std::min(newVelocity, maxVelocity);
 
     if (gfxPrefs::APZCurveThreshold() > 0.0f && gfxPrefs::APZCurveThreshold() < gfxPrefs::APZMaxVelocity()) {
@@ -112,30 +127,36 @@ void Axis::UpdateWithTouchAtDevicePoint(
       }
     }
 
     if (velocityIsNegative) {
       newVelocity = -newVelocity;
     }
   }
 
-  AXIS_LOG("%p|%s updating velocity to %f with touch\n",
-    mAsyncPanZoomController, Name(), newVelocity);
-  mVelocity = newVelocity;
-  mPos = aPos;
-  mVelocitySampleTimeMs = aTimestampMs;
-  mVelocitySamplePos = aPos;
+  return newVelocity;
+}
 
-  // Limit queue size pased on pref
-  mVelocityQueue.AppendElement(std::make_pair(aTimestampMs, mVelocity));
+void Axis::AddVelocityToQueue(uint32_t aTimestampMs, float aVelocity) {
+  mVelocityQueue.AppendElement(std::make_pair(aTimestampMs, aVelocity));
   if (mVelocityQueue.Length() > gfxPrefs::APZMaxVelocityQueueSize()) {
     mVelocityQueue.RemoveElementAt(0);
   }
 }
 
+void Axis::HandleTouchVelocity(uint32_t aTimestampMs, float aSpeed) {
+  // mVelocityQueue is controller-thread only
+  APZThreadUtils::AssertOnControllerThread();
+
+  mVelocity = ApplyFlingCurveToVelocity(aSpeed);
+  mVelocitySampleTimeMs = aTimestampMs;
+
+  AddVelocityToQueue(aTimestampMs, mVelocity);
+}
+
 void Axis::StartTouch(ParentLayerCoord aPos, uint32_t aTimestampMs) {
   mStartPos = aPos;
   mPos = aPos;
   mVelocitySampleTimeMs = aTimestampMs;
   mVelocitySamplePos = aPos;
   mAxisLocked = false;
 }
 
--- a/gfx/layers/apz/src/Axis.h
+++ b/gfx/layers/apz/src/Axis.h
@@ -44,16 +44,23 @@ public:
    * Notify this Axis that a new touch has been received, including a timestamp
    * for when the touch was received. This triggers a recalculation of velocity.
    * This can also used for pan gesture events. For those events, the "touch"
    * location is stationary and the scroll displacement is passed in as
    * aAdditionalDelta.
    */
   void UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos, ParentLayerCoord aAdditionalDelta, uint32_t aTimestampMs);
 
+protected:
+  float ApplyFlingCurveToVelocity(float aVelocity) const;
+  void AddVelocityToQueue(uint32_t aTimestampMs, float aVelocity);
+
+public:
+  void HandleTouchVelocity(uint32_t aTimestampMs, float aSpeed);
+
   /**
    * Notify this Axis that a touch has begun, i.e. the user has put their finger
    * on the screen but has not yet tried to pan.
    */
   void StartTouch(ParentLayerCoord aPos, uint32_t aTimestampMs);
 
   /**
    * Notify this Axis that a touch has ended gracefully. This may perform
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -57,16 +57,23 @@ public:
 
   virtual void ClearCachedResources() override
   {
     if (mCanvasClient) {
       mCanvasClient->Clear();
     }
   }
 
+  virtual void HandleMemoryPressure() override
+  {
+    if (mCanvasClient) {
+      mCanvasClient->HandleMemoryPressure();
+    }
+  }
+
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override
   {
     aAttrs = CanvasLayerAttributes(mFilter, mBounds);
   }
 
   virtual Layer* AsLayer()  override { return this; }
   virtual ShadowableLayer* AsShadowableLayer()  override { return this; }
 
--- a/gfx/layers/client/ClientImageLayer.cpp
+++ b/gfx/layers/client/ClientImageLayer.cpp
@@ -55,16 +55,23 @@ protected:
 
   virtual void RenderLayer() override;
   
   virtual void ClearCachedResources() override
   {
     DestroyBackBuffer();
   }
 
+  virtual void HandleMemoryPressure() override
+  {
+    if (mImageClient) {
+      mImageClient->HandleMemoryPressure();
+    }
+  }
+
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override
   {
     aAttrs = ImageLayerAttributes(mFilter, mScaleToSize, mScaleMode);
   }
 
   virtual Layer* AsLayer() override { return this; }
   virtual ShadowableLayer* AsShadowableLayer() override { return this; }
 
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -742,32 +742,46 @@ ClientLayerManager::ClearCachedResources
   for (size_t i = 0; i < mTexturePools.Length(); i++) {
     mTexturePools[i]->Clear();
   }
 }
 
 void
 ClientLayerManager::HandleMemoryPressure()
 {
+  if (mRoot) {
+    HandleMemoryPressureLayer(mRoot);
+  }
+
   for (size_t i = 0; i < mTexturePools.Length(); i++) {
     mTexturePools[i]->ShrinkToMinimumSize();
   }
 }
 
 void
 ClientLayerManager::ClearLayer(Layer* aLayer)
 {
   ClientLayer::ToClientLayer(aLayer)->ClearCachedResources();
   for (Layer* child = aLayer->GetFirstChild(); child;
        child = child->GetNextSibling()) {
     ClearLayer(child);
   }
 }
 
 void
+ClientLayerManager::HandleMemoryPressureLayer(Layer* aLayer)
+{
+  ClientLayer::ToClientLayer(aLayer)->HandleMemoryPressure();
+  for (Layer* child = aLayer->GetFirstChild(); child;
+       child = child->GetNextSibling()) {
+    HandleMemoryPressureLayer(child);
+  }
+}
+
+void
 ClientLayerManager::GetBackendName(nsAString& aName)
 {
   switch (mForwarder->GetCompositorBackendType()) {
     case LayersBackend::LAYERS_NONE: aName.AssignLiteral("None"); return;
     case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return;
     case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return;
     case LayersBackend::LAYERS_D3D9: aName.AssignLiteral("Direct3D 9"); return;
     case LayersBackend::LAYERS_D3D11: {
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -294,16 +294,18 @@ private:
   /**
    * Take a snapshot of the parent context, and copy
    * it into mShadowTarget.
    */
   void MakeSnapshotIfRequired();
 
   void ClearLayer(Layer* aLayer);
 
+  void HandleMemoryPressureLayer(Layer* aLayer);
+
   bool EndTransactionInternal(DrawPaintedLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags);
 
   bool DependsOnStaleDevice() const;
 
   LayerRefArray mKeepAlive;
 
@@ -381,16 +383,20 @@ public:
     // automatically managed by IPDL, so we don't need to explicitly
     // free them here (it's hard to get that right on emergency
     // shutdown anyway).
     mShadow = nullptr;
   }
 
   virtual void ClearCachedResources() { }
 
+  // Shrink memory usage.
+  // Called when "memory-pressure" is observed.
+  virtual void HandleMemoryPressure() { }
+
   virtual void RenderLayer() = 0;
   virtual void RenderLayerWithReadback(ReadbackProcessor *aReadback) { RenderLayer(); }
 
   virtual ClientPaintedLayer* AsThebes() { return nullptr; }
 
   static inline ClientLayer *
   ToClientLayer(Layer* aLayer)
   {
--- a/gfx/layers/client/ClientPaintedLayer.h
+++ b/gfx/layers/client/ClientPaintedLayer.h
@@ -72,17 +72,24 @@ public:
   virtual void ClearCachedResources() override
   {
     if (mContentClient) {
       mContentClient->Clear();
     }
     mValidRegion.SetEmpty();
     DestroyBackBuffer();
   }
-  
+
+  virtual void HandleMemoryPressure() override
+  {
+    if (mContentClient) {
+      mContentClient->HandleMemoryPressure();
+    }
+  }
+
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override
   {
     aAttrs = PaintedLayerAttributes(GetValidRegion());
   }
   
   ClientLayerManager* ClientManager()
   {
     return static_cast<ClientLayerManager*>(mManager);
--- a/gfx/layers/client/ClientTiledPaintedLayer.h
+++ b/gfx/layers/client/ClientTiledPaintedLayer.h
@@ -68,16 +68,23 @@ public:
   {
     ClientLayer::Disconnect();
   }
 
   virtual void RenderLayer() override;
 
   virtual void ClearCachedResources() override;
 
+  virtual void HandleMemoryPressure() override
+  {
+    if (mContentClient) {
+      mContentClient->HandleMemoryPressure();
+    }
+  }
+
   /**
    * Helper method to find the nearest ancestor layers which
    * scroll and have a displayport. The parameters are out-params
    * which hold the return values; the values passed in may be null.
    */
   void GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
                          LayerMetricsWrapper* aOutDisplayPortAncestor,
                          bool* aOutHasTransformAnimation);
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -238,17 +238,25 @@ CompositableClient::AddTextureClient(Tex
   aClient->SetAddedToCompositableClient();
   return aClient->InitIPDLActor(mForwarder);
 }
 
 void
 CompositableClient::ClearCachedResources()
 {
   if (mTextureClientRecycler) {
-    mTextureClientRecycler = nullptr;
+    mTextureClientRecycler->ShrinkToMinimumSize();
+  }
+}
+
+void
+CompositableClient::HandleMemoryPressure()
+{
+  if (mTextureClientRecycler) {
+    mTextureClientRecycler->ShrinkToMinimumSize();
   }
 }
 
 void
 CompositableClient::RemoveTexture(TextureClient* aTexture)
 {
   mForwarder->RemoveTextureFromCompositable(this, aTexture);
 }
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -191,16 +191,22 @@ public:
 
   /**
    * Clear any resources that are not immediately necessary. This may be called
    * in low-memory conditions.
    */
   virtual void ClearCachedResources();
 
   /**
+   * Shrink memory usage.
+   * Called when "memory-pressure" is observed.
+   */
+  virtual void HandleMemoryPressure();
+
+  /**
    * Should be called when deataching a TextureClient from a Compositable, because
    * some platforms need to do some extra book keeping when this happens (for
    * example to properly keep track of fences on Gonk).
    *
    * See AutoRemoveTexture to automatically invoke this at the end of a scope.
    */
   virtual void RemoveTexture(TextureClient* aTexture);
 
--- a/gfx/layers/client/TextureClientRecycleAllocator.cpp
+++ b/gfx/layers/client/TextureClientRecycleAllocator.cpp
@@ -190,16 +190,25 @@ TextureClientRecycleAllocator::Allocate(
                                         TextureFlags aTextureFlags,
                                         TextureAllocationFlags aAllocFlags)
 {
   return TextureClient::CreateForDrawing(mSurfaceAllocator, aFormat, aSize, aSelector,
                                          aTextureFlags, aAllocFlags);
 }
 
 void
+TextureClientRecycleAllocator::ShrinkToMinimumSize()
+{
+  MutexAutoLock lock(mLock);
+  while (!mPooledClients.empty()) {
+    mPooledClients.pop();
+  }
+}
+
+void
 TextureClientRecycleAllocator::RecycleTextureClient(TextureClient* aClient)
 {
   // Clearing the recycle allocator drops a reference, so make sure we stay alive
   // for the duration of this function.
   RefPtr<TextureClientRecycleAllocator> kungFuDeathGrip(this);
   aClient->SetRecycleAllocator(nullptr);
 
   RefPtr<TextureClientHolder> textureHolder;
--- a/gfx/layers/client/TextureClientRecycleAllocator.h
+++ b/gfx/layers/client/TextureClientRecycleAllocator.h
@@ -81,16 +81,18 @@ public:
                   gfx::IntSize aSize,
                   BackendSelector aSelector,
                   TextureFlags aTextureFlags,
                   TextureAllocationFlags flags = ALLOC_DEFAULT);
 
   already_AddRefed<TextureClient>
   CreateOrRecycle(ITextureClientAllocationHelper& aHelper);
 
+  void ShrinkToMinimumSize();
+
 protected:
   virtual already_AddRefed<TextureClient>
   Allocate(gfx::SurfaceFormat aFormat,
            gfx::IntSize aSize,
            BackendSelector aSelector,
            TextureFlags aTextureFlags,
            TextureAllocationFlags aAllocFlags);
 
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -667,17 +667,17 @@ CompositorD3D9::Ready()
 void
 CompositorD3D9::FailedToResetDevice() {
   mFailedResetAttempts += 1;
   // 10 is a totally arbitrary number that we may want to increase or decrease
   // depending on how things behave in the wild.
   if (mFailedResetAttempts > 10) {
     mFailedResetAttempts = 0;
     gfxWindowsPlatform::GetPlatform()->D3D9DeviceReset();
-    gfxWarning() << "[D3D9] Unable to get a working D3D9 Compositor";
+    gfxCriticalNote << "[D3D9] Unable to get a working D3D9 Compositor";
   }
 }
 
 void
 CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion,
                            const Rect *aClipRectIn,
                            const Rect& aRenderBounds,
                            const nsIntRegion& aOpaqueRegion,
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -899,17 +899,17 @@ TextureHostD3D9::UpdatedInternal(const n
                                                nullptr, mFlags);
     if (mFlags & TextureFlags::COMPONENT_ALPHA) {
       // Update the full region the first time for component alpha textures.
       regionToUpdate = nullptr;
     }
   }
 
   if (!mTextureSource->UpdateFromTexture(mTexture, regionToUpdate)) {
-    gfxWarning() << "[D3D9] DataTextureSourceD3D9::UpdateFromTexture failed";
+    gfxCriticalNote << "[D3D9] DataTextureSourceD3D9::UpdateFromTexture failed";
   }
 }
 
 IDirect3DDevice9*
 TextureHostD3D9::GetDevice()
 {
   if (mFlags & TextureFlags::INVALID_COMPOSITOR) {
     return nullptr;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2066,21 +2066,18 @@ InitLayersAccelerationPrefs()
     int32_t status;
 #ifdef XP_WIN
     if (gfxPrefs::LayersAccelerationForceEnabled()) {
       sLayersSupportsD3D9 = true;
       sLayersSupportsD3D11 = true;
     } else if (gfxInfo) {
       if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
         if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
-          if (sPrefBrowserTabsRemoteAutostart && !IsVistaOrLater()) {
-            gfxWarning() << "Disallowing D3D9 on Windows XP with E10S - see bug 1237770";
-          } else {
-            sLayersSupportsD3D9 = true;
-          }
+          MOZ_ASSERT(!sPrefBrowserTabsRemoteAutostart || IsVistaOrLater());
+          sLayersSupportsD3D9 = true;
         }
       }
       if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
         if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
           sLayersSupportsD3D11 = true;
         }
       }
       if (!gfxPrefs::LayersD3D11DisableWARP()) {
@@ -2207,21 +2204,21 @@ gfxPlatform::GetScaledFontForFontWithCai
     }
 
     return nullptr;
 }
 
 /* static */ bool
 gfxPlatform::UsesOffMainThreadCompositing()
 {
-  InitLayersAccelerationPrefs();
   static bool firstTime = true;
   static bool result = false;
 
   if (firstTime) {
+    InitLayersAccelerationPrefs();
     result =
       sPrefBrowserTabsRemoteAutostart ||
       !gfxPrefs::LayersOffMainThreadCompositionForceDisabled();
 #if defined(MOZ_WIDGET_GTK)
     // Linux users who chose OpenGL are being grandfathered in to OMTC
     result |= gfxPrefs::LayersAccelerationForceEnabled();
 
 #endif
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -425,17 +425,17 @@ private:
   DECL_GFX_PREF(Live, "test.mousescroll",                      MouseScrollTestingEnabled, bool, false);
 
   DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay",     UiClickHoldContextMenusDelay, int32_t, 500);
 
   // WebGL (for pref access from Worker threads)
   DECL_GFX_PREF(Live, "webgl.all-angle-options",               WebGLAllANGLEOptions, bool, false);
   DECL_GFX_PREF(Live, "webgl.angle.force-d3d11",               WebGLANGLEForceD3D11, bool, false);
   DECL_GFX_PREF(Live, "webgl.angle.try-d3d11",                 WebGLANGLETryD3D11, bool, false);
-  DECL_GFX_PREF(Once, "webgl.angle.force-warp",                WebGLANGLEForceWARP, bool, false);
+  DECL_GFX_PREF(Live, "webgl.angle.force-warp",                WebGLANGLEForceWARP, bool, false);
   DECL_GFX_PREF(Live, "webgl.bypass-shader-validation",        WebGLBypassShaderValidator, bool, true);
   DECL_GFX_PREF(Live, "webgl.can-lose-context-in-foreground",  WebGLCanLoseContextInForeground, bool, true);
   DECL_GFX_PREF(Live, "webgl.default-no-alpha",                WebGLDefaultNoAlpha, bool, false);
   DECL_GFX_PREF(Live, "webgl.disable-angle",                   WebGLDisableANGLE, bool, false);
   DECL_GFX_PREF(Live, "webgl.disable-extensions",              WebGLDisableExtensions, bool, false);
   DECL_GFX_PREF(Live, "webgl.dxgl.enabled",                    WebGLDXGLEnabled, bool, false);
   DECL_GFX_PREF(Live, "webgl.dxgl.needs-finish",               WebGLDXGLNeedsFinish, bool, false);
 
--- a/gfx/vr/gfxVR.cpp
+++ b/gfx/vr/gfxVR.cpp
@@ -48,17 +48,16 @@ VRHMDInfo::~VRHMDInfo()
 
 /* static */ uint32_t
 VRHMDManager::AllocateDeviceID()
 {
   return ++sDeviceBase;
 }
 
 VRHMDRenderingSupport::RenderTargetSet::RenderTargetSet()
-  : currentRenderTarget(0)
 {
 }
 
 VRHMDRenderingSupport::RenderTargetSet::~RenderTargetSet()
 {
 }
 
 Matrix4x4
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -231,17 +231,16 @@ public:
   struct RenderTargetSet {
     RenderTargetSet();
     
     NS_INLINE_DECL_REFCOUNTING(RenderTargetSet)
 
     RefPtr<layers::Compositor> compositor;
     IntSize size;
     nsTArray<RefPtr<layers::CompositingRenderTarget>> renderTargets;
-    int32_t currentRenderTarget;
 
     virtual already_AddRefed<layers::CompositingRenderTarget> GetNextRenderTarget() = 0;
   protected:
     virtual ~RenderTargetSet();
   };
 
   virtual already_AddRefed<RenderTargetSet> CreateRenderTargetSet(layers::Compositor *aCompositor, const IntSize& aSize) = 0;
   virtual void DestroyRenderTargetSet(RenderTargetSet *aRTSet) = 0;
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -28,45 +28,77 @@
 using namespace mozilla::gfx;
 using namespace mozilla::gfx::impl;
 
 namespace {
 
 #ifdef OVR_CAPI_LIMITED_MOZILLA
 static pfn_ovr_Initialize ovr_Initialize = nullptr;
 static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
-static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
+static pfn_ovr_GetLastErrorInfo ovr_GetLastErrorInfo = nullptr;
+static pfn_ovr_GetVersionString ovr_GetVersionString = nullptr;
+static pfn_ovr_TraceMessage ovr_TraceMessage = nullptr;
 static pfn_ovr_GetHmdDesc ovr_GetHmdDesc = nullptr;
-
+static pfn_ovr_GetTrackerCount ovr_GetTrackerCount = nullptr;
+static pfn_ovr_GetTrackerDesc ovr_GetTrackerDesc = nullptr;
 static pfn_ovr_Create ovr_Create = nullptr;
 static pfn_ovr_Destroy ovr_Destroy = nullptr;
-
-static pfn_ovr_RecenterPose ovr_RecenterPose = nullptr;
+static pfn_ovr_GetSessionStatus ovr_GetSessionStatus = nullptr;
+static pfn_ovr_SetTrackingOriginType ovr_SetTrackingOriginType = nullptr;
+static pfn_ovr_GetTrackingOriginType ovr_GetTrackingOriginType = nullptr;
+static pfn_ovr_RecenterTrackingOrigin ovr_RecenterTrackingOrigin = nullptr;
+static pfn_ovr_ClearShouldRecenterFlag ovr_ClearShouldRecenterFlag = nullptr;
 static pfn_ovr_GetTrackingState ovr_GetTrackingState = nullptr;
-static pfn_ovr_GetPredictedDisplayTime ovr_GetPredictedDisplayTime = nullptr;
+static pfn_ovr_GetTrackerPose ovr_GetTrackerPose = nullptr;
+static pfn_ovr_GetInputState ovr_GetInputState = nullptr;
+static pfn_ovr_GetConnectedControllerTypes ovr_GetConnectedControllerTypes = nullptr;
+static pfn_ovr_SetControllerVibration ovr_SetControllerVibration = nullptr;
+static pfn_ovr_GetTextureSwapChainLength ovr_GetTextureSwapChainLength = nullptr;
+static pfn_ovr_GetTextureSwapChainCurrentIndex ovr_GetTextureSwapChainCurrentIndex = nullptr;
+static pfn_ovr_GetTextureSwapChainDesc ovr_GetTextureSwapChainDesc = nullptr;
+static pfn_ovr_CommitTextureSwapChain ovr_CommitTextureSwapChain = nullptr;
+static pfn_ovr_DestroyTextureSwapChain ovr_DestroyTextureSwapChain = nullptr;
+static pfn_ovr_DestroyMirrorTexture ovr_DestroyMirrorTexture = nullptr;
 static pfn_ovr_GetFovTextureSize ovr_GetFovTextureSize = nullptr;
 static pfn_ovr_GetRenderDesc ovr_GetRenderDesc = nullptr;
-
-static pfn_ovr_DestroySwapTextureSet ovr_DestroySwapTextureSet = nullptr;
 static pfn_ovr_SubmitFrame ovr_SubmitFrame = nullptr;
+static pfn_ovr_GetPredictedDisplayTime ovr_GetPredictedDisplayTime = nullptr;
+static pfn_ovr_GetTimeInSeconds ovr_GetTimeInSeconds = nullptr;
+static pfn_ovr_GetBool ovr_GetBool = nullptr;
+static pfn_ovr_SetBool ovr_SetBool = nullptr;
+static pfn_ovr_GetInt ovr_GetInt = nullptr;
+static pfn_ovr_SetInt ovr_SetInt = nullptr;
+static pfn_ovr_GetFloat ovr_GetFloat = nullptr;
+static pfn_ovr_SetFloat ovr_SetFloat = nullptr;
+static pfn_ovr_GetFloatArray ovr_GetFloatArray = nullptr;
+static pfn_ovr_SetFloatArray ovr_SetFloatArray = nullptr;
+static pfn_ovr_GetString ovr_GetString = nullptr;
+static pfn_ovr_SetString ovr_SetString = nullptr;
 
 #ifdef XP_WIN
-static pfn_ovr_CreateSwapTextureSetD3D11 ovr_CreateSwapTextureSetD3D11 = nullptr;
+static pfn_ovr_CreateTextureSwapChainDX ovr_CreateTextureSwapChainDX = nullptr;
+static pfn_ovr_GetTextureSwapChainBufferDX ovr_GetTextureSwapChainBufferDX = nullptr;
+static pfn_ovr_CreateMirrorTextureDX ovr_CreateMirrorTextureDX = nullptr;
+static pfn_ovr_GetMirrorTextureBufferDX ovr_GetMirrorTextureBufferDX = nullptr;
 #endif
-static pfn_ovr_CreateSwapTextureSetGL ovr_CreateSwapTextureSetGL = nullptr;
+
+static pfn_ovr_CreateTextureSwapChainGL ovr_CreateTextureSwapChainGL = nullptr;
+static pfn_ovr_GetTextureSwapChainBufferGL ovr_GetTextureSwapChainBufferGL = nullptr;
+static pfn_ovr_CreateMirrorTextureGL ovr_CreateMirrorTextureGL = nullptr;
+static pfn_ovr_GetMirrorTextureBufferGL ovr_GetMirrorTextureBufferGL = nullptr;
 
 #ifdef HAVE_64BIT_BUILD
 #define BUILD_BITS 64
 #else
 #define BUILD_BITS 32
 #endif
 
-#define OVR_PRODUCT_VERSION 0
-#define OVR_MAJOR_VERSION   8
-#define OVR_MINOR_VERSION   0
+#define OVR_PRODUCT_VERSION 1
+#define OVR_MAJOR_VERSION   3
+#define OVR_MINOR_VERSION   1
 
 static bool
 InitializeOculusCAPI()
 {
   static PRLibrary *ovrlib = nullptr;
 
   if (!ovrlib) {
     nsTArray<nsCString> libSearchPaths;
@@ -82,17 +114,17 @@ InitializeOculusCAPI()
 #if defined(_WIN32)
     static const int pathLen = 260;
     searchPath.SetCapacity(pathLen);
     int realLen = ::GetSystemDirectoryA(searchPath.BeginWriting(), pathLen);
     if (realLen != 0 && realLen < pathLen) {
       searchPath.SetLength(realLen);
       libSearchPaths.AppendElement(searchPath);
     }
-    libName.AppendPrintf("LibOVRRT%d_%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
+    libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
 #elif defined(__APPLE__)
     searchPath.Truncate();
     searchPath.AppendPrintf("/Library/Frameworks/LibOVRRT_%d.framework/Versions/%d", OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
     libSearchPaths.AppendElement(searchPath);
 
     if (PR_GetEnv("HOME")) {
       searchPath.Truncate();
       searchPath.AppendPrintf("%s/Library/Frameworks/LibOVRRT_%d.framework/Versions/%d", PR_GetEnv("HOME"), OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
@@ -158,34 +190,69 @@ InitializeOculusCAPI()
 
 #define REQUIRE_FUNCTION(_x) do { \
     *(void **)&_x = (void *) PR_FindSymbol(ovrlib, #_x);                \
     if (!_x) { printf_stderr(#_x " symbol missing\n"); goto fail; }       \
   } while (0)
 
   REQUIRE_FUNCTION(ovr_Initialize);
   REQUIRE_FUNCTION(ovr_Shutdown);
-  REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
+  REQUIRE_FUNCTION(ovr_GetLastErrorInfo);
+  REQUIRE_FUNCTION(ovr_GetVersionString);
+  REQUIRE_FUNCTION(ovr_TraceMessage);
   REQUIRE_FUNCTION(ovr_GetHmdDesc);
-  
+  REQUIRE_FUNCTION(ovr_GetTrackerCount);
+  REQUIRE_FUNCTION(ovr_GetTrackerDesc);
   REQUIRE_FUNCTION(ovr_Create);
   REQUIRE_FUNCTION(ovr_Destroy);
-  
-  REQUIRE_FUNCTION(ovr_RecenterPose);
+  REQUIRE_FUNCTION(ovr_GetSessionStatus);
+  REQUIRE_FUNCTION(ovr_SetTrackingOriginType);
+  REQUIRE_FUNCTION(ovr_GetTrackingOriginType);
+  REQUIRE_FUNCTION(ovr_RecenterTrackingOrigin);
+  REQUIRE_FUNCTION(ovr_ClearShouldRecenterFlag);
   REQUIRE_FUNCTION(ovr_GetTrackingState);
-  REQUIRE_FUNCTION(ovr_GetPredictedDisplayTime);
+  REQUIRE_FUNCTION(ovr_GetTrackerPose);
+  REQUIRE_FUNCTION(ovr_GetInputState);
+  REQUIRE_FUNCTION(ovr_GetConnectedControllerTypes);
+  REQUIRE_FUNCTION(ovr_SetControllerVibration);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainLength);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainCurrentIndex);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainDesc);
+  REQUIRE_FUNCTION(ovr_CommitTextureSwapChain);
+  REQUIRE_FUNCTION(ovr_DestroyTextureSwapChain);
+  REQUIRE_FUNCTION(ovr_DestroyMirrorTexture);
   REQUIRE_FUNCTION(ovr_GetFovTextureSize);
   REQUIRE_FUNCTION(ovr_GetRenderDesc);
+  REQUIRE_FUNCTION(ovr_SubmitFrame);
+  REQUIRE_FUNCTION(ovr_GetPredictedDisplayTime);
+  REQUIRE_FUNCTION(ovr_GetTimeInSeconds);
+  REQUIRE_FUNCTION(ovr_GetBool);
+  REQUIRE_FUNCTION(ovr_SetBool);
+  REQUIRE_FUNCTION(ovr_GetInt);
+  REQUIRE_FUNCTION(ovr_SetInt);
+  REQUIRE_FUNCTION(ovr_GetFloat);
+  REQUIRE_FUNCTION(ovr_SetFloat);
+  REQUIRE_FUNCTION(ovr_GetFloatArray);
+  REQUIRE_FUNCTION(ovr_SetFloatArray);
+  REQUIRE_FUNCTION(ovr_GetString);
+  REQUIRE_FUNCTION(ovr_SetString);
 
-  REQUIRE_FUNCTION(ovr_DestroySwapTextureSet);
-  REQUIRE_FUNCTION(ovr_SubmitFrame);
 #ifdef XP_WIN
-  REQUIRE_FUNCTION(ovr_CreateSwapTextureSetD3D11);
+
+  REQUIRE_FUNCTION(ovr_CreateTextureSwapChainDX);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainBufferDX);
+  REQUIRE_FUNCTION(ovr_CreateMirrorTextureDX);
+  REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferDX);
+
 #endif
-  REQUIRE_FUNCTION(ovr_CreateSwapTextureSetGL);
+
+  REQUIRE_FUNCTION(ovr_CreateTextureSwapChainGL);
+  REQUIRE_FUNCTION(ovr_GetTextureSwapChainBufferGL);
+  REQUIRE_FUNCTION(ovr_CreateMirrorTextureGL);
+  REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferGL);
 
 #undef REQUIRE_FUNCTION
 
   return true;
 
  fail:
   ovr_Initialize = nullptr;
   return false;
@@ -286,18 +353,18 @@ HMDInfoOculus::SetFOV(const gfx::VRField
 
   // get eye parameters and create the mesh
   for (uint32_t eye = 0; eye < VRDeviceInfo::NumEyes; eye++) {
     mDeviceInfo.mEyeFOV[eye] = eye == 0 ? aFOVLeft : aFOVRight;
     mFOVPort[eye] = ToFovPort(mDeviceInfo.mEyeFOV[eye]);
 
     ovrEyeRenderDesc renderDesc = ovr_GetRenderDesc(mSession, (ovrEyeType)eye, mFOVPort[eye]);
 
-    // As of Oculus 0.6.0, the HmdToEyeViewOffset values are correct and don't need to be negated.
-    mDeviceInfo.mEyeTranslation[eye] = Point3D(renderDesc.HmdToEyeViewOffset.x, renderDesc.HmdToEyeViewOffset.y, renderDesc.HmdToEyeViewOffset.z);
+    // As of Oculus 0.6.0, the HmdToEyeOffset values are correct and don't need to be negated.
+    mDeviceInfo.mEyeTranslation[eye] = Point3D(renderDesc.HmdToEyeOffset.x, renderDesc.HmdToEyeOffset.y, renderDesc.HmdToEyeOffset.z);
 
     // note that we are using a right-handed coordinate system here, to match CSS
     mDeviceInfo.mEyeProjectionMatrix[eye] = mDeviceInfo.mEyeFOV[eye].ConstructProjectionMatrix(zNear, zFar, true);
 
     texSize[eye] = ovr_GetFovTextureSize(mSession, (ovrEyeType)eye, mFOVPort[eye], pixelsPerDisplayPixel);
   }
 
   // take the max of both for eye resolution
@@ -333,17 +400,17 @@ void
 HMDInfoOculus::NotifyVsync(const mozilla::TimeStamp& aVsyncTimestamp)
 {
   ++mInputFrameID;
 }
 
 void
 HMDInfoOculus::ZeroSensor()
 {
-  ovr_RecenterPose(mSession);
+  ovr_RecenterTrackingOrigin(mSession);
 }
 
 VRHMDSensorState
 HMDInfoOculus::GetSensorState()
 {
   VRHMDSensorState result;
   double frameTiming = 0.0f;
   if (gfxPrefs::VRPosePredictionEnabled()) {
@@ -405,109 +472,124 @@ HMDInfoOculus::GetSensorState(double tim
     result.linearAcceleration[2] = pose.LinearAcceleration.z;
   }
   
   return result;
 }
 
 struct RenderTargetSetOculus : public VRHMDRenderingSupport::RenderTargetSet
 {
-  RenderTargetSetOculus(const IntSize& aSize,
+  RenderTargetSetOculus(ovrSession aSession,
+                        const IntSize& aSize,
                         HMDInfoOculus *aHMD,
-                        ovrSwapTextureSet *aTS)
+                        ovrTextureSwapChain aTS)
     : hmd(aHMD)
+    , textureSet(aTS)
+    , session(aSession)
   {
-    textureSet = aTS;
     size = aSize;
   }
   
   already_AddRefed<layers::CompositingRenderTarget> GetNextRenderTarget() override {
-    currentRenderTarget = (currentRenderTarget + 1) % renderTargets.Length();
-    textureSet->CurrentIndex = currentRenderTarget;
+    int currentRenderTarget = 0;
+    DebugOnly<ovrResult> orv = ovr_GetTextureSwapChainCurrentIndex(session, textureSet, &currentRenderTarget);
+    MOZ_ASSERT(orv == ovrSuccess, "ovr_GetTextureSwapChainCurrentIndex failed.");
+
     renderTargets[currentRenderTarget]->ClearOnBind();
     RefPtr<layers::CompositingRenderTarget> rt = renderTargets[currentRenderTarget];
     return rt.forget();
   }
 
   void Destroy() {
-    if (!hmd)
-      return;
-    
-    if (hmd->GetOculusSession()) {
-      // If the ovrSession was already destroyed, so were all associated
-      // texture sets
-      ovr_DestroySwapTextureSet(hmd->GetOculusSession(), textureSet);
-    }
+    ovr_DestroyTextureSwapChain(session, textureSet);
     hmd = nullptr;
     textureSet = nullptr;
   }
   
   ~RenderTargetSetOculus() {
     Destroy();
   }
 
   RefPtr<HMDInfoOculus> hmd;
-  ovrSwapTextureSet *textureSet;
+  ovrTextureSwapChain textureSet;
+  ovrSession session;
 };
 
 #ifdef XP_WIN
 class BasicTextureSourceD3D11 : public layers::TextureSourceD3D11
 {
 public:
   BasicTextureSourceD3D11(ID3D11Texture2D *aTexture, const IntSize& aSize) {
     mTexture = aTexture;
     mSize = aSize;
   }
 };
 
 struct RenderTargetSetD3D11 : public RenderTargetSetOculus
 {
-  RenderTargetSetD3D11(layers::CompositorD3D11 *aCompositor,
+  RenderTargetSetD3D11(ovrSession aSession,
+                       layers::CompositorD3D11 *aCompositor,
                        const IntSize& aSize,
                        HMDInfoOculus *aHMD,
-                       ovrSwapTextureSet *aTS)
-    : RenderTargetSetOculus(aSize, aHMD, aTS)
+                       ovrTextureSwapChain aTS)
+    : RenderTargetSetOculus(aSession, aSize, aHMD, aTS)
   {
     compositor = aCompositor;
     
-    renderTargets.SetLength(aTS->TextureCount);
-    
-    currentRenderTarget = aTS->CurrentIndex;
+    int textureCount = 0;
+    DebugOnly<ovrResult> orv = ovr_GetTextureSwapChainLength(session, aTS, &textureCount);
+    MOZ_ASSERT(orv == ovrSuccess, "ovr_GetTextureSwapChainLength failed.");
 
-    for (int i = 0; i < aTS->TextureCount; ++i) {
-      ovrD3D11Texture *tex11;
+    renderTargets.SetLength(textureCount);
+    
+    for (int i = 0; i < textureCount; ++i) {
+      
       RefPtr<layers::CompositingRenderTargetD3D11> rt;
-      
-      tex11 = (ovrD3D11Texture*)&aTS->Textures[i];
-      rt = new layers::CompositingRenderTargetD3D11(tex11->D3D11.pTexture, IntPoint(0, 0), DXGI_FORMAT_B8G8R8A8_UNORM);
+
+      ID3D11Texture2D* texture = nullptr;
+      orv = ovr_GetTextureSwapChainBufferDX(session, aTS, i, IID_PPV_ARGS(&texture));
+      MOZ_ASSERT(orv == ovrSuccess, "ovr_GetTextureSwapChainBufferDX failed.");
+      rt = new layers::CompositingRenderTargetD3D11(texture, IntPoint(0, 0), DXGI_FORMAT_B8G8R8A8_UNORM);
       rt->SetSize(size);
       renderTargets[i] = rt;
+      texture->Release();
     }
   }
 };
 #endif
 
 already_AddRefed<VRHMDRenderingSupport::RenderTargetSet>
 HMDInfoOculus::CreateRenderTargetSet(layers::Compositor *aCompositor, const IntSize& aSize)
 {
 #ifdef XP_WIN
   if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_D3D11)
   {
     layers::CompositorD3D11 *comp11 = static_cast<layers::CompositorD3D11*>(aCompositor);
 
-    CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, aSize.width, aSize.height, 1, 1,
-                               D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
-    ovrSwapTextureSet *ts = nullptr;
+    ovrTextureSwapChainDesc desc;
+    memset(&desc, 0, sizeof(desc));
+    desc.Type = ovrTexture_2D;
+    desc.ArraySize = 1;
+    desc.Format = OVR_FORMAT_B8G8R8A8_UNORM_SRGB;
+    desc.Width = aSize.width;
+    desc.Height = aSize.height;
+    desc.MipLevels = 1;
+    desc.SampleCount = 1;
+    desc.StaticImage = false;
+    desc.MiscFlags = ovrTextureMisc_DX_Typeless;
+    desc.BindFlags = ovrTextureBind_DX_RenderTarget;
+
+    ovrTextureSwapChain ts = nullptr;
     
-    ovrResult orv = ovr_CreateSwapTextureSetD3D11(mSession, comp11->GetDevice(), &desc, ovrSwapTextureSetD3D11_Typeless, &ts);
+    ovrResult orv = ovr_CreateTextureSwapChainDX(mSession, comp11->GetDevice(), &desc, &ts);
     if (orv != ovrSuccess) {
       return nullptr;
     }
 
-    RefPtr<RenderTargetSetD3D11> rts = new RenderTargetSetD3D11(comp11, aSize, this, ts);
+    RefPtr<RenderTargetSetD3D11> rts = new RenderTargetSetD3D11(mSession, comp11, aSize, this, ts);
     return rts.forget();
   }
 #endif
 
   if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_OPENGL) {
   }
 
   return nullptr;
@@ -527,16 +609,20 @@ HMDInfoOculus::SubmitFrame(RenderTargetS
   MOZ_ASSERT(rts->hmd != nullptr);
   MOZ_ASSERT(rts->textureSet != nullptr);
   MOZ_ASSERT(aInputFrameID >= 0);
   if (aInputFrameID < 0) {
     // Sanity check to prevent invalid memory access on builds with assertions
     // disabled.
     aInputFrameID = 0;
   }
+  ovrResult orv = ovr_CommitTextureSwapChain(mSession, rts->textureSet);
+  if (orv != ovrSuccess) {
+    printf_stderr("ovr_CommitTextureSwapChain failed.\n");
+  }
 
   VRHMDSensorState sensorState = mLastSensorState[aInputFrameID % kMaxLatencyFrames];
   // It is possible to get a cache miss on mLastSensorState if latency is
   // longer than kMaxLatencyFrames.  An optimization would be to find a frame
   // that is closer than the one selected with the modulus.
   // If we hit this; however, latency is already so high that the site is
   // un-viewable and a more accurate pose prediction is not likely to
   // compensate.
@@ -575,20 +661,20 @@ HMDInfoOculus::SubmitFrame(RenderTargetS
     layer.RenderPose[i].Orientation.z = o.z;
     layer.RenderPose[i].Orientation.w = o.w;
     layer.RenderPose[i].Position.x = p.x + sensorState.position[0];
     layer.RenderPose[i].Position.y = p.y + sensorState.position[1];
     layer.RenderPose[i].Position.z = p.z + sensorState.position[2];
   }
 
   ovrLayerHeader *layers = &layer.Header;
-  ovrResult orv = ovr_SubmitFrame(mSession, aInputFrameID, nullptr, &layers, 1);
+  orv = ovr_SubmitFrame(mSession, aInputFrameID, nullptr, &layers, 1);
   //printf_stderr("Submitted frame %d, result: %d\n", rts->textureSet->CurrentIndex, orv);
   if (orv != ovrSuccess) {
-    // not visible? failed?
+    printf_stderr("ovr_SubmitFrame failed.\n");
   }
 }
 
 /*static*/ already_AddRefed<VRHMDManagerOculus>
 VRHMDManagerOculus::Create()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/gfx/vr/ovr_capi_dynamic.h
+++ b/gfx/vr/ovr_capi_dynamic.h
@@ -54,16 +54,20 @@
 #define OVR_ALIGNAS(n) __attribute__((aligned(n)))
 #elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
 #define OVR_ALIGNAS(n) __declspec(align(n))
 #else
 #error Need to define OVR_ALIGNAS
 #endif
 #endif
 
+#if !defined(OVR_UNUSED_STRUCT_PAD)
+#define OVR_UNUSED_STRUCT_PAD(padName, size) char padName[size];
+#endif
+
 #ifdef __cplusplus 
 extern "C" {
 #endif
 
 typedef int32_t ovrResult;
 
 typedef enum {
   ovrSuccess = 0,
@@ -88,17 +92,17 @@ typedef struct OVR_ALIGNAS(4) {
 } ovrPosef;
 
 typedef struct OVR_ALIGNAS(8) {
   ovrPosef ThePose;
   ovrVector3f AngularVelocity;
   ovrVector3f LinearVelocity;
   ovrVector3f AngularAcceleration;
   ovrVector3f LinearAcceleration;
-  float       Pad;
+  OVR_UNUSED_STRUCT_PAD(pad0, 4)
   double      TimeInSeconds;
 } ovrPoseStatef;
 
 typedef struct {
   float UpTan;
   float DownTan;
   float LeftTan;
   float RightTan;
@@ -108,360 +112,410 @@ typedef enum {
   ovrHmd_None      = 0,    
   ovrHmd_DK1       = 3,
   ovrHmd_DKHD      = 4,
   ovrHmd_DK2       = 6,
   ovrHmd_CB        = 8,
   ovrHmd_Other     = 9,
   ovrHmd_E3_2015   = 10,
   ovrHmd_ES06      = 11,
+  ovrHmd_ES09      = 12,
+  ovrHmd_ES11      = 13,
+  ovrHmd_CV1       = 14,
   ovrHmd_EnumSize = 0x7fffffff
 } ovrHmdType;
 
 typedef enum {
-  ovrHmdCap_Writable_Mask     = 0x0000,
-  ovrHmdCap_Service_Mask      = 0x0000,
   ovrHmdCap_DebugDevice       = 0x0010,
   ovrHmdCap_EnumSize          = 0x7fffffff
 } ovrHmdCaps;
 
 typedef enum
 {
   ovrTrackingCap_Orientation      = 0x0010,
   ovrTrackingCap_MagYawCorrection = 0x0020,
   ovrTrackingCap_Position         = 0x0040,
-  ovrTrackingCap_Idle             = 0x0100,
   ovrTrackingCap_EnumSize         = 0x7fffffff
 } ovrTrackingCaps;
 
-typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-  char Reserved[8];
-} ovrGraphicsLuid;
-
 typedef enum {
   ovrEye_Left  = 0,
   ovrEye_Right = 1,
   ovrEye_Count = 2,
   ovrEye_EnumSize = 0x7fffffff
 } ovrEyeType;
 
+typedef enum {
+  ovrTrackingOrigin_EyeLevel = 0,
+  ovrTrackingOrigin_FloorLevel = 1,
+  ovrTrackingOrigin_Count = 2,            ///< \internal Count of enumerated elements.
+  ovrTrackingOrigin_EnumSize = 0x7fffffff ///< \internal Force type int32_t.
+} ovrTrackingOrigin;
+
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
+	char Reserved[8];
+} ovrGraphicsLuid;
+
 typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
   ovrHmdType  Type;
-  OVR_ON64(unsigned char pad0[4];)
+  OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad0, 4))
   char ProductName[64];
   char Manufacturer[64];
   short VendorId;
   short ProductId;
   char SerialNumber[24];
   short FirmwareMajor;
   short FirmwareMinor;
-  float CameraFrustumHFovInRadians;
-  float CameraFrustumVFovInRadians;
-  float CameraFrustumNearZInMeters;
-  float CameraFrustumFarZInMeters;
-
   unsigned int AvailableHmdCaps;
   unsigned int DefaultHmdCaps;
   unsigned int AvailableTrackingCaps;
   unsigned int DefaultTrackingCaps;
-
-  ovrFovPort  DefaultEyeFov[ovrEye_Count];
-  ovrFovPort  MaxEyeFov[ovrEye_Count];
-  ovrSizei    Resolution;
+  ovrFovPort DefaultEyeFov[ovrEye_Count];
+  ovrFovPort MaxEyeFov[ovrEye_Count];
+  ovrSizei Resolution;
   float DisplayRefreshRate;
-  OVR_ON64(unsigned char pad1[4];)
+  OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad1, 4))
 } ovrHmdDesc;
 
 typedef struct ovrHmdStruct* ovrSession;
 
 typedef enum {
   ovrStatus_OrientationTracked    = 0x0001,
   ovrStatus_PositionTracked       = 0x0002,
-  ovrStatus_CameraPoseTracked     = 0x0004,
-  ovrStatus_PositionConnected     = 0x0020,
-  ovrStatus_HmdConnected          = 0x0080,
   ovrStatus_EnumSize              = 0x7fffffff
 } ovrStatusBits;
 
-typedef struct OVR_ALIGNAS(4) {
-  ovrVector3f    Accelerometer;
-  ovrVector3f    Gyro;
-  ovrVector3f    Magnetometer;
-  float          Temperature;
-  float          TimeInSeconds;
-} ovrSensorData;
+typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
+  float FrustumHFovInRadians;
+  float FrustumVFovInRadians;
+  float FrustumNearZInMeters;
+  float FrustumFarZInMeters;
+} ovrTrackerDesc;
 
+typedef enum {
+  ovrTracker_Connected = 0x0020,
+  ovrTracker_PoseTracked = 0x0004
+} ovrTrackerFlags;
+
+typedef struct OVR_ALIGNAS(8) {
+  unsigned int TrackerFlags;
+  ovrPosef Pose;
+  ovrPosef LeveledPose;
+  OVR_UNUSED_STRUCT_PAD(pad0, 4)
+} ovrTrackerPose;
 
 typedef struct OVR_ALIGNAS(8) {
   ovrPoseStatef HeadPose;
-  ovrPosef CameraPose;
-  ovrPosef LeveledCameraPose;
+  unsigned int StatusFlags;
   ovrPoseStatef HandPoses[2];
-  ovrSensorData RawSensorData;
-  unsigned int StatusFlags;
   unsigned int HandStatusFlags[2];
-  uint32_t LastCameraFrameCounter;
-  unsigned char pad0[4];
+  ovrPosef CalibratedOrigin;
 } ovrTrackingState;
 
 typedef struct OVR_ALIGNAS(4) {
-	ovrEyeType Eye;
-	ovrFovPort Fov;
-	ovrRecti DistortedViewport;
-	ovrVector2f PixelsPerTanAngleAtCenter;
-	ovrVector3f HmdToEyeViewOffset;
+  ovrEyeType  Eye;
+  ovrFovPort  Fov;
+  ovrRecti    DistortedViewport;
+  ovrVector2f PixelsPerTanAngleAtCenter;
+  ovrVector3f HmdToEyeOffset;
 } ovrEyeRenderDesc;
 
 typedef struct OVR_ALIGNAS(4) {
-	float Projection22;
-	float Projection23;
-	float Projection32;
+  float Projection22;
+  float Projection23;
+  float Projection32;
 } ovrTimewarpProjectionDesc;
 
 typedef struct OVR_ALIGNAS(4) {
-	ovrVector3f HmdToEyeViewOffset[ovrEye_Count];
-	float HmdSpaceToWorldScaleInMeters;
+  ovrVector3f HmdToEyeViewOffset[ovrEye_Count];
+  float HmdSpaceToWorldScaleInMeters;
 } ovrViewScaleDesc;
 
 typedef enum {
-	ovrRenderAPI_None = 0,
-	ovrRenderAPI_OpenGL = 1,
-	ovrRenderAPI_Android_GLES = 2,
-	ovrRenderAPI_D3D11 = 5,
-	ovrRenderAPI_Count = 4,
-	ovrRenderAPI_EnumSize = 0x7fffffff
-} ovrRenderAPIType;
+  ovrTexture_2D,
+  ovrTexture_2D_External,
+  ovrTexture_Cube,
+  ovrTexture_Count,
+  ovrTexture_EnumSize = 0x7fffffff
+} ovrTextureType;
+
+typedef enum {
+  ovrTextureBind_None,
+  ovrTextureBind_DX_RenderTarget = 0x0001,
+  ovrTextureBind_DX_UnorderedAccess = 0x0002,
+  ovrTextureBind_DX_DepthStencil = 0x0004,
+  ovrTextureBind_EnumSize = 0x7fffffff
+} ovrTextureBindFlags;
 
-typedef struct OVR_ALIGNAS(4) {
-  ovrRenderAPIType API;
-  ovrSizei TextureSize;
-} ovrTextureHeader;
+typedef enum {
+  OVR_FORMAT_UNKNOWN,
+  OVR_FORMAT_B5G6R5_UNORM,
+  OVR_FORMAT_B5G5R5A1_UNORM,
+  OVR_FORMAT_B4G4R4A4_UNORM,
+  OVR_FORMAT_R8G8B8A8_UNORM,
+  OVR_FORMAT_R8G8B8A8_UNORM_SRGB,
+  OVR_FORMAT_B8G8R8A8_UNORM,
+  OVR_FORMAT_B8G8R8A8_UNORM_SRGB,
+  OVR_FORMAT_B8G8R8X8_UNORM,
+  OVR_FORMAT_B8G8R8X8_UNORM_SRGB,
+  OVR_FORMAT_R16G16B16A16_FLOAT,
+  OVR_FORMAT_D16_UNORM,
+  OVR_FORMAT_D24_UNORM_S8_UINT,
+  OVR_FORMAT_D32_FLOAT,
+  OVR_FORMAT_D32_FLOAT_S8X24_UINT,
+  OVR_FORMAT_ENUMSIZE = 0x7fffffff
+} ovrTextureFormat;
 
-typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-  ovrTextureHeader Header;
-  OVR_ON64(unsigned char pad0[4];)
-  uintptr_t PlatformData[8];
-} ovrTexture;
+typedef enum {
+  ovrTextureMisc_None,
+  ovrTextureMisc_DX_Typeless = 0x0001,
+  ovrTextureMisc_AllowGenerateMips = 0x0002,
+  ovrTextureMisc_EnumSize = 0x7fffffff
+} ovrTextureFlags;
 
-typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-  ovrTexture* Textures;
-  int TextureCount;
-  int CurrentIndex;
-} ovrSwapTextureSet;
+typedef struct {
+  ovrTextureType Type;
+  ovrTextureFormat Format;
+  int ArraySize;
+  int Width;
+  int Height;
+  int MipLevels;
+  int SampleCount;
+  ovrBool StaticImage;
+  unsigned int MiscFlags;
+  unsigned int BindFlags;
+} ovrTextureSwapChainDesc;
+
+typedef struct
+{
+  ovrTextureFormat Format;
+  int Width;
+  int Height;
+  unsigned int MiscFlags;
+} ovrMirrorTextureDesc;
+
+typedef void* ovrTextureSwapChain;
+typedef struct ovrMirrorTextureData* ovrMirrorTexture;
+
 
 
 typedef enum {
   ovrButton_A = 0x00000001,
   ovrButton_B = 0x00000002,
   ovrButton_RThumb = 0x00000004,
   ovrButton_RShoulder = 0x00000008,
+  ovrButton_RMask = ovrButton_A | ovrButton_B | ovrButton_RThumb | ovrButton_RShoulder,
   ovrButton_X = 0x00000100,
   ovrButton_Y = 0x00000200,
   ovrButton_LThumb = 0x00000400,
   ovrButton_LShoulder = 0x00000800,
+  ovrButton_LMask = ovrButton_X | ovrButton_Y | ovrButton_LThumb | ovrButton_LShoulder,
   ovrButton_Up = 0x00010000,
   ovrButton_Down = 0x00020000,
   ovrButton_Left = 0x00040000,
   ovrButton_Right = 0x00080000,
   ovrButton_Enter = 0x00100000,
   ovrButton_Back = 0x00200000,
-  ovrButton_Private = 0x00400000 | 0x00800000 | 0x01000000,
+  ovrButton_VolUp = 0x00400000,
+  ovrButton_VolDown = 0x00800000,
+  ovrButton_Home = 0x01000000,
+  ovrButton_Private = ovrButton_VolUp | ovrButton_VolDown | ovrButton_Home,
   ovrButton_EnumSize = 0x7fffffff
 } ovrButton;
 
 typedef enum {
   ovrTouch_A = ovrButton_A,
   ovrTouch_B = ovrButton_B,
   ovrTouch_RThumb = ovrButton_RThumb,
   ovrTouch_RIndexTrigger = 0x00000010,
+  ovrTouch_RButtonMask = ovrTouch_A | ovrTouch_B | ovrTouch_RThumb | ovrTouch_RIndexTrigger,
   ovrTouch_X = ovrButton_X,
   ovrTouch_Y = ovrButton_Y,
   ovrTouch_LThumb = ovrButton_LThumb,
   ovrTouch_LIndexTrigger = 0x00001000,
+  ovrTouch_LButtonMask = ovrTouch_X | ovrTouch_Y | ovrTouch_LThumb | ovrTouch_LIndexTrigger,
   ovrTouch_RIndexPointing = 0x00000020,
   ovrTouch_RThumbUp = 0x00000040,
+  ovrTouch_RPoseMask = ovrTouch_RIndexPointing | ovrTouch_RThumbUp,
   ovrTouch_LIndexPointing = 0x00002000,
   ovrTouch_LThumbUp = 0x00004000,
+  ovrTouch_LPoseMask = ovrTouch_LIndexPointing | ovrTouch_LThumbUp,
   ovrTouch_EnumSize = 0x7fffffff
 } ovrTouch;
 
 typedef enum {
   ovrControllerType_None = 0x00,
   ovrControllerType_LTouch = 0x01,
   ovrControllerType_RTouch = 0x02,
   ovrControllerType_Touch = 0x03,
+  ovrControllerType_Remote = 0x04,
   ovrControllerType_XBox = 0x10,
-  ovrControllerType_All = 0xff,
+  ovrControllerType_Active = 0xff,
   ovrControllerType_EnumSize = 0x7fffffff
 } ovrControllerType;
 
 typedef enum {
   ovrHand_Left = 0,
   ovrHand_Right = 1,
+  ovrHand_Count = 2,
   ovrHand_EnumSize = 0x7fffffff
 } ovrHandType;
 
 typedef struct {
-  double              TimeInSeconds;
-  unsigned int        ConnectedControllerTypes;
-  unsigned int        Buttons;
-  unsigned int        Touches;
-  float               IndexTrigger[2];
-  float               HandTrigger[2];
-  ovrVector2f         Thumbstick[2];
+  double TimeInSeconds;
+  unsigned int Buttons;
+  unsigned int Touches;
+  float IndexTrigger[ovrHand_Count];
+  float HandTrigger[ovrHand_Count];
+  ovrVector2f Thumbstick[ovrHand_Count];
+  ovrControllerType ControllerType;
 } ovrInputState;
 
 typedef enum {
   ovrInit_Debug          = 0x00000001,
   ovrInit_RequestVersion = 0x00000004,
   ovrinit_WritableBits   = 0x00ffffff,
   ovrInit_EnumSize       = 0x7fffffff
 } ovrInitFlags;
 
 typedef enum {
   ovrLogLevel_Debug = 0,
   ovrLogLevel_Info  = 1,
   ovrLogLevel_Error = 2,
   ovrLogLevel_EnumSize = 0x7fffffff
 } ovrLogLevel;
 
-typedef void (OVR_PFN *ovrLogCallback)(int level, const char* message);
+typedef void (OVR_PFN* ovrLogCallback)(uintptr_t userData, int level, const char* message);
 
 typedef struct OVR_ALIGNAS(8) {
   uint32_t Flags;
   uint32_t RequestedMinorVersion;
   ovrLogCallback LogCallback;
   uintptr_t UserData;
   uint32_t ConnectionTimeoutMS;
-  OVR_ON64(unsigned char pad0[4];)
+  OVR_ON64(OVR_UNUSED_STRUCT_PAD(pad0, 4))
 } ovrInitParams;
 
-typedef ovrResult(OVR_PFN *pfn_ovr_Initialize)(ovrInitParams const* params);
-typedef void (OVR_PFN *pfn_ovr_Shutdown)();
+typedef ovrResult(OVR_PFN* pfn_ovr_Initialize)(const ovrInitParams* params);
+typedef void (OVR_PFN* pfn_ovr_Shutdown)();
 
 typedef struct {
   ovrResult Result;
   char      ErrorString[512];
 } ovrErrorInfo;
 
-typedef void (OVR_PFN *pfn_ovr_GetLastErrorInfo)(ovrErrorInfo* errorInfo);
-typedef const char* (OVR_PFN *pfn_ovr_GetVersionString)();
-typedef int (OVR_PFN *pfn_ovr_TraceMessage)(int level, const char* message);
-typedef ovrHmdDesc (OVR_PFN *pfn_ovr_GetHmdDesc)(ovrSession session);
-typedef ovrResult (OVR_PFN *pfn_ovr_Create)(ovrSession*, ovrGraphicsLuid*);
-typedef void (OVR_PFN *pfn_ovr_Destroy)(ovrSession session);
+typedef void (OVR_PFN* pfn_ovr_GetLastErrorInfo)(ovrErrorInfo* errorInfo);
+typedef const char* (OVR_PFN* pfn_ovr_GetVersionString)();
+typedef int (OVR_PFN* pfn_ovr_TraceMessage)(int level, const char* message);
+typedef ovrHmdDesc (OVR_PFN* pfn_ovr_GetHmdDesc)(ovrSession session);
+typedef unsigned int (OVR_PFN* pfn_ovr_GetTrackerCount)(ovrSession session);
+typedef ovrTrackerDesc* (OVR_PFN* pfn_ovr_GetTrackerDesc)(ovrSession session, unsigned int trackerDescIndex);
+typedef ovrResult (OVR_PFN* pfn_ovr_Create)(ovrSession* pSession, ovrGraphicsLuid* pLuid);
+typedef void (OVR_PFN* pfn_ovr_Destroy)(ovrSession session);
 
 typedef struct {
-  ovrBool HasVrFocus;
+  ovrBool IsVisible;
   ovrBool HmdPresent;
+  ovrBool HmdMounted;
+  ovrBool DisplayLost;
+  ovrBool ShouldQuit;
+  ovrBool ShouldRecenter;
 } ovrSessionStatus;
 
-typedef ovrResult (OVR_PFN *pfn_ovr_GetSessionStatus)(ovrSession session, ovrSessionStatus* sessionStatus);
-typedef unsigned int (OVR_PFN *pfn_ovr_GetEnabledCaps)(ovrSession session);
-typedef void (OVR_PFN *pfn_ovr_SetEnabledCaps)(ovrSession session, unsigned int hmdCaps);
-typedef unsigned int (OVR_PFN *pfn_ovr_GetTrackingCaps)(ovrSession session);
-typedef ovrResult(OVR_PFN *pfn_ovr_ConfigureTracking)(ovrSession session, unsigned int requestedTrackingCaps, unsigned int requiredTrackingCaps);
-typedef void (OVR_PFN *pfn_ovr_RecenterPose)(ovrSession session);
-typedef ovrTrackingState (OVR_PFN *pfn_ovr_GetTrackingState)(ovrSession session, double absTime, ovrBool latencyMarker);
-typedef ovrResult (OVR_PFN *pfn_ovr_GetInputState)(ovrSession session, unsigned int controllerTypeMask, ovrInputState* inputState);
-typedef ovrResult (OVR_PFN *pfn_ovr_SetControllerVibration)(ovrSession session, unsigned int controllerTypeMask, float frequency, float amplitude);
+typedef ovrResult (OVR_PFN* pfn_ovr_GetSessionStatus)(ovrSession session, ovrSessionStatus* sessionStatus);
+
+typedef ovrResult (OVR_PFN* pfn_ovr_SetTrackingOriginType)(ovrSession session, ovrTrackingOrigin origin);
+typedef ovrTrackingOrigin (OVR_PFN* pfn_ovr_GetTrackingOriginType)(ovrSession session);
+typedef ovrResult (OVR_PFN* pfn_ovr_RecenterTrackingOrigin)(ovrSession session);
+typedef void (OVR_PFN* pfn_ovr_ClearShouldRecenterFlag)(ovrSession session);
+typedef ovrTrackingState (OVR_PFN* pfn_ovr_GetTrackingState)(ovrSession session, double absTime, ovrBool latencyMarker);
+typedef ovrTrackerPose (OVR_PFN* pfn_ovr_GetTrackerPose)(ovrSession session, unsigned int trackerPoseIndex);
+typedef ovrResult (OVR_PFN* pfn_ovr_GetInputState)(ovrSession session, ovrControllerType controllerType, ovrInputState* inputState);
+typedef unsigned int (OVR_PFN* pfn_ovr_GetConnectedControllerTypes)(ovrSession session);
+typedef ovrResult (OVR_PFN* pfn_ovr_SetControllerVibration)(ovrSession session, ovrControllerType controllerType, float frequency, float amplitude);
 
 enum {
-  ovrMaxLayerCount = 32
+  ovrMaxLayerCount = 16
 };
 
 typedef enum {
   ovrLayerType_Disabled       = 0,
   ovrLayerType_EyeFov         = 1,
-  ovrLayerType_EyeFovDepth    = 2,
   ovrLayerType_Quad           = 3,
   ovrLayerType_EyeMatrix      = 5,
-  ovrLayerType_Direct         = 6,
   ovrLayerType_EnumSize       = 0x7fffffff
 } ovrLayerType;
 
 typedef enum {
   ovrLayerFlag_HighQuality               = 0x01,
   ovrLayerFlag_TextureOriginAtBottomLeft = 0x02,
   ovrLayerFlag_HeadLocked                = 0x04
 } ovrLayerFlags;
 
 typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-    ovrLayerType    Type;
-    unsigned        Flags;
+  ovrLayerType Type;
+  unsigned Flags;
 } ovrLayerHeader;
 
 typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-    ovrLayerHeader      Header;
-    ovrSwapTextureSet*  ColorTexture[ovrEye_Count];
-    ovrRecti            Viewport[ovrEye_Count];
-    ovrFovPort          Fov[ovrEye_Count];
-    ovrPosef            RenderPose[ovrEye_Count];
-    double              SensorSampleTime;
+  ovrLayerHeader Header;
+  ovrTextureSwapChain ColorTexture[ovrEye_Count];
+  ovrRecti Viewport[ovrEye_Count];
+  ovrFovPort Fov[ovrEye_Count];
+  ovrPosef RenderPose[ovrEye_Count];
+  double SensorSampleTime;
 } ovrLayerEyeFov;
 
 typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-  ovrLayerHeader      Header;
-  ovrSwapTextureSet*  ColorTexture[ovrEye_Count];
-  ovrRecti            Viewport[ovrEye_Count];
-  ovrFovPort          Fov[ovrEye_Count];
-  ovrPosef            RenderPose[ovrEye_Count];
-  double              SensorSampleTime;
-  ovrSwapTextureSet*  DepthTexture[ovrEye_Count];
-  ovrTimewarpProjectionDesc ProjectionDesc;
-} ovrLayerEyeFovDepth;
-
-typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-  ovrLayerHeader      Header;
-  ovrSwapTextureSet*  ColorTexture[ovrEye_Count];
-  ovrRecti            Viewport[ovrEye_Count];
-  ovrPosef            RenderPose[ovrEye_Count];
-  ovrMatrix4f         Matrix[ovrEye_Count];
-  double              SensorSampleTime;
+  ovrLayerHeader Header;
+  ovrTextureSwapChain ColorTexture[ovrEye_Count];
+  ovrRecti Viewport[ovrEye_Count];
+  ovrPosef RenderPose[ovrEye_Count];
+  ovrMatrix4f Matrix[ovrEye_Count];
+  double SensorSampleTime;
 } ovrLayerEyeMatrix;
 
 typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-  ovrLayerHeader      Header;
-  ovrSwapTextureSet*  ColorTexture;
-  ovrRecti            Viewport;
-  ovrPosef            QuadPoseCenter;
-  ovrVector2f         QuadSize;
+  ovrLayerHeader Header;
+  ovrTextureSwapChain ColorTexture;
+  ovrRecti Viewport;
+  ovrPosef QuadPoseCenter;
+  ovrVector2f QuadSize;
 } ovrLayerQuad;
 
-typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-  ovrLayerHeader      Header;
-  ovrSwapTextureSet*  ColorTexture[ovrEye_Count];
-  ovrRecti            Viewport[ovrEye_Count];
-} ovrLayerDirect;
-
 typedef union {
-  ovrLayerHeader      Header;
-  ovrLayerEyeFov      EyeFov;
-  ovrLayerEyeFovDepth EyeFovDepth;
-  ovrLayerQuad        Quad;
-  ovrLayerDirect      Direct;
+  ovrLayerHeader Header;
+  ovrLayerEyeFov EyeFov;
+  ovrLayerQuad Quad;
 } ovrLayer_Union;
 
-typedef void (OVR_PFN *pfn_ovr_DestroySwapTextureSet)(ovrSession session, ovrSwapTextureSet* textureSet);
-typedef void (OVR_PFN *pfn_ovr_DestroyMirrorTexture)(ovrSession session, ovrTexture* mirrorTexture);
-typedef ovrSizei (OVR_PFN *pfn_ovr_GetFovTextureSize)(ovrSession session, ovrEyeType eye, ovrFovPort fov, float pixelsPerDisplayPixel);
-typedef ovrEyeRenderDesc (OVR_PFN *pfn_ovr_GetRenderDesc)(ovrSession session, ovrEyeType eyeType, ovrFovPort fov);
-typedef ovrResult (OVR_PFN *pfn_ovr_SubmitFrame)(ovrSession session, unsigned int frameIndex,
-  const ovrViewScaleDesc* viewScaleDesc,
-  ovrLayerHeader const * const * layerPtrList, unsigned int layerCount);
-typedef double (OVR_PFN *pfn_ovr_GetPredictedDisplayTime)(ovrSession session, long long frameIndex);
-typedef double (OVR_PFN *pfn_ovr_GetTimeInSeconds)();
+
+typedef ovrResult (OVR_PFN* pfn_ovr_GetTextureSwapChainLength)(ovrSession session, ovrTextureSwapChain chain, int* out_Length);
+typedef ovrResult (OVR_PFN* pfn_ovr_GetTextureSwapChainCurrentIndex)(ovrSession session, ovrTextureSwapChain chain, int* out_Index);
+typedef ovrResult (OVR_PFN* pfn_ovr_GetTextureSwapChainDesc)(ovrSession session, ovrTextureSwapChain chain, ovrTextureSwapChainDesc* out_Desc);
+typedef ovrResult (OVR_PFN* pfn_ovr_CommitTextureSwapChain)(ovrSession session, ovrTextureSwapChain chain);
+typedef void (OVR_PFN* pfn_ovr_DestroyTextureSwapChain)(ovrSession session, ovrTextureSwapChain chain);
+typedef void (OVR_PFN* pfn_ovr_DestroyMirrorTexture)(ovrSession session, ovrMirrorTexture mirrorTexture);
+typedef ovrSizei(OVR_PFN* pfn_ovr_GetFovTextureSize)(ovrSession session, ovrEyeType eye, ovrFovPort fov, float pixelsPerDisplayPixel);
+typedef ovrEyeRenderDesc(OVR_PFN* pfn_ovr_GetRenderDesc)(ovrSession session, ovrEyeType eyeType, ovrFovPort fov);
+typedef ovrResult(OVR_PFN* pfn_ovr_SubmitFrame)(ovrSession session, unsigned int frameIndex,
+	const ovrViewScaleDesc* viewScaleDesc,
+	ovrLayerHeader const * const * layerPtrList, unsigned int layerCount);
+typedef double (OVR_PFN* pfn_ovr_GetPredictedDisplayTime)(ovrSession session, long long frameIndex);
+typedef double (OVR_PFN* pfn_ovr_GetTimeInSeconds)();
+
 
 typedef enum {
   ovrPerfHud_Off = 0,
-  ovrPerfHud_LatencyTiming = 1,
-  ovrPerfHud_RenderTiming = 2,
-  ovrPerfHud_PerfHeadroom = 3,
-  ovrPerfHud_VersionInfo = 4,
-  ovrPerfHud_Count,
+  ovrPerfHud_PerfSummary = 1,
+  ovrPerfHud_LatencyTiming = 2,
+  ovrPerfHud_AppRenderTiming = 3,
+  ovrPerfHud_CompRenderTiming = 4,
+  ovrPerfHud_VersionInfo = 5,
+  ovrPerfHud_Count = 6,
   ovrPerfHud_EnumSize = 0x7fffffff
 } ovrPerfHudMode;
 
 typedef enum {
   ovrLayerHud_Off = 0,
   ovrLayerHud_Info = 1,
   ovrLayerHud_EnumSize = 0x7fffffff
 } ovrLayerHudMode;
@@ -470,44 +524,47 @@ typedef enum {
   ovrDebugHudStereo_Off = 0,
   ovrDebugHudStereo_Quad = 1,
   ovrDebugHudStereo_QuadWithCrosshair = 2,
   ovrDebugHudStereo_CrosshairAtInfinity = 3,
   ovrDebugHudStereo_Count,
   ovrDebugHudStereo_EnumSize = 0x7fffffff
 } ovrDebugHudStereoMode;
 
-typedef void (OVR_PFN *pfn_ovr_ResetBackOfHeadTracking)(ovrSession session);
-typedef void (OVR_PFN *pfn_ovr_ResetMulticameraTracking)(ovrSession session);
-typedef ovrBool (OVR_PFN *pfn_ovr_GetBool)(ovrSession session, const char* propertyName, ovrBool defaultVal);
-typedef ovrBool (OVR_PFN *pfn_ovr_SetBool)(ovrSession session, const char* propertyName, ovrBool value);
-typedef int (OVR_PFN *pfn_ovr_GetInt)(ovrSession session, const char* propertyName, int defaultVal);
-typedef ovrBool (OVR_PFN *pfn_ovr_SetInt)(ovrSession session, const char* propertyName, int value);
-typedef float (OVR_PFN *pfn_ovr_GetFloat)(ovrSession session, const char* propertyName, float defaultVal);
-typedef ovrBool (OVR_PFN *pfn_ovr_SetFloat)(ovrSession session, const char* propertyName, float value);
-typedef unsigned int (OVR_PFN *pfn_ovr_GetFloatArray)(ovrSession session, const char* propertyName,
+typedef ovrBool(OVR_PFN* pfn_ovr_GetBool)(ovrSession session, const char* propertyName, ovrBool defaultVal);
+typedef ovrBool(OVR_PFN* pfn_ovr_SetBool)(ovrSession session, const char* propertyName, ovrBool value); 
+typedef int (OVR_PFN* pfn_ovr_GetInt)(ovrSession session, const char* propertyName, int defaultVal);
+typedef ovrBool (OVR_PFN* pfn_ovr_SetInt)(ovrSession session, const char* propertyName, int value);
+typedef float (OVR_PFN* pfn_ovr_GetFloat)(ovrSession session, const char* propertyName, float defaultVal);
+typedef ovrBool (OVR_PFN* pfn_ovr_SetFloat)(ovrSession session, const char* propertyName, float value);
+typedef unsigned int (OVR_PFN* pfn_ovr_GetFloatArray)(ovrSession session, const char* propertyName,
   float values[], unsigned int valuesCapacity);
-typedef ovrBool (OVR_PFN *pfn_ovr_SetFloatArray)(ovrSession session, const char* propertyName,
+typedef ovrBool (OVR_PFN* pfn_ovr_SetFloatArray)(ovrSession session, const char* propertyName,
   const float values[], unsigned int valuesSize);
-typedef const char* (OVR_PFN *pfn_ovr_GetString)(ovrSession session, const char* propertyName,
+typedef const char* (OVR_PFN* pfn_ovr_GetString)(ovrSession session, const char* propertyName,
   const char* defaultVal);
-typedef ovrBool (OVR_PFN *pfn_ovr_SetString)(ovrSession session, const char* propertyName,
+typedef ovrBool (OVR_PFN* pfn_ovr_SetString)(ovrSession session, const char* propertyName,
   const char* value);
 
 
 
 typedef enum {
   ovrError_MemoryAllocationFailure = -1000,
   ovrError_SocketCreationFailure = -1001,
   ovrError_InvalidSession = -1002,
   ovrError_Timeout = -1003,
   ovrError_NotInitialized = -1004,
   ovrError_InvalidParameter = -1005,
   ovrError_ServiceError = -1006,
   ovrError_NoHmd = -1007,
+  ovrError_Unsupported = -1009,
+  ovrError_DeviceUnavailable = -1010,
+  ovrError_InvalidHeadsetOrientation = -1011,
+  ovrError_ClientSkippedDestroy = -1012,
+  ovrError_ClientSkippedShutdown = -1013,
   ovrError_AudioReservedBegin = -2000,
   ovrError_AudioDeviceNotFound = -2001,
   ovrError_AudioComError = -2002,
   ovrError_AudioReservedEnd = -2999,
   ovrError_Initialize = -3000,
   ovrError_LibLoad = -3001,
   ovrError_LibVersion = -3002,
   ovrError_ServiceConnection = -3003,
@@ -518,92 +575,110 @@ typedef enum {
   ovrError_Reinitialization = -3008,
   ovrError_MismatchedAdapters = -3009,
   ovrError_LeakingResources = -3010,
   ovrError_ClientVersion = -3011,
   ovrError_OutOfDateOS = -3012,
   ovrError_OutOfDateGfxDriver = -3013,
   ovrError_IncompatibleGPU = -3014,
   ovrError_NoValidVRDisplaySystem = -3015,
+  ovrError_Obsolete = -3016,
+  ovrError_DisabledOrDefaultAdapter = -3017,
+  ovrError_HybridGraphicsNotSupported = -3018,
+  ovrError_DisplayManagerInit = -3019,
+  ovrError_TrackerDriverInit = -3020,
   ovrError_InvalidBundleAdjustment = -4000,
   ovrError_USBBandwidth = -4001,
   ovrError_USBEnumeratedSpeed = -4002,
   ovrError_ImageSensorCommError = -4003,
   ovrError_GeneralTrackerFailure = -4004,
   ovrError_ExcessiveFrameTruncation = -4005,
   ovrError_ExcessiveFrameSkipping = -4006,
   ovrError_SyncDisconnected = -4007,
   ovrError_TrackerMemoryReadFailure = -4008,
   ovrError_TrackerMemoryWriteFailure = -4009,
   ovrError_TrackerFrameTimeout = -4010,
   ovrError_TrackerTruncatedFrame = -4011,
+  ovrError_TrackerDriverFailure = -4012,
+  ovrError_TrackerNRFFailure = -4013,
+  ovrError_HardwareGone = -4014,
+  ovrError_NordicEnabledNoSync = -4015,
+  ovrError_NordicSyncNoFrames = -4016,
+  ovrError_CatastrophicFailure = -4017,
   ovrError_HMDFirmwareMismatch = -4100,
   ovrError_TrackerFirmwareMismatch = -4101,
   ovrError_BootloaderDeviceDetected = -4102,
   ovrError_TrackerCalibrationError = -4103,
   ovrError_ControllerFirmwareMismatch = -4104,
+  ovrError_IMUTooManyLostSamples = -4200,
+  ovrError_IMURateError = -4201,
+  ovrError_FeatureReportFailure = -4202,
   ovrError_Incomplete = -5000,
   ovrError_Abandoned = -5001,
   ovrError_DisplayLost = -6000,
+  ovrError_TextureSwapChainFull = -6001,
+  ovrError_TextureSwapChainInvalid = -6002,
   ovrError_RuntimeException = -7000,
+  ovrError_MetricsUnknownApp = -90000,
+  ovrError_MetricsDuplicateApp = -90001,
+  ovrError_MetricsNoEvents = -90002,
+  ovrError_MetricsRuntime = -90003,
+  ovrError_MetricsFile = -90004,
+  ovrError_MetricsNoClientInfo = -90005,
+  ovrError_MetricsNoAppMetaData = -90006,
+  ovrError_MetricsNoApp = -90007,
+  ovrError_MetricsOafFailure = -90008,
+  ovrError_MetricsSessionAlreadyActive = -90009,
+  ovrError_MetricsSessionNotActive = -90010,
 } ovrErrorType;
 
 
 #ifdef XP_WIN
-struct D3D11_TEXTURE2D_DESC;
-struct ID3D11Device;
-struct ID3D11Texture2D;
-struct ID3D11ShaderResourceView;
+
+struct IUnknown;
 
-typedef struct OVR_ALIGNAS(OVR_PTR_SIZE) {
-    ovrTextureHeader          Header;
-    OVR_ON64(uint32_t pad0;)
-    ID3D11Texture2D*          pTexture;
-    ID3D11ShaderResourceView* pSRView;
-} ovrD3D11TextureData;
+typedef ovrResult (OVR_PFN* pfn_ovr_CreateTextureSwapChainDX)(ovrSession session,
+	IUnknown* d3dPtr,
+	const ovrTextureSwapChainDesc* desc,
+	ovrTextureSwapChain* out_TextureSwapChain);
 
-typedef union {
-    ovrTexture          Texture;
-    ovrD3D11TextureData D3D11;
-} ovrD3D11Texture;
-
-typedef enum {
-    ovrSwapTextureSetD3D11_Typeless = 0x0001,
-    ovrSwapTextureSetD3D11_EnumSize = 0x7fffffff
-} ovrSwapTextureSetD3D11Flags;
+typedef ovrResult (OVR_PFN* pfn_ovr_GetTextureSwapChainBufferDX)(ovrSession session,
+	ovrTextureSwapChain chain,
+	int index,
+	IID iid,
+	void** out_Buffer);
 
-typedef ovrResult (OVR_PFN *pfn_ovr_CreateSwapTextureSetD3D11)(ovrSession session, ID3D11Device* device,
-                                                               const D3D11_TEXTURE2D_DESC* desc,
-                                                               unsigned int miscFlags,
-                                                               ovrSwapTextureSet** outTextureSet);
+typedef ovrResult (OVR_PFN* pfn_ovr_CreateMirrorTextureDX)(ovrSession session,
+	IUnknown* d3dPtr,
+	const ovrMirrorTextureDesc* desc,
+	ovrMirrorTexture* out_MirrorTexture);
 
-typedef ovrResult (OVR_PFN *pfn_ovr_CreateMirrorTextureD3D11)(ovrSession session,
-                                                              ID3D11Device* device,
-                                                              const D3D11_TEXTURE2D_DESC* desc,
-                                                              unsigned int miscFlags,
-                                                              ovrTexture** outMirrorTexture);
+typedef ovrResult (OVR_PFN* pfn_ovr_GetMirrorTextureBufferDX)(ovrSession session,
+	ovrMirrorTexture mirrorTexture,
+	IID iid,
+	void** out_Buffer);
 
 #endif
 
-typedef struct {
-    ovrTextureHeader Header;
-    uint32_t TexId;
-} ovrGLTextureData;
+
+typedef ovrResult (OVR_PFN* pfn_ovr_CreateTextureSwapChainGL)(ovrSession session,
+	const ovrTextureSwapChainDesc* desc,
+	ovrTextureSwapChain* out_TextureSwapChain);
 
-typedef union {
-    ovrTexture       Texture;
-    ovrGLTextureData OGL;
-} ovrGLTexture;
+typedef ovrResult (OVR_PFN* pfn_ovr_GetTextureSwapChainBufferGL)(ovrSession session,
+	ovrTextureSwapChain chain,
+	int index,
+	unsigned int* out_TexId);
 
-typedef ovrResult (OVR_PFN *pfn_ovr_CreateSwapTextureSetGL)(ovrSession session, uint32_t format,
-                                                            int width, int height,
-                                                            ovrSwapTextureSet** outTextureSet);
+typedef ovrResult (OVR_PFN* pfn_ovr_CreateMirrorTextureGL)(ovrSession session,
+	const ovrMirrorTextureDesc* desc,
+	ovrMirrorTexture* out_MirrorTexture);
 
-typedef ovrResult (OVR_PFN *pfn_ovr_CreateMirrorTextureGL)(ovrSession session, uint32_t format,
-                                                         int width, int height,
-                                                         ovrTexture** outMirrorTexture);
+typedef ovrResult (OVR_PFN* pfn_ovr_GetMirrorTextureBufferGL)(ovrSession session,
+	ovrMirrorTexture mirrorTexture,
+	unsigned int* out_TexId);
 
 #ifdef __cplusplus 
 }
 #endif
 
 #endif /* mozilla_ovr_capi_dynamic_h_ */
 #endif /* OVR_CAPI_h */
--- a/intl/locale/nsLanguageAtomService.cpp
+++ b/intl/locale/nsLanguageAtomService.cpp
@@ -10,17 +10,17 @@
 #include "nsIAtom.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Services.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/dom/EncodingUtils.h"
 
 using namespace mozilla;
 
-static const char* const kLangGroups[][3] = {
+static const nsUConvProp kLangGroups[] = {
 #include "langGroups.properties.h"
 };
 
 NS_IMPL_ISUPPORTS(nsLanguageAtomService, nsILanguageAtomService)
 
 nsLanguageAtomService::nsLanguageAtomService()
 {
 }
--- a/intl/locale/nsLanguageAtomService.h
+++ b/intl/locale/nsLanguageAtomService.h
@@ -3,16 +3,17 @@
  * 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 "nsCOMPtr.h"
 #include "nsILanguageAtomService.h"
 #include "nsIStringBundle.h"
 #include "nsInterfaceHashtable.h"
 #include "nsIAtom.h"
+#include "nsUConvPropertySearch.h"
 #include "mozilla/Attributes.h"
 
 #define NS_LANGUAGEATOMSERVICE_CID \
   {0xB7C65853, 0x2996, 0x435E, {0x96, 0x54, 0xDC, 0xC1, 0x78, 0xAA, 0xB4, 0x8C}}
 
 class nsLanguageAtomService final : public nsILanguageAtomService
 {
 public:
--- a/intl/locale/nsUConvPropertySearch.cpp
+++ b/intl/locale/nsUConvPropertySearch.cpp
@@ -8,37 +8,37 @@
 #include "mozilla/BinarySearch.h"
 
 namespace {
 
 struct PropertyComparator
 {
   const nsCString& mKey;
   explicit PropertyComparator(const nsCString& aKey) : mKey(aKey) {}
-  int operator()(const char* const (&aProperty)[3]) const {
-    return mKey.Compare(aProperty[0]);
+  int operator()(const nsUConvProp& aProperty) const {
+    return mKey.Compare(aProperty.mKey);
   }
 };
 
 } // namespace
 
 // static
 nsresult
-nsUConvPropertySearch::SearchPropertyValue(const char* const aProperties[][3],
+nsUConvPropertySearch::SearchPropertyValue(const nsUConvProp aProperties[],
                                            int32_t aNumberOfProperties,
                                            const nsACString& aKey,
                                            nsACString& aValue)
 {
   using mozilla::BinarySearchIf;
 
   const nsCString& flat = PromiseFlatCString(aKey);
   size_t index;
   if (BinarySearchIf(aProperties, 0, aNumberOfProperties,
                      PropertyComparator(flat), &index)) {
-    nsDependentCString val(aProperties[index][1],
-                           NS_PTR_TO_UINT32(aProperties[index][2]));
+    nsDependentCString val(aProperties[index].mValue,
+                           aProperties[index].mValueLength);
     aValue.Assign(val);
     return NS_OK;
   }
 
   aValue.Truncate();
   return NS_ERROR_FAILURE;
 }
--- a/intl/locale/nsUConvPropertySearch.h
+++ b/intl/locale/nsUConvPropertySearch.h
@@ -2,29 +2,36 @@
  * 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 nsUConvPropertySearch_h_
 #define nsUConvPropertySearch_h_
 
 #include "nsStringFwd.h"
 
+struct nsUConvProp
+{
+    const char* const mKey;
+    const char* const mValue;
+    const uint32_t mValueLength;
+};
+
 class nsUConvPropertySearch
 {
   public:
     /**
      * Looks up a property by value.
      *
      * @param aProperties
      *   the static property array
      * @param aKey
      *   the key to look up
      * @param aValue
      *   the return value (empty string if not found)
      * @return NS_OK if found or NS_ERROR_FAILURE if not found
      */
-    static nsresult SearchPropertyValue(const char* const aProperties[][3],
+    static nsresult SearchPropertyValue(const nsUConvProp aProperties[],
                                         int32_t aNumberOfProperties,
                                         const nsACString& aKey,
                                         nsACString& aValue);
 };
 
 #endif /* nsUConvPropertySearch_h_ */
--- a/intl/locale/props2arrays.py
+++ b/intl/locale/props2arrays.py
@@ -16,12 +16,12 @@ def main(header, propFile):
           mappings[parts[0].strip()] = parts[1].strip()
  
   keys = mappings.keys()
   keys.sort()
 
   header.write("// This is a generated file. Please do not edit.\n")
   header.write("// Please edit the corresponding .properties file instead.\n")
 
-  entries = ['{ "%s", "%s", (const char*)NS_INT32_TO_PTR(%d) }'
+  entries = ['{ "%s", "%s", %d }'
              % (key, mappings[key], len(mappings[key])) for key in keys]
   header.write(',\n'.join(entries) + '\n')
 
--- a/intl/locale/unix/nsUNIXCharset.cpp
+++ b/intl/locale/unix/nsUNIXCharset.cpp
@@ -24,36 +24,33 @@
 #include "nsPlatformCharset.h"
 #include "prinit.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/dom/EncodingUtils.h"
 
 using mozilla::dom::EncodingUtils;
 using namespace mozilla;
 
-static const char* const kUnixCharsets[][3] = {
+static const nsUConvProp kUnixCharsets[] = {
 #include "unixcharset.properties.h"
 };
 
 NS_IMPL_ISUPPORTS(nsPlatformCharset, nsIPlatformCharset)
 
 nsPlatformCharset::nsPlatformCharset()
 {
 }
 
 static nsresult
 ConvertLocaleToCharsetUsingDeprecatedConfig(const nsACString& locale,
                                             nsACString& oResult)
 {
   if (!(locale.IsEmpty())) {
-    nsAutoCString localeKey;
-    localeKey.AssignLiteral("locale.all.");
-    localeKey.Append(locale);
     if (NS_SUCCEEDED(nsUConvPropertySearch::SearchPropertyValue(kUnixCharsets,
-        ArrayLength(kUnixCharsets), localeKey, oResult))) {
+        ArrayLength(kUnixCharsets), locale, oResult))) {
       return NS_OK;
     }
   }
   NS_ERROR("unable to convert locale to charset using deprecated config");
   oResult.AssignLiteral("ISO-8859-1");
   return NS_SUCCESS_USING_FALLBACK_LOCALE;
 }
 
--- a/intl/locale/unix/unixcharset.properties
+++ b/intl/locale/unix/unixcharset.properties
@@ -8,529 +8,529 @@
 ##       nl_langinfo(CODESET) this file should not be used
 ##
 ## All platform section
 ##   Put the general locale to charset mapping here.
 ##   If somehow two platform use the same locale name with different
 ##   charset, put the least common one in the platform specific section
 ##   This section have lower priority than the platform specific section
 ##
-## The key is "locale.all." + locale name
+## The key is the locale name
 # AIX
-locale.all.ar_AA=ISO-8859-6
+ar_AA=ISO-8859-6
 # Solaris
-locale.all.Ar_ARM=ISO-8859-6
-locale.all.american.iso88591=ISO-8859-1
-locale.all.bulgarian=ISO-8859-2
-locale.all.bg_BG.ISO8859-5=ISO-8859-5
+Ar_ARM=ISO-8859-6
+american.iso88591=ISO-8859-1
+bulgarian=ISO-8859-2
+bg_BG.ISO8859-5=ISO-8859-5
 # AIX
-locale.all.bg_BG=ISO-8859-5
-locale.all.C=ISO-8859-1
+bg_BG=ISO-8859-5
+C=ISO-8859-1
 # HP
-locale.all.C.iso885915=ISO-8859-15
-locale.all.c-french.iso88591=ISO-8859-1
-locale.all.chinese=gb18030
-locale.all.chinese-s=gb18030
-locale.all.chinese-t.big5=Big5
-locale.all.cs=ISO-8859-2
-locale.all.cs_CZ=ISO-8859-2
-locale.all.cs_CZ.ISO8859-2=ISO-8859-2
-locale.all.cs_CZ.88592=ISO-8859-2
-locale.all.czech=ISO-8859-2
-locale.all.da=ISO-8859-1
+C.iso885915=ISO-8859-15
+c-french.iso88591=ISO-8859-1
+chinese=gb18030
+chinese-s=gb18030
+chinese-t.big5=Big5
+cs=ISO-8859-2
+cs_CZ=ISO-8859-2
+cs_CZ.ISO8859-2=ISO-8859-2
+cs_CZ.88592=ISO-8859-2
+czech=ISO-8859-2
+da=ISO-8859-1
 # Solaris
-locale.all.da.ISO8859-15=ISO-8859-15
-locale.all.da_DK.ISO8859-15=ISO-8859-15
-locale.all.da_DK.ISO8859-15@euro=ISO-8859-15
+da.ISO8859-15=ISO-8859-15
+da_DK.ISO8859-15=ISO-8859-15
+da_DK.ISO8859-15@euro=ISO-8859-15
 # Solaris
-locale.all.da.ISO8859-15@euro=ISO-8859-15
-locale.all.da_DK.88591=ISO-8859-1
+da.ISO8859-15@euro=ISO-8859-15
+da_DK.88591=ISO-8859-1
 # HP
-locale.all.da_DK.iso885915@euro=ISO-8859-15
-locale.all.da_DK.ISO8859-1=ISO-8859-1
-locale.all.da_DK=ISO-8859-1
+da_DK.iso885915@euro=ISO-8859-15
+da_DK.ISO8859-1=ISO-8859-1
+da_DK=ISO-8859-1
 # AIX
-#locale.all.Da_DK=IBM-850
-locale.all.danish.iso88591=ISO-8859-1
-locale.all.dutch.iso88591=ISO-8859-1
-locale.all.de=ISO-8859-1
+#Da_DK=IBM-850
+danish.iso88591=ISO-8859-1
+dutch.iso88591=ISO-8859-1
+de=ISO-8859-1
 # Solaris
-locale.all.de.ISO8859-15=ISO-8859-15
+de.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.de.ISO8859-15@euro=ISO-8859-15
+de.ISO8859-15@euro=ISO-8859-15
 # Solaris
-locale.all.de.UTF-8=UTF-8
+de.UTF-8=UTF-8
 # Solaris
-locale.all.de.UTF-8@euro=UTF-8
-locale.all.de_AT=ISO-8859-1
+de.UTF-8@euro=UTF-8
+de_AT=ISO-8859-1
 # Solaris
-locale.all.de_AT.ISO8859-15=ISO-8859-15
+de_AT.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.de_AT.ISO8859-15@euro=ISO-8859-15
-locale.all.de_CH=ISO-8859-1
-locale.all.de_CH.88591=ISO-8859-1
-locale.all.de_CH.ISO8859-1=ISO-8859-1
-locale.all.de_DE.ISO8859-15=ISO-8859-15
-locale.all.de_DE.ISO8859-15@euro=ISO-8859-15
+de_AT.ISO8859-15@euro=ISO-8859-15
+de_CH=ISO-8859-1
+de_CH.88591=ISO-8859-1
+de_CH.ISO8859-1=ISO-8859-1
+de_DE.ISO8859-15=ISO-8859-15
+de_DE.ISO8859-15@euro=ISO-8859-15
 # AIX
-#locale.all.De_CH=IBM-850
-locale.all.de_DE=ISO-8859-1
-locale.all.de_DE.88591=ISO-8859-1
+#De_CH=IBM-850
+de_DE=ISO-8859-1
+de_DE.88591=ISO-8859-1
 # HP
-locale.all.de_DE.iso885915=ISO-8859-15
+de_DE.iso885915=ISO-8859-15
 # HP
-locale.all.de_DE.iso885915@euro=ISO-8859-15
-locale.all.de_DE.ISO8859-1=ISO-8859-1
+de_DE.iso885915@euro=ISO-8859-15
+de_DE.ISO8859-1=ISO-8859-1
 # AIX
-#locale.all.De_DE=IBM-850
+#De_DE=IBM-850
 # Solaris
-locale.all.el_GR.ISO8859-7=ISO-8859-7
-locale.all.el_GR.ISO8859-7@euro=ISO-8859-7
-locale.all.en_AU.ISO8859-1=ISO-8859-1
-locale.all.en_CA.ISO8859-1=ISO-8859-1
+el_GR.ISO8859-7=ISO-8859-7
+el_GR.ISO8859-7@euro=ISO-8859-7
+en_AU.ISO8859-1=ISO-8859-1
+en_CA.ISO8859-1=ISO-8859-1
 # AIX
-locale.all.el_GR=ISO-8859-7
-locale.all.en=ISO-8859-1
-locale.all.en_AU=ISO-8859-1
-locale.all.en_CA=ISO-8859-1
-locale.all.en_GB=ISO-8859-1
+el_GR=ISO-8859-7
+en=ISO-8859-1
+en_AU=ISO-8859-1
+en_CA=ISO-8859-1
+en_GB=ISO-8859-1
 # Solaris
-locale.all.en_GB.ISO8859-15=ISO-8859-15
+en_GB.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.en_GB.ISO8859-15@euro=ISO-8859-15
-locale.all.en_GB.88591=ISO-8859-1
-locale.all.en_GB.ISO8859-1=ISO-8859-1
+en_GB.ISO8859-15@euro=ISO-8859-15
+en_GB.88591=ISO-8859-1
+en_GB.ISO8859-1=ISO-8859-1
 # HP
-locale.all.en_GB.iso885915@euro=ISO-8859-15
+en_GB.iso885915@euro=ISO-8859-15
 # AIX
-#locale.all.En_GB=IBM-850
+#En_GB=IBM-850
 # Solaris
-locale.all.en_IE.ISO8859-1=ISO-8859-1
-locale.all.en_IE.ISO8859-15=ISO-8859-15
+en_IE.ISO8859-1=ISO-8859-1
+en_IE.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.en_IE.ISO8859-15@euro=ISO-8859-15
-locale.all.en_JP=EUC-JP
-locale.all.en_JP.IBM-eucJP=EUC-JP
-locale.all.En_JP.IBM-932=Shift_JIS
-locale.all.En_JP=Shift_JIS
-locale.all.en_KR=EUC-KR
-locale.all.en_KR.IBM-eucKR=EUC-KR
-locale.all.en_TH=ISO-8859-1
-locale.all.en_US=ISO-8859-1
-locale.all.en_US.88591=ISO-8859-1
-locale.all.en_US.ISO8859-1=ISO-8859-1
+en_IE.ISO8859-15@euro=ISO-8859-15
+en_JP=EUC-JP
+en_JP.IBM-eucJP=EUC-JP
+En_JP.IBM-932=Shift_JIS
+En_JP=Shift_JIS
+en_KR=EUC-KR
+en_KR.IBM-eucKR=EUC-KR
+en_TH=ISO-8859-1
+en_US=ISO-8859-1
+en_US.88591=ISO-8859-1
+en_US.ISO8859-1=ISO-8859-1
 #FreeBSD
-locale.all.en_US.ISO_8859-1=ISO-8859-1
-locale.all.da_DK.ISO_8859-1=ISO-8859-1
-locale.all.de_AT.ISO_8859-1=ISO-8859-1
-locale.all.de_CH.ISO_8859-1=ISO-8859-1
-locale.all.de_DE.ISO_8859-1=ISO-8859-1
-locale.all.en_AU.ISO_8859-1=ISO-8859-1
-locale.all.en_CA.ISO_8859-1=ISO-8859-1
-locale.all.en_GB.ISO_8859-1=ISO-8859-1
-locale.all.es_ES.ISO_8859-1=ISO-8859-1
-locale.all.fi_FI.ISO_8859-1=ISO-8859-1
-locale.all.fr_BE.ISO_8859-1=ISO-8859-1
-locale.all.fr_CA.ISO_8859-1=ISO-8859-1
-locale.all.fr_CH.ISO_8859-1=ISO-8859-1
-locale.all.fr_FR.ISO_8859-1=ISO-8859-1
-locale.all.is_IS.ISO_8859-1=ISO-8859-1
-locale.all.it_CH.ISO_8859-1=ISO-8859-1
-locale.all.it_IT.ISO_8859-1=ISO-8859-1
-locale.all.la_LN.ISO_8859-1=ISO-8859-1
-locale.all.nl_BE.ISO_8859-1=ISO-8859-1
-locale.all.nl_NL.ISO_8859-1=ISO-8859-1
-locale.all.no_NO.ISO_8859-1=ISO-8859-1
-locale.all.pt_PT.ISO_8859-1=ISO-8859-1
-locale.all.sv_SE.ISO_8859-1=ISO-8859-1
+en_US.ISO_8859-1=ISO-8859-1
+da_DK.ISO_8859-1=ISO-8859-1
+de_AT.ISO_8859-1=ISO-8859-1
+de_CH.ISO_8859-1=ISO-8859-1
+de_DE.ISO_8859-1=ISO-8859-1
+en_AU.ISO_8859-1=ISO-8859-1
+en_CA.ISO_8859-1=ISO-8859-1
+en_GB.ISO_8859-1=ISO-8859-1
+es_ES.ISO_8859-1=ISO-8859-1
+fi_FI.ISO_8859-1=ISO-8859-1
+fr_BE.ISO_8859-1=ISO-8859-1
+fr_CA.ISO_8859-1=ISO-8859-1
+fr_CH.ISO_8859-1=ISO-8859-1
+fr_FR.ISO_8859-1=ISO-8859-1
+is_IS.ISO_8859-1=ISO-8859-1
+it_CH.ISO_8859-1=ISO-8859-1
+it_IT.ISO_8859-1=ISO-8859-1
+la_LN.ISO_8859-1=ISO-8859-1
+nl_BE.ISO_8859-1=ISO-8859-1
+nl_NL.ISO_8859-1=ISO-8859-1
+no_NO.ISO_8859-1=ISO-8859-1
+pt_PT.ISO_8859-1=ISO-8859-1
+sv_SE.ISO_8859-1=ISO-8859-1
 # FreeBSD 8859-15
-locale.all.da_DK.DIS_8859-15=ISO-8859-15
-locale.all.de_AT.DIS_8859-15=ISO-8859-15
-locale.all.de_CH.DIS_8859-15=ISO-8859-15
-locale.all.de_DE.DIS_8859-15=ISO-8859-15
-locale.all.en_AU.DIS_8859-15=ISO-8859-15
-locale.all.en_CA.DIS_8859-15=ISO-8859-15
-locale.all.en_GB.DIS_8859-15=ISO-8859-15
-locale.all.en_US.DIS_8859-15=ISO-8859-15
-locale.all.es_ES.DIS_8859-15=ISO-8859-15
-locale.all.fi_FI.DIS_8859-15=ISO-8859-15
-locale.all.fr_BE.DIS_8859-15=ISO-8859-15
-locale.all.fr_CA.DIS_8859-15=ISO-8859-15
-locale.all.fr_CH.DIS_8859-15=ISO-8859-15
-locale.all.fr_FR.DIS_8859-15=ISO-8859-15
-locale.all.is_IS.DIS_8859-15=ISO-8859-15
-locale.all.it_CH.DIS_8859-15=ISO-8859-15
-locale.all.it_IT.DIS_8859-15=ISO-8859-15
-locale.all.la_LN.DIS_8859-15=ISO-8859-15
-locale.all.nl_BE.DIS_8859-15=ISO-8859-15
-locale.all.nl_NL.DIS_8859-15=ISO-8859-15
-locale.all.no_NO.DIS_8859-15=ISO-8859-15
-locale.all.pt_PT.DIS_8859-15=ISO-8859-15
-locale.all.sv_SE.DIS_8859-15=ISO-8859-15
+da_DK.DIS_8859-15=ISO-8859-15
+de_AT.DIS_8859-15=ISO-8859-15
+de_CH.DIS_8859-15=ISO-8859-15
+de_DE.DIS_8859-15=ISO-8859-15
+en_AU.DIS_8859-15=ISO-8859-15
+en_CA.DIS_8859-15=ISO-8859-15
+en_GB.DIS_8859-15=ISO-8859-15
+en_US.DIS_8859-15=ISO-8859-15
+es_ES.DIS_8859-15=ISO-8859-15
+fi_FI.DIS_8859-15=ISO-8859-15
+fr_BE.DIS_8859-15=ISO-8859-15
+fr_CA.DIS_8859-15=ISO-8859-15
+fr_CH.DIS_8859-15=ISO-8859-15
+fr_FR.DIS_8859-15=ISO-8859-15
+is_IS.DIS_8859-15=ISO-8859-15
+it_CH.DIS_8859-15=ISO-8859-15
+it_IT.DIS_8859-15=ISO-8859-15
+la_LN.DIS_8859-15=ISO-8859-15
+nl_BE.DIS_8859-15=ISO-8859-15
+nl_NL.DIS_8859-15=ISO-8859-15
+no_NO.DIS_8859-15=ISO-8859-15
+pt_PT.DIS_8859-15=ISO-8859-15
+sv_SE.DIS_8859-15=ISO-8859-15
 # FreeBSD 8859-2
-locale.all.cs_CZ.ISO_8859-2=ISO-8859-2
-locale.all.hr_HR.ISO_8859-2=ISO-8859-2
-locale.all.hu_HU.ISO_8859-2=ISO-8859-2
-locale.all.la_LN.ISO_8859-2=ISO-8859-2
-locale.all.pl_PL.ISO_8859-2=ISO-8859-2
-locale.all.sl_SI.ISO_8859-2=ISO-8859-2
+cs_CZ.ISO_8859-2=ISO-8859-2
+hr_HR.ISO_8859-2=ISO-8859-2
+hu_HU.ISO_8859-2=ISO-8859-2
+la_LN.ISO_8859-2=ISO-8859-2
+pl_PL.ISO_8859-2=ISO-8859-2
+sl_SI.ISO_8859-2=ISO-8859-2
 # FreeBSD 8859-4
-locale.all.la_LN.ISO_8859-4=ISO-8859-4
-locale.all.lt_LT.ISO_8859-4=ISO-8859-4
+la_LN.ISO_8859-4=ISO-8859-4
+lt_LT.ISO_8859-4=ISO-8859-4
 # FreeBSD 8859-5
-locale.all.ru_RU.ISO_8859-5=ISO-8859-5
-locale.all.ru_SU.ISO_8859-5=ISO-8859-5
+ru_RU.ISO_8859-5=ISO-8859-5
+ru_SU.ISO_8859-5=ISO-8859-5
 # FreeBSD Russian
-locale.all.ru_SU.KOI8-R=KOI8-R
+ru_SU.KOI8-R=KOI8-R
 # FreeBSD Ukrainian
-locale.all.uk_UA.KOI8-U=KOI8-U
+uk_UA.KOI8-U=KOI8-U
 # Solaris
-locale.all.en_US.UTF-8=UTF-8
+en_US.UTF-8=UTF-8
 # Solaris
-locale.all.en_US.UTF-8@euro=UTF-8
+en_US.UTF-8@euro=UTF-8
 # AIX
-#locale.all.En_US=IBM-850
-locale.all.english.iso88591=ISO-8859-1
-locale.all.es=ISO-8859-1
+#En_US=IBM-850
+english.iso88591=ISO-8859-1
+es=ISO-8859-1
 # Solaris
-locale.all.es.ISO8859-15=ISO-8859-15
+es.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.es.ISO8859-15@euro=ISO-8859-15
+es.ISO8859-15@euro=ISO-8859-15
 # Solaris
-locale.all.es.UTF-8=UTF-8
+es.UTF-8=UTF-8
 # Solaris
-locale.all.es.UTF-8@euro=UTF-8
-locale.all.es_ES=ISO-8859-1
-locale.all.es_ES.ISO8859-15=ISO-8859-15
-locale.all.es_ES.ISO8859-15@euro=ISO-8859-15
-locale.all.es_AR.ISO8859-1=ISO-8859-1
-locale.all.es_BO.ISO8859-1=ISO-8859-1
-locale.all.es_CL.ISO8859-1=ISO-8859-1
-locale.all.es_CO.ISO8859-1=ISO-8859-1
-locale.all.es_CR.ISO8859-1=ISO-8859-1
-locale.all.es_EC.ISO8859-1=ISO-8859-1
-locale.all.es_GT.ISO8859-1=ISO-8859-1
-locale.all.es_MX.ISO8859-1=ISO-8859-1
-locale.all.es_NI.ISO8859-1=ISO-8859-1
-locale.all.es_PA.ISO8859-1=ISO-8859-1
-locale.all.es_PE.ISO8859-1=ISO-8859-1
-locale.all.es_PY.ISO8859-1=ISO-8859-1
-locale.all.es_SV.ISO8859-1=ISO-8859-1
-locale.all.es_UY.ISO8859-1=ISO-8859-1
-locale.all.es_VE.ISO8859-1=ISO-8859-1
+es.UTF-8@euro=UTF-8
+es_ES=ISO-8859-1
+es_ES.ISO8859-15=ISO-8859-15
+es_ES.ISO8859-15@euro=ISO-8859-15
+es_AR.ISO8859-1=ISO-8859-1
+es_BO.ISO8859-1=ISO-8859-1
+es_CL.ISO8859-1=ISO-8859-1
+es_CO.ISO8859-1=ISO-8859-1
+es_CR.ISO8859-1=ISO-8859-1
+es_EC.ISO8859-1=ISO-8859-1
+es_GT.ISO8859-1=ISO-8859-1
+es_MX.ISO8859-1=ISO-8859-1
+es_NI.ISO8859-1=ISO-8859-1
+es_PA.ISO8859-1=ISO-8859-1
+es_PE.ISO8859-1=ISO-8859-1
+es_PY.ISO8859-1=ISO-8859-1
+es_SV.ISO8859-1=ISO-8859-1
+es_UY.ISO8859-1=ISO-8859-1
+es_VE.ISO8859-1=ISO-8859-1
 # HP
-locale.all.es_ES.iso885915=ISO-8859-15
+es_ES.iso885915=ISO-8859-15
 # HP
-locale.all.es_ES.iso885915@euro=ISO-8859-15
-locale.all.es_ES.88591=ISO-8859-1
-locale.all.es_ES.ISO8859-1=ISO-8859-1
+es_ES.iso885915@euro=ISO-8859-15
+es_ES.88591=ISO-8859-1
+es_ES.ISO8859-1=ISO-8859-1
 # AIX
-#locale.all.En_ES=IBM-850
+#En_ES=IBM-850
 # Solaris
-locale.all.et_EE.ISO8859-15=ISO-8859-15
+et_EE.ISO8859-15=ISO-8859-15
 # AIX
-#locale.all.Et_ET=IBM-922
+#Et_ET=IBM-922
 # AIX
-locale.all.ET_ET=UTF-8
-locale.all.fi=ISO-8859-1
+ET_ET=UTF-8
+fi=ISO-8859-1
 # Solaris
-locale.all.fi.ISO8859-15=ISO-8859-15
+fi.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.fi.ISO8859-15@euro=ISO-8859-15
-locale.all.fi_FI=ISO-8859-1
-locale.all.fi_FI.88591=ISO-8859-1
-locale.all.fi_FI.ISO8859-1=ISO-8859-1
-locale.all.fi_FI.ISO8859-15=ISO-8859-15
-locale.all.fi_FI.ISO8859-15@euro=ISO-8859-15
+fi.ISO8859-15@euro=ISO-8859-15
+fi_FI=ISO-8859-1
+fi_FI.88591=ISO-8859-1
+fi_FI.ISO8859-1=ISO-8859-1
+fi_FI.ISO8859-15=ISO-8859-15
+fi_FI.ISO8859-15@euro=ISO-8859-15
 # HP
-locale.all.fi_FI.iso885915@euro=ISO-8859-15
+fi_FI.iso885915@euro=ISO-8859-15
 # AIX
-#locale.all.Fi_ES=IBM-850
-locale.all.finnish.iso88591=ISO-8859-1
-locale.all.fr=ISO-8859-1
+#Fi_ES=IBM-850
+finnish.iso88591=ISO-8859-1
+fr=ISO-8859-1
 # Solaris
-locale.all.fr.ISO8859-15=ISO-8859-15
+fr.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.fr.ISO8859-15@euro=ISO-8859-15
+fr.ISO8859-15@euro=ISO-8859-15
 # Solaris
-locale.all.fr.UTF-8=UTF-8
+fr.UTF-8=UTF-8
 # Solaris
-locale.all.fr.UTF-8@euro=UTF-8
-locale.all.fr_BE=ISO-8859-1
+fr.UTF-8@euro=UTF-8
+fr_BE=ISO-8859-1
 # Solaris
-locale.all.fr_BE.ISO8859-15=ISO-8859-15
+fr_BE.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.fr_BE.ISO8859-15@euro=ISO-8859-15
-locale.all.fr_BE.88591=ISO-8859-1
-locale.all.fr_BE.ISO8859-1=ISO-8859-1
-locale.all.fr_BE.iso8859=ISO-8859-1
+fr_BE.ISO8859-15@euro=ISO-8859-15
+fr_BE.88591=ISO-8859-1
+fr_BE.ISO8859-1=ISO-8859-1
+fr_BE.iso8859=ISO-8859-1
 # AIX
-#locale.all.Fr_BE=IBM-850
-locale.all.fr_CA=ISO-8859-1
-locale.all.fr_CA.88591=ISO-8859-1
-locale.all.fr_CA.iso8859=ISO-8859-1
+#Fr_BE=IBM-850
+fr_CA=ISO-8859-1
+fr_CA.88591=ISO-8859-1
+fr_CA.iso8859=ISO-8859-1
 # HP
-locale.all.fr_CA.iso885915@euro=ISO-8859-15
-locale.all.fr_CA.ISO8859-1=ISO-8859-1
+fr_CA.iso885915@euro=ISO-8859-15
+fr_CA.ISO8859-1=ISO-8859-1
 # AIX
-#locale.all.Fr_CA=IBM-850
-locale.all.fr_CH=ISO-8859-1
-locale.all.fr_CH.88591=ISO-8859-1
-locale.all.fr_CH.iso8859=ISO-8859-1
-locale.all.fr_CH.ISO8859-1=ISO-8859-1
+#Fr_CA=IBM-850
+fr_CH=ISO-8859-1
+fr_CH.88591=ISO-8859-1
+fr_CH.iso8859=ISO-8859-1
+fr_CH.ISO8859-1=ISO-8859-1
 # Solaris
-locale.all.fr_FR.ISO8859-15=ISO-8859-15
-locale.all.fr_FR.ISO8859-15@euro=ISO-8859-15
+fr_FR.ISO8859-15=ISO-8859-15
+fr_FR.ISO8859-15@euro=ISO-8859-15
 # AIX
-#locale.all.Fr_CH=IBM-850
-locale.all.fr_FR=ISO-8859-1
-locale.all.fr_FR.88591=ISO-8859-1
-locale.all.fr_FR.iso8859=ISO-8859-1
+#Fr_CH=IBM-850
+fr_FR=ISO-8859-1
+fr_FR.88591=ISO-8859-1
+fr_FR.iso8859=ISO-8859-1
 # HP
-locale.all.fr_FR.iso885915=ISO-8859-15
+fr_FR.iso885915=ISO-8859-15
 # HP
-locale.all.fr_FR.iso885915@euro=ISO-8859-15
-locale.all.fr_FR.ISO8859-1=ISO-8859-1
+fr_FR.iso885915@euro=ISO-8859-15
+fr_FR.ISO8859-1=ISO-8859-1
 # AIX
-#locale.all.Fr_FR=IBM-850
-locale.all.french.iso88591=ISO-8859-1
-locale.all.german.iso88591=ISO-8859-1
+#Fr_FR=IBM-850
+french.iso88591=ISO-8859-1
+german.iso88591=ISO-8859-1
 # Solaris
-locale.all.he_HE=ISO-8859-8
-locale.all.he_IL=ISO-8859-8
-locale.all.hr_HR.ISO8859-2=ISO-8859-2
+he_HE=ISO-8859-8
+he_IL=ISO-8859-8
+hr_HR.ISO8859-2=ISO-8859-2
 # AIX
-locale.all.hr_HR=ISO-8859-2
-locale.all.hu_HU=ISO-8859-2
-locale.all.hu_HU.88592=ISO-8859-2
-locale.all.hu_HU.ISO8859-2=ISO-8859-2
-locale.all.hungarian=ISO-8859-2
-locale.all.icelandic.iso88591=ISO-8859-1
-locale.all.iso_8859_1=ISO-8859-1
-locale.all.is=ISO-8859-1
-locale.all.is_IS=ISO-8859-1
-locale.all.is_IS.88591=ISO-8859-1
-locale.all.is_IS.ISO8859-1=ISO-8859-1
+hr_HR=ISO-8859-2
+hu_HU=ISO-8859-2
+hu_HU.88592=ISO-8859-2
+hu_HU.ISO8859-2=ISO-8859-2
+hungarian=ISO-8859-2
+icelandic.iso88591=ISO-8859-1
+iso_8859_1=ISO-8859-1
+is=ISO-8859-1
+is_IS=ISO-8859-1
+is_IS.88591=ISO-8859-1
+is_IS.ISO8859-1=ISO-8859-1
 # HP
-locale.all.is_IS.iso885915@euro=ISO-8859-15
+is_IS.iso885915@euro=ISO-8859-15
 # AIX
-#locale.all.Is_IS=IBM-850
-locale.all.it=ISO-8859-1
+#Is_IS=IBM-850
+it=ISO-8859-1
 # Solaris
-locale.all.it.ISO8859-15=ISO-8859-15
+it.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.it.ISO8859-15@euro=ISO-8859-15
+it.ISO8859-15@euro=ISO-8859-15
 # Solaris
-locale.all.it.UTF-8=UTF-8
+it.UTF-8=UTF-8
 # Solaris
-locale.all.it.UTF-8@euro=UTF-8
-locale.all.it_IT.ISO8859-15=ISO-8859-15
-locale.all.it_IT.ISO8859-15@euro=ISO-8859-15
+it.UTF-8@euro=UTF-8
+it_IT.ISO8859-15=ISO-8859-15
+it_IT.ISO8859-15@euro=ISO-8859-15
 # AIX
-#locale.all.It_IT=IBM-850
-locale.all.italian.iso8859-1=ISO-8859-1
-locale.all.it_CH=ISO-8859-1
-locale.all.it_IT=ISO-8859-1
-locale.all.it_IT.88591=ISO-8859-1
-locale.all.it_IT.ISO8859-1=ISO-8859-1
+#It_IT=IBM-850
+italian.iso8859-1=ISO-8859-1
+it_CH=ISO-8859-1
+it_IT=ISO-8859-1
+it_IT.88591=ISO-8859-1
+it_IT.ISO8859-1=ISO-8859-1
 # HP
-locale.all.it_IT.iso885915=ISO-8859-15
+it_IT.iso885915=ISO-8859-15
 # HP
-locale.all.it_IT.iso885915@euro=ISO-8859-15
+it_IT.iso885915@euro=ISO-8859-15
 # AIX
-locale.all.iw_IL=ISO-8859-8
+iw_IL=ISO-8859-8
 # AIX
-#locale.all.Iw_IL=IBM-856
-locale.all.ja=EUC-JP
-locale.all.Ja_JP.IBM-932=Shift_JIS
-locale.all.Ja_JP=Shift_JIS
-locale.all.japanese=EUC-JP
-locale.all.japanese.euc=EUC-JP
-locale.all.ja_JP=EUC-JP
+#Iw_IL=IBM-856
+ja=EUC-JP
+Ja_JP.IBM-932=Shift_JIS
+Ja_JP=Shift_JIS
+japanese=EUC-JP
+japanese.euc=EUC-JP
+ja_JP=EUC-JP
 # Solaris
-locale.all.ja_JP.UTF-8=UTF-8
+ja_JP.UTF-8=UTF-8
 # Solaris
-locale.all.ja_JP.UTF-8@euro=UTF-8
-locale.all.ja_JP.EUC=EUC-JP
-locale.all.ja_JP.eucJP=EUC-JP
-locale.all.ja_JP.SJIS=Shift_JIS
-locale.all.ja_JP.PCK=Shift_JIS
-locale.all.ja_JP.IBM-eucJP=EUC-JP
-locale.all.ja_JP.mscode=Shift_JIS
-locale.all.ja_JP.ujis=EUC-JP
-locale.all.katakana=Shift_JIS
-locale.all.ko=EUC-KR
-locale.all.ko_KR=EUC-KR
+ja_JP.UTF-8@euro=UTF-8
+ja_JP.EUC=EUC-JP
+ja_JP.eucJP=EUC-JP
+ja_JP.SJIS=Shift_JIS
+ja_JP.PCK=Shift_JIS
+ja_JP.IBM-eucJP=EUC-JP
+ja_JP.mscode=Shift_JIS
+ja_JP.ujis=EUC-JP
+katakana=Shift_JIS
+ko=EUC-KR
+ko_KR=EUC-KR
 # Solaris
-locale.all.ko_KR.UTF-8=UTF-8
+ko_KR.UTF-8=UTF-8
 # Solaris
-locale.all.ko_KR.UTF-8@euro=UTF-8
-locale.all.ko_KR.euc=EUC-KR
-locale.all.ko_KR.euckr=EUC-KR
-locale.all.ko_KR.eucKR=EUC-KR
-locale.all.ko_KR.IBM-eucKR=EUC-KR
-locale.all.ko_KR.EUC=EUC-KR
-locale.all.ko.UTF-8=UTF-8
-locale.all.korean=EUC-KR
+ko_KR.UTF-8@euro=UTF-8
+ko_KR.euc=EUC-KR
+ko_KR.euckr=EUC-KR
+ko_KR.eucKR=EUC-KR
+ko_KR.IBM-eucKR=EUC-KR
+ko_KR.EUC=EUC-KR
+ko.UTF-8=UTF-8
+korean=EUC-KR
 # Solaris
-locale.all.lt_LT.ISO8859-13=ISO-8859-13
+lt_LT.ISO8859-13=ISO-8859-13
 # AIX
-#locale.all.Lt_LT=IBM-921
+#Lt_LT=IBM-921
 # AIX
-locale.all.LT_LT=UTF-8
+LT_LT=UTF-8
 # Solaris
-locale.all.lv_LV.ISO8859-13=ISO-8859-13
+lv_LV.ISO8859-13=ISO-8859-13
 # AIX
-#locale.all.Lt_LV=IBM-921
+#Lt_LV=IBM-921
 # AIX
-locale.all.LT_LV=UTF-8
+LT_LV=UTF-8
 # Solaris
-locale.all.mk_MK.ISO8859-5=ISO-8859-5
+mk_MK.ISO8859-5=ISO-8859-5
 # AIX
-locale.all.mk_MK=ISO-8859-5
-locale.all.nl=ISO-8859-1
+mk_MK=ISO-8859-5
+nl=ISO-8859-1
 # Solaris
-locale.all.nl.ISO8859-15=ISO-8859-15
+nl.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.nl.ISO8859-15@euro=ISO-8859-15
-locale.all.nl_BE=ISO-8859-1
+nl.ISO8859-15@euro=ISO-8859-15
+nl_BE=ISO-8859-1
 # Solaris
-locale.all.nl_BE.ISO8859-15=ISO-8859-15
+nl_BE.ISO8859-15=ISO-8859-15
 # Solaris
-locale.all.nl_BE.ISO8859-15@euro=ISO-8859-15
-locale.all.nl_BE.88591=ISO-8859-1
-locale.all.nl_BE.ISO8859-1=ISO-8859-1
+nl_BE.ISO8859-15@euro=ISO-8859-15
+nl_BE.88591=ISO-8859-1
+nl_BE.ISO8859-1=ISO-8859-1
 # Solaris
-locale.all.nl_NL.ISO8859-15=ISO-8859-15
-locale.all.nl_NL.ISO8859-15@euro=ISO-8859-15
+nl_NL.ISO8859-15=ISO-8859-15
+nl_NL.ISO8859-15@euro=ISO-8859-15
 # AIX
-#locale.all.NL_BE=IBM-850
-locale.all.nl_NL=ISO-8859-1
-locale.all.nl_NL.88591=ISO-8859-1
-locale.all.nl_NL.ISO8859-1=ISO-8859-1
+#NL_BE=IBM-850
+nl_NL=ISO-8859-1
+nl_NL.88591=ISO-8859-1
+nl_NL.ISO8859-1=ISO-8859-1
 # HP
-locale.all.nl_NL.iso885915@euro=ISO-8859-15
+nl_NL.iso885915@euro=ISO-8859-15
 # AIX
-#locale.all.NL_NL=IBM-850
-locale.all.no=ISO-8859-1
-locale.all.no_NO=ISO-8859-1
-locale.all.no_NO.88591=ISO-8859-1
-locale.all.no_NO.ISO8859-1=ISO-8859-1
+#NL_NL=IBM-850
+no=ISO-8859-1
+no_NO=ISO-8859-1
+no_NO.88591=ISO-8859-1
+no_NO.ISO8859-1=ISO-8859-1
 # Solaris
-locale.all.no_NO.ISO8859-1@bokmal=ISO-8859-1
-locale.all.no_NO.ISO8859-1@nynorsk=ISO-8859-1
+no_NO.ISO8859-1@bokmal=ISO-8859-1
+no_NO.ISO8859-1@nynorsk=ISO-8859-1
 # HP
-locale.all.no_NO.iso885915@euro=ISO-8859-15