merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 28 Dec 2015 10:25:05 +0100
changeset 277689 7c83da46ea740bc14028aca9f9a662f062de5586
parent 277663 a3271c17e5ac5b08b6886d66c3a26e0afd7d7b0b (current diff)
parent 277688 210aaacaf2b1a5f51b5d78d17c44197af2956614 (diff)
child 277697 798732ac61bbe88baf3117acca1018757ca3d810
child 277710 5b9292b9f878471b54498c1a70cecb76d5a409b3
child 277718 56c56562d06eed2a33d43ea3c27e0238712b4da4
push id29829
push usercbook@mozilla.com
push dateMon, 28 Dec 2015 09:26:06 +0000
treeherdermozilla-central@7c83da46ea74 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone46.0a1
first release with
nightly linux32
7c83da46ea74 / 46.0a1 / 20151228030213 / files
nightly linux64
7c83da46ea74 / 46.0a1 / 20151228030213 / files
nightly mac
7c83da46ea74 / 46.0a1 / 20151228030213 / files
nightly win32
7c83da46ea74 / 46.0a1 / 20151228030213 / files
nightly win64
7c83da46ea74 / 46.0a1 / 20151228030213 / 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
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1086,32 +1086,60 @@ window.addEventListener('ContentStart', 
 
   let updatePrompt = promptCc.createInstance(Ci.nsIUpdatePrompt);
   if (!updatePrompt) {
     return;
   }
 
   updatePrompt.wrappedJSObject.handleContentStart(shell);
 });
+/* The "GPSChipOn" is to indicate that GPS engine is turned ON by the modem.
+   During this GPS engine is turned ON by the modem, we make the location tracking icon visible to user.
+   Once GPS engine is turned OFF, the location icon will disappear.
+   If GPS engine is not turned ON by the modem or GPS location service is triggered,
+   we let GPS service take over the control of showing the location tracking icon.
+   The regular sequence of the geolocation-device-events is: starting-> GPSStarting-> shutdown-> GPSShutdown
+*/
+
 
 (function geolocationStatusTracker() {
   let gGeolocationActive = false;
+  let GPSChipOn = false;
 
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     let oldState = gGeolocationActive;
-    if (aData == "starting") {
-      gGeolocationActive = true;
-    } else if (aData == "shutdown") {
-      gGeolocationActive = false;
+    let promptWarning = false;
+    switch (aData) {
+      case "GPSStarting":
+        if (!gGeolocationActive) {
+          gGeolocationActive = true;
+          GPSChipOn = true;
+          promptWarning = true;
+        }
+        break;
+      case "GPSShutdown":
+        if (GPSChipOn) {
+          gGeolocationActive = false;
+          GPSChipOn = false;
+        }
+        break;
+      case "starting":
+        gGeolocationActive = true;
+        GPSChipOn = false;
+        break;
+      case "shutdown":
+        gGeolocationActive = false;
+        break;
     }
 
     if (gGeolocationActive != oldState) {
       shell.sendChromeEvent({
         type: 'geolocation-status',
-        active: gGeolocationActive
+        active: gGeolocationActive,
+        prompt: promptWarning
       });
     }
 }, "geolocation-device-events", false);
 })();
 
 (function headphonesStatusTracker() {
   Services.obs.addObserver(function(aSubject, aTopic, aData) {
     shell.sendChromeEvent({
--- a/browser/components/sessionstore/SessionHistory.jsm
+++ b/browser/components/sessionstore/SessionHistory.jsm
@@ -149,20 +149,24 @@ var SessionHistoryInternal = {
       entry.isSrcdocEntry = shEntry.isSrcdocEntry;
 
     if (shEntry.baseURI)
       entry.baseURI = shEntry.baseURI.spec;
 
     if (shEntry.contentType)
       entry.contentType = shEntry.contentType;
 
-    let x = {}, y = {};
-    shEntry.getScrollPosition(x, y);
-    if (x.value != 0 || y.value != 0)
-      entry.scroll = x.value + "," + y.value;
+    if (shEntry.scrollRestorationIsManual) {
+      entry.scrollRestorationIsManual = true;
+    } else {
+      let x = {}, y = {};
+      shEntry.getScrollPosition(x, y);
+      if (x.value != 0 || y.value != 0)
+        entry.scroll = x.value + "," + y.value;
+    }
 
     // Collect owner data for the current history entry.
     try {
       let owner = this.serializeOwner(shEntry);
       if (owner) {
         entry.owner_b64 = owner;
       }
     } catch (ex) {
@@ -333,17 +337,19 @@ var SessionHistoryInternal = {
       shEntry.stateData =
         Cc["@mozilla.org/docshell/structured-clone-container;1"].
         createInstance(Ci.nsIStructuredCloneContainer);
 
       shEntry.stateData.initFromBase64(entry.structuredCloneState,
                                        entry.structuredCloneVersion);
     }
 
-    if (entry.scroll) {
+    if (entry.scrollRestorationIsManual) {
+      shEntry.scrollRestorationIsManual = true;
+    } else if (entry.scroll) {
       var scrollPos = (entry.scroll || "0,0").split(",");
       scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
       shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
     }
 
     let childDocIdents = {};
     if (entry.docIdentifier) {
       // If we have a serialized document identifier, try to find an SHEntry
--- a/build/autoconf/config.status.m4
+++ b/build/autoconf/config.status.m4
@@ -95,20 +95,16 @@ AC_SUBST(WIN_TOP_SRC)
 dnl Used in all Makefile.in files
 top_srcdir=$srcdir
 AC_SUBST(top_srcdir)
 
 dnl Picked from autoconf 2.13
 trap '' 1 2 15
 AC_CACHE_SAVE
 
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
 trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
 : ${CONFIG_STATUS=./config.status}
 
 dnl We're going to need [ ] for python syntax.
 changequote(<<<, >>>)dnl
 echo creating $CONFIG_STATUS
 
 extra_python_path=${COMM_BUILD:+"'mozilla', "}
--- a/build/autoconf/hooks.m4
+++ b/build/autoconf/hooks.m4
@@ -10,16 +10,21 @@ trap '[ "$?" != 0 ] && echo "------ conf
 changequote([, ])dnl
 ])
 
 dnl Wrap AC_INIT_PREPARE to add the above trap.
 define([_MOZ_AC_INIT_PREPARE], defn([AC_INIT_PREPARE]))
 define([AC_INIT_PREPARE],
 [_MOZ_AC_INIT_PREPARE($1)
 MOZ_CONFIG_LOG_TRAP
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
 > subconfigures
 > skip_subconfigures
 ])
 
 define([AC_OUTPUT_SUBDIRS],
 [for moz_config_dir in $1; do
   _CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
   case "$moz_config_dir" in
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10038,33 +10038,40 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       // flag on firing onLocationChange(...).
       // Anyway, aCloneSHChildren param is simply reflecting
       // doShortCircuitedLoad in this scope.
       OnNewURI(aURI, nullptr, owner, mLoadType, true, true, true);
 
       nsCOMPtr<nsIInputStream> postData;
       nsCOMPtr<nsISupports> cacheKey;
 
+      bool scrollRestorationIsManual = false;
       if (mOSHE) {
         /* save current position of scroller(s) (bug 59774) */
         mOSHE->SetScrollPosition(cx, cy);
+        mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
         // Get the postdata and page ident from the current page, if
         // the new load is being done via normal means.  Note that
         // "normal means" can be checked for just by checking for
         // LOAD_CMD_NORMAL, given the loadType and allowScroll check
         // above -- it filters out some LOAD_CMD_NORMAL cases that we
         // wouldn't want here.
         if (aLoadType & LOAD_CMD_NORMAL) {
           mOSHE->GetPostData(getter_AddRefs(postData));
           mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
 
           // Link our new SHEntry to the old SHEntry's back/forward
           // cache data, since the two SHEntries correspond to the
           // same document.
           if (mLSHE) {
+            if (!aSHEntry) {
+              // If we're not doing a history load, scroll restoration
+              // should be inherited from the previous session history entry.
+              mLSHE->SetScrollRestorationIsManual(scrollRestorationIsManual);
+            }
             mLSHE->AdoptBFCacheEntry(mOSHE);
           }
         }
       }
 
       /* Assign mOSHE to mLSHE. This will either be a new entry created
        * by OnNewURI() for normal loads or aSHEntry for history loads.
        */
@@ -10127,20 +10134,22 @@ nsDocShell::InternalLoad(nsIURI* aURI,
       // ScrollToAnchor performs other important tasks, such as informing
       // the presShell that we have a new hash.  See bug 680257.
       rv = ScrollToAnchor(curHash, newHash, aLoadType);
       NS_ENSURE_SUCCESS(rv, rv);
 
       /* restore previous position of scroller(s), if we're moving
        * back in history (bug 59774)
        */
-      nscoord bx, by;
+      nscoord bx = 0;
+      nscoord by = 0;
       bool needsScrollPosUpdate = false;
       if (mOSHE && (aLoadType == LOAD_HISTORY ||
-                    aLoadType == LOAD_RELOAD_NORMAL)) {
+                    aLoadType == LOAD_RELOAD_NORMAL) &&
+          !scrollRestorationIsManual) {
         needsScrollPosUpdate = true;
         mOSHE->GetScrollPosition(&bx, &by);
       }
 
       // Dispatch the popstate and hashchange events, as appropriate.
       //
       // The event dispatch below can cause us to re-enter script and
       // destroy the docshell, nulling out mScriptGlobal. Hold a stack
@@ -11619,24 +11628,31 @@ nsDocShell::AddState(JS::Handle<JS::Valu
   nsCOMPtr<nsISHEntry> newSHEntry;
   if (!aReplace) {
     // Save the current scroll position (bug 590573).
     nscoord cx = 0, cy = 0;
     GetCurScrollPos(ScrollOrientation_X, &cx);
     GetCurScrollPos(ScrollOrientation_Y, &cy);
     mOSHE->SetScrollPosition(cx, cy);
 
+    bool scrollRestorationIsManual = false;
+    mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
+
     // Since we're not changing which page we have loaded, pass
     // true for aCloneChildren.
     rv = AddToSessionHistory(newURI, nullptr, nullptr, true,
                              getter_AddRefs(newSHEntry));
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
 
+    // Session history entries created by pushState inherit scroll restoration
+    // mode from the current entry.
+    newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual);
+
     // Link the new SHEntry to the old SHEntry's BFCache entry, since the
     // two entries correspond to the same document.
     NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), NS_ERROR_FAILURE);
 
     // Set the new SHEntry's title (bug 655273).
     nsString title;
     mOSHE->GetTitle(getter_Copies(title));
     newSHEntry->SetTitle(title);
@@ -11735,16 +11751,37 @@ nsDocShell::AddState(JS::Handle<JS::Valu
   } else {
     FireDummyOnLocationChange();
   }
   document->SetStateObject(scContainer);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual)
+{
+  *aIsManual = false;
+  if (mOSHE) {
+    mOSHE->GetScrollRestorationIsManual(aIsManual);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::SetCurrentScrollRestorationIsManual(bool aIsManual)
+{
+  if (mOSHE) {
+    mOSHE->SetScrollRestorationIsManual(aIsManual);
+  }
+
+  return NS_OK;
+}
+
 bool
 nsDocShell::ShouldAddToSessionHistory(nsIURI* aURI)
 {
   // I believe none of the about: urls should go in the history. But then
   // that could just be me... If the intent is only deny about:blank then we
   // should just do a spec compare, rather than two gets of the scheme and
   // then the path.  -Gagan
   nsresult rv;
@@ -12135,20 +12172,31 @@ nsDocShell::GetShouldSaveLayoutState(boo
 }
 
 nsresult
 nsDocShell::PersistLayoutHistoryState()
 {
   nsresult rv = NS_OK;
 
   if (mOSHE) {
+    bool scrollRestorationIsManual = false;
+    mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
+
     nsCOMPtr<nsIPresShell> shell = GetPresShell();
+    nsCOMPtr<nsILayoutHistoryState> layoutState;
     if (shell) {
-      nsCOMPtr<nsILayoutHistoryState> layoutState;
       rv = shell->CaptureHistoryState(getter_AddRefs(layoutState));
+    } else if (scrollRestorationIsManual) {
+      // Even if we don't have layout anymore, we may want to reset the current
+      // scroll state in layout history.
+      GetLayoutHistoryState(getter_AddRefs(layoutState));
+    }
+
+    if (scrollRestorationIsManual && layoutState) {
+      layoutState->ResetScrollState();
     }
   }
 
   return rv;
 }
 
 /* static */ nsresult
 nsDocShell::WalkHistoryEntries(nsISHEntry* aRootEntry,
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -38,17 +38,17 @@ interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
 
 typedef unsigned long nsLoadFlags;
 
-[scriptable, builtinclass, uuid(bc3524bd-023c-4fc8-ace1-472bc999fb12)]
+[scriptable, builtinclass, uuid(811aa3e1-7c4d-45ae-89da-ea1b107c60ed)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -1085,9 +1085,15 @@ interface nsIDocShell : nsIDocShellTreeI
   attribute DOMString paymentRequestId;
 
   /**
    * Allow usage of -moz-window-dragging:drag for content docshells.
    * True for top level chrome docshells. Throws if set to false with
    * top level chrome docshell.
    */
   attribute boolean windowDraggingAllowed;
+
+  /**
+   * Sets/gets the current scroll restoration mode.
+   * @see https://html.spec.whatwg.org/#dom-history-scroll-restoration
+  */
+  attribute boolean currentScrollRestorationIsManual;
 };
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -25,17 +25,17 @@ interface nsIBFCacheEntry;
 #include "nsRect.h"
 class nsDocShellEditorData;
 class nsSHEntryShared;
 %}
 [ref] native nsIntRect(nsIntRect);
 [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
 [ptr] native nsSHEntryShared(nsSHEntryShared);
 
-[scriptable, uuid(3a5e5fa0-5364-4fbb-a87a-3f12a6b51903)]
+[scriptable, uuid(0dad26b8-a259-42c7-93f1-2fa7fc076e45)]
 interface nsISHEntry : nsISupports
 {
     /**
      * A readonly property that returns the URI
      * of the current entry. The object returned is
      * of type nsIURI
      */
     readonly attribute nsIURI URI;
@@ -296,16 +296,22 @@ interface nsISHEntry : nsISupports
     attribute AString srcdocData;
 
     /**
      * When isSrcdocEntry is true, this contains the baseURI of the srcdoc
      * document for use in situations where it cannot otherwise be determined,
      * for example with view-source.
      */
     attribute nsIURI baseURI;
+
+    /**
+     * Sets/gets the current scroll restoration state,
+     * if true == "manual", false == "auto".
+     */
+    attribute boolean scrollRestorationIsManual;
 };
 
 [scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)]
 interface nsISHEntryInternal : nsISupports
 {
     [notxpcom] void RemoveFromBFCacheAsync();
     [notxpcom] void RemoveFromBFCacheSync();
 
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -28,16 +28,17 @@ nsSHEntry::nsSHEntry()
   , mReferrerPolicy(mozilla::net::RP_Default)
   , mLoadType(0)
   , mID(gEntryID++)
   , mScrollPositionX(0)
   , mScrollPositionY(0)
   , mParent(nullptr)
   , mURIWasModified(false)
   , mIsSrcdocEntry(false)
+  , mScrollRestorationIsManual(false)
 {
 }
 
 nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
   : mShared(aOther.mShared)
   , mURI(aOther.mURI)
   , mOriginalURI(aOther.mOriginalURI)
   , mLoadReplace(aOther.mLoadReplace)
@@ -48,16 +49,17 @@ nsSHEntry::nsSHEntry(const nsSHEntry& aO
   , mLoadType(0)         // XXX why not copy?
   , mID(aOther.mID)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
   , mParent(aOther.mParent)
   , mURIWasModified(aOther.mURIWasModified)
   , mStateData(aOther.mStateData)
   , mIsSrcdocEntry(aOther.mIsSrcdocEntry)
+  , mScrollRestorationIsManual(false)
   , mSrcdocData(aOther.mSrcdocData)
   , mBaseURI(aOther.mBaseURI)
 {
 }
 
 static bool
 ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
 {
@@ -594,16 +596,30 @@ nsSHEntry::GetBaseURI(nsIURI** aBaseURI)
 NS_IMETHODIMP
 nsSHEntry::SetBaseURI(nsIURI* aBaseURI)
 {
   mBaseURI = aBaseURI;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsSHEntry::GetScrollRestorationIsManual(bool* aIsManual)
+{
+  *aIsManual = mScrollRestorationIsManual;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::SetScrollRestorationIsManual(bool aIsManual)
+{
+  mScrollRestorationIsManual = aIsManual;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsSHEntry::GetChildCount(int32_t* aCount)
 {
   *aCount = mChildren.Count();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::AddChild(nsISHEntry* aChild, int32_t aOffset)
--- a/docshell/shistory/nsSHEntry.h
+++ b/docshell/shistory/nsSHEntry.h
@@ -59,13 +59,14 @@ private:
   uint32_t mID;
   int32_t mScrollPositionX;
   int32_t mScrollPositionY;
   nsISHEntry* mParent;
   nsCOMArray<nsISHEntry> mChildren;
   bool mURIWasModified;
   nsCOMPtr<nsIStructuredCloneContainer> mStateData;
   bool mIsSrcdocEntry;
+  bool mScrollRestorationIsManual;
   nsString mSrcdocData;
   nsCOMPtr<nsIURI> mBaseURI;
 };
 
 #endif /* nsSHEntry_h */
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_scrollRestoration.html
@@ -0,0 +1,128 @@
+<html>
+  <head>
+    <script>
+      var oldHistoryObject = null;
+
+      function test(event) {
+        if (!opener.scrollRestorationTest) {
+          opener.scrollRestorationTest = 0;
+        }
+        ++opener.scrollRestorationTest;
+
+        switch (opener.scrollRestorationTest) {
+          case 1: {
+            opener.is(event.persisted, false, "Shouldn't have persisted session history entry.");
+            opener.ok(history.scrollRestoration, "History object has scrollRestoration property.");
+            opener.ok(history.scrollRestoration, "auto", "history.scrollRestoration's default value should be 'auto'.");
+            history.scrollRestoration = "foobar";
+            opener.ok(history.scrollRestoration, "auto", "Invalid enum value should not change the value of an attribute.");
+            history.scrollRestoration = "manual";
+            opener.ok(history.scrollRestoration, "manual", "Valid enum value should change the value of an attribute.");
+            history.scrollRestoration = "auto";
+            opener.ok(history.scrollRestoration, "auto", "Valid enum value should change the value of an attribute.");
+            document.getElementById("bottom").scrollIntoView();
+            window.location.reload(false);
+            break;
+          }
+          case 2: {
+            opener.is(event.persisted, false, "Shouldn't have persisted session history entry.");
+            opener.isnot(window.scrollY, 0, "Should have restored scrolling.");
+            opener.is(history.scrollRestoration, "auto", "Should have the same scrollRestoration as before reload.");
+            history.scrollRestoration = "manual";
+            window.onunload = function() {} // Disable bfcache.
+            window.location.reload(false);
+            break;
+          }
+          case 3: {
+            opener.is(event.persisted, false, "Shouldn't have persisted session history entry.");
+            opener.is(window.scrollY, 0, "Should not have restored scrolling.");
+            opener.is(history.scrollRestoration, "manual", "Should have the same scrollRestoration as before reload.");
+            document.getElementById("bottom").scrollIntoView();
+            window.onunload = null; // Should get bfcache behavior.
+            opener.setTimeout("testWindow.history.back();", 250);
+            window.location.href = 'data:text/html,';
+            break;
+          }
+          case 4: {
+            opener.is(event.persisted, true, "Should have persisted session history entry.");
+            opener.isnot(window.scrollY, 0, "Should have kept the old scroll position.");
+            opener.is(history.scrollRestoration, "manual", "Should have the same scrollRestoration as before reload.");
+            window.scrollTo(0, 0);
+            window.location.hash = "hash";
+            requestAnimationFrame(test);
+            break;
+          }
+          case 5: {
+            opener.isnot(window.scrollY, 0, "Should have scrolled to #hash.");
+            opener.is(history.scrollRestoration, "manual", "Should have the same scrollRestoration mode as before fragment navigation.");
+            window.onunload = function() {} // Disable bfcache.
+            opener.setTimeout("is(testWindow.history.scrollRestoration, 'auto'); testWindow.history.back();", 250);
+            window.location.href = 'data:text/html,';
+            break;
+          }
+          case 6: {
+            opener.is(event.persisted, false, "Shouldn't have persisted session history entry.");
+            opener.is(window.scrollY, 0, "Shouldn't have kept the old scroll position.");
+            opener.is(history.scrollRestoration, "manual", "Should have the same scrollRestoration mode as before fragment navigation.");
+            history.scrollRestoration = "auto";
+            document.getElementById("bottom").scrollIntoView();
+            history.pushState({ state: "state1" }, "state1");
+            history.pushState({ state: "state2" }, "state2");
+            window.scrollTo(0, 0);
+            history.back();
+            opener.isnot(window.scrollY, 0, "Should have scrolled back to the state1's position");
+            opener.is(history.state.state, "state1", "Unexpected state.");
+
+            history.scrollRestoration = "manual";
+            document.getElementById("bottom").scrollIntoView();
+            history.pushState({ state: "state3" }, "state3");
+            history.pushState({ state: "state4" }, "state4");
+            window.scrollTo(0, 0);
+            history.back();
+            opener.is(window.scrollY, 0, "Shouldn't have scrolled back to the state3's position");
+            opener.is(history.state.state, "state3", "Unexpected state.");
+
+            var ifr = document.createElement("iframe");
+            ifr.src = "data:text/html,";
+            document.body.appendChild(ifr);
+            ifr.onload = test;
+            break;
+          }
+          case 7: {
+            oldHistoryObject = event.target.contentWindow.history;
+            event.target.src = "about:blank";
+            break;
+          }
+          case 8: {
+            try {
+              var sr = oldHistoryObject.scrollRestoration;
+              opener.ok(false, "Should have thrown an exception.");
+            } catch(ex) {
+              opener.isnot(ex, null, "Did get an exception");
+            }
+            try {
+              oldHistoryObject.scrollRestoration = "auto";
+              opener.ok(false, "Should have thrown an exception.");
+            } catch(ex) {
+              opener.isnot(ex, null, "Did get an exception");
+            }
+            opener.nextTest();
+            window.close();
+            break;
+          }
+        }
+      }
+
+      window.addEventListener("pageshow",
+          function(e) {
+            setTimeout(test, 0, e);
+          });
+    </script>
+  </head>
+  <body>
+  <div style="border: 1px solid black; height: 5000px;">
+  &nbsp;</div>
+  <div id="bottom">Hello world</div>
+  <a href="#hash" name="hash">hash</a>
+  </body>
+</html>
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -5,16 +5,17 @@ support-files =
   file_bug462076_1.html
   file_bug462076_2.html
   file_bug462076_3.html
   file_bug508537_1.html
   file_bug534178.html
   file_document_write_1.html
   file_fragment_handling_during_load.html
   file_nested_frames.html
+  file_scrollRestoration.html
   file_shiftReload_and_pushState.html
   file_static_and_dynamic_1.html
   frame0.html
   frame1.html
   frame2.html
   frame3.html
   goback.html
   iframe.html
--- a/docshell/test/navigation/test_sessionhistory.html
+++ b/docshell/test/navigation/test_sessionhistory.html
@@ -24,17 +24,18 @@ var testFiles =
     "file_bug462076_2.html",         // Dynamic frames when handling onload
     "file_bug462076_3.html",         // Dynamic frames after onload
     "file_bug508537_1.html",         // Dynamic frames and forward-back
     "file_document_write_1.html",    // Session history + document.write
     //"file_static_and_dynamic_1.html",// Static and dynamic frames and forward-back
     "file_bug534178.html",           // Session history transaction clean-up.
     "file_fragment_handling_during_load.html",
     "file_nested_frames.html",
-    "file_shiftReload_and_pushState.html"
+    "file_shiftReload_and_pushState.html",
+    "file_scrollRestoration.html"
   ];
 var testCount = 0; // Used by the test files.
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.requestFlakyTimeout("untriaged");
 
 var testWindow;
 function nextTest_() {
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -2011,16 +2011,21 @@ KeyframeEffectReadOnly::ShouldBlockCompo
   // to update this to only return true when that is the case since paused,
   // filling, cancelled Animations etc. shouldn't stop other Animations from
   // running on the compositor.
   MOZ_ASSERT(mAnimation && mAnimation->IsPlaying());
 
   bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
 
   for (const AnimationProperty& property : mProperties) {
+    // If a property is overridden in the CSS cascade, it should not block other
+    // animations from running on the compositor.
+    if (!property.mWinsInCascade) {
+      continue;
+    }
     // Check for geometric properties
     if (IsGeometricProperty(property.mProperty)) {
       if (shouldLog) {
         nsCString message;
         message.AppendLiteral("Performance warning: Async animation of "
           "'transform' or 'opacity' not possible due to animation of geometric"
           "properties on the same element");
         AnimationUtils::LogAsyncAnimationFailure(message, aFrame->GetContent());
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -15,16 +15,20 @@
 }
 @keyframes background {
   to { background-color: red; }
 }
 @keyframes rotate {
   from { transform: rotate(0deg); }
   to { transform: rotate(360deg); }
 }
+@keyframes rotate_and_opacity {
+  from { transform: rotate(0deg); opacity: 1;}
+  to { transform: rotate(360deg); opacity: 0;}
+}
 div {
   /* Element needs geometry to be eligible for layerization */
   width: 100px;
   height: 100px;
   background-color: white;
 }
 </style>
 </head>
@@ -260,10 +264,27 @@ promise_test(function(t) {
 
   return animation.ready.then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
        'Transition reports that it is running on the compositor'
        + ' during playback for opacity transition');
   }));
 }, 'isRunningOnCompositor for transitions');
 
+promise_test(function(t) {
+  var div = addDiv(t, { style: 'animation: rotate_and_opacity 100s; ' +
+                               'backface-visibility: hidden; ' +
+                               'transform: none !important;' });
+  var animation = div.getAnimations()[0];
+
+  return animation.ready.then(t.step_func(function() {
+    assert_equals(animation.isRunningOnCompositor, omtaEnabled,
+       'If an animation has a property that can run on the compositor and a '
+       + 'property that cannot (due to Gecko limitations) but where the latter'
+       + 'property is overridden in the CSS cascade, the animation should '
+       + 'still report that it is running on the compositor');
+  }));
+}, 'isRunningOnCompositor is true when a property that would otherwise block ' +
+   'running on the compositor is overridden in the CSS cascade');
+
+</script>
 </script>
 </body>
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -2,17 +2,16 @@
 /* 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 "nsHistory.h"
 
 #include "jsapi.h"
-#include "mozilla/dom/HistoryBinding.h"
 #include "nsCOMPtr.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsIDocShell.h"
 #include "nsIWebNavigation.h"
 #include "nsIURI.h"
@@ -91,16 +90,48 @@ nsHistory::GetLength(ErrorResult& aRv) c
     aRv.Throw(rv);
 
     return 0;
   }
 
   return len >= 0 ? len : 0;
 }
 
+ScrollRestoration
+nsHistory::GetScrollRestoration(mozilla::ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !win->HasActiveDocument() || !win->GetDocShell()) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return mozilla::dom::ScrollRestoration::Auto;
+  }
+
+  bool currentScrollRestorationIsManual = false;
+  win->GetDocShell()->
+    GetCurrentScrollRestorationIsManual(&currentScrollRestorationIsManual);
+  return currentScrollRestorationIsManual ?
+    mozilla::dom::ScrollRestoration::Manual :
+    mozilla::dom::ScrollRestoration::Auto;
+}
+
+void
+nsHistory::SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
+                                mozilla::ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
+  if (!win || !win->HasActiveDocument() || !win->GetDocShell()) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return;
+  }
+
+  win->GetDocShell()->
+    SetCurrentScrollRestorationIsManual(
+      aMode == mozilla::dom::ScrollRestoration::Manual);
+}
+
 void
 nsHistory::GetState(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
                     ErrorResult& aRv) const
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryReferent(mInnerWindow));
   if (!win) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return;
--- a/dom/base/nsHistory.h
+++ b/dom/base/nsHistory.h
@@ -3,16 +3,17 @@
 /* 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 nsHistory_h___
 #define nsHistory_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
+#include "mozilla/dom/HistoryBinding.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDOMHistory.h"
 #include "nsPIDOMWindow.h" // for GetParentObject
 #include "nsStringFwd.h"
 #include "nsWrapperCache.h"
 
 class nsIDocShell;
@@ -31,16 +32,19 @@ public:
 
 public:
   explicit nsHistory(nsPIDOMWindow* aInnerWindow);
 
   nsPIDOMWindow* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   uint32_t GetLength(mozilla::ErrorResult& aRv) const;
+  mozilla::dom::ScrollRestoration GetScrollRestoration(mozilla::ErrorResult& aRv);
+  void SetScrollRestoration(mozilla::dom::ScrollRestoration aMode,
+                            mozilla::ErrorResult& aRv);
   void GetState(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
                 mozilla::ErrorResult& aRv) const;
   void Go(int32_t aDelta, mozilla::ErrorResult& aRv);
   void Back(mozilla::ErrorResult& aRv);
   void Forward(mozilla::ErrorResult& aRv);
   void PushState(JSContext* aCx, JS::Handle<JS::Value> aData,
                  const nsAString& aTitle, const nsAString& aUrl,
                  mozilla::ErrorResult& aRv);
--- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp
+++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp
@@ -148,40 +148,63 @@ GonkGPSGeolocationProvider::LocationCall
   RefPtr<UpdateLocationEvent> event = new UpdateLocationEvent(somewhere);
   NS_DispatchToMainThread(event);
 
 #ifdef MOZ_B2G_RIL
   MozStumble(somewhere);
 #endif
 }
 
+class NotifyObserversGPSTask final : public nsRunnable
+{
+public:
+  explicit NotifyObserversGPSTask(const char16_t* aData)
+    : mData(aData)
+  {}
+  NS_IMETHOD Run() override {
+    RefPtr<nsIGeolocationProvider> provider =
+    GonkGPSGeolocationProvider::GetSingleton();
+    nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
+    obsService->NotifyObservers(provider, "geolocation-device-events", mData);
+    return NS_OK;
+  }
+private:
+  const char16_t* mData;
+};
+
+
+
 void
 GonkGPSGeolocationProvider::StatusCallback(GpsStatus* status)
 {
-  if (gDebug_isLoggingEnabled) {
-    switch (status->status) {
-      case GPS_STATUS_NONE:
-        nsContentUtils::LogMessageToConsole("geo: GPS_STATUS_NONE\n");
-        break;
-      case GPS_STATUS_SESSION_BEGIN:
-        nsContentUtils::LogMessageToConsole("geo: GPS_STATUS_SESSION_BEGIN\n");
-        break;
-      case GPS_STATUS_SESSION_END:
-        nsContentUtils::LogMessageToConsole("geo: GPS_STATUS_SESSION_END\n");
-        break;
-      case GPS_STATUS_ENGINE_ON:
-        nsContentUtils::LogMessageToConsole("geo: GPS_STATUS_ENGINE_ON\n");
-        break;
-      case GPS_STATUS_ENGINE_OFF:
-        nsContentUtils::LogMessageToConsole("geo: GPS_STATUS_ENGINE_OFF\n");
-        break;
-      default:
-        nsContentUtils::LogMessageToConsole("geo: Unknown GPS status\n");
-        break;
-    }
+  const char* msgStream=0;
+  switch (status->status) {
+    case GPS_STATUS_NONE:
+      msgStream = "geo: GPS_STATUS_NONE\n";
+      break;
+    case GPS_STATUS_SESSION_BEGIN:
+      msgStream = "geo: GPS_STATUS_SESSION_BEGIN\n";
+      break;
+    case GPS_STATUS_SESSION_END:
+      msgStream = "geo: GPS_STATUS_SESSION_END\n";
+      break;
+    case GPS_STATUS_ENGINE_ON:
+      msgStream = "geo: GPS_STATUS_ENGINE_ON\n";
+      NS_DispatchToMainThread(new NotifyObserversGPSTask( MOZ_UTF16("GPSStarting")));
+      break;
+    case GPS_STATUS_ENGINE_OFF:
+      msgStream = "geo: GPS_STATUS_ENGINE_OFF\n";
+      NS_DispatchToMainThread(new NotifyObserversGPSTask( MOZ_UTF16("GPSShutdown")));
+      break;
+    default:
+      msgStream = "geo: Unknown GPS status\n";
+      break;
+  }
+  if (gDebug_isLoggingEnabled){
+    nsContentUtils::LogMessageToConsole(msgStream);
   }
 }
 
 void
 GonkGPSGeolocationProvider::SvStatusCallback(GpsSvStatus* sv_info)
 {
   if (gDebug_isLoggingEnabled) {
     static int numSvs = 0;
--- a/dom/webidl/History.webidl
+++ b/dom/webidl/History.webidl
@@ -6,20 +6,24 @@
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/#the-history-interface
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
+enum ScrollRestoration { "auto", "manual" };
+
 interface History {
   [Throws]
   readonly attribute unsigned long length;
   [Throws]
+  attribute ScrollRestoration scrollRestoration;
+  [Throws]
   readonly attribute any state;
   [Throws, UnsafeInPrerendering]
   void go(optional long delta = 0);
   [Throws, UnsafeInPrerendering]
   void back();
   [Throws, UnsafeInPrerendering]
   void forward();
   [Throws]
--- a/gfx/doc/LayersHistory.md
+++ b/gfx/doc/LayersHistory.md
@@ -16,35 +16,45 @@ content across paints in gecko controlle
 the concept of buffer rotation to deal with scrolling instead of using the
 native scrolling APIs like ScrollWindowEx
 
 - Layers IPC (July 2010 - Bug 570294)
 This introduced shadow layers and edit lists and was originally done for e10s v1
 
 - 3d transforms (September 2011 - Bug 505115)
 
-- OMTC (December 2012 - Bug 711168)
+- OMTC (December 2011 - Bug 711168)
 This was prototyped on OS X but shipped first for Fennec
 
 - Tiling v1 (April 2012 - Bug 739679)
 Originally done for Fennec.
 This was done to avoid situations where we had to do a bunch of work for
 scrolling a small amount. i.e. buffer rotation.  It allowed us to have a
 variety of interesting features like progressive painting and lower resolution
 painting.
 
 - C++ Async pan zoom controller (July 2012 - Bug 750974)
 The existing APZ code was in Java for Fennec so this was reimplemented.
 
+- Streaming WebGL Buffers (February 2013 - Bug 716859)
+Infrastructure to allow OMTC WebGL and avoid the need to glFinish() every
+frame.
+
 - Compositor API (April 2013 - Bug 825928)
+The planing for this started around November 2012.
 Layers refactoring created a compositor API that abstracted away the differences between the
 D3D vs OpenGL. The main piece of API is DrawQuad.
 
 - Tiling v2 (Mar 7 2014 - Bug 963073)
 Tiling for B2G. This work is mainly porting tiled layers to new textures,
 implementing double-buffered tiles and implementing a texture client pool, to
 be used by tiled content clients.
 
  A large motivation for the pool was the very slow performance of allocating tiles because
 of the sync messages to the compositor.
 
  The slow performance of allocating was directly addressed by bug 959089 which allowed us
 to allocate gralloc buffers without sync messages to the compositor thread.
+
+- B2G WebGL performance (May 2014 - Bug 1006957, 1001417, 1024144)
+This work improved the synchronization mechanism between the compositor
+and the producer.
+
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -37,16 +37,17 @@
 #include "gfxPrefs.h"
 #if defined(MOZ_WIDGET_ANDROID)
 # include <android/log.h>
 # include "AndroidBridge.h"
 #endif
 #include "GeckoProfiler.h"
 #include "FrameUniformityData.h"
 #include "TreeTraversal.h"
+#include "VsyncSource.h"
 
 struct nsCSSValueSharedList;
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
@@ -1373,17 +1374,16 @@ AsyncCompositionManager::TransformShadow
     // Attempt to apply an async content transform to any layer that has
     // an async pan zoom controller (which means that it is rendered
     // async using Gecko). If this fails, fall back to transforming the
     // primary scrollable layer.  "Failing" here means that we don't
     // find a frame that is async scrollable.  Note that the fallback
     // code also includes Fennec which is rendered async.  Fennec uses
     // its own platform-specific async rendering that is done partially
     // in Gecko and partially in Java.
-    wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), aCurrentFrame);
     bool foundRoot = false;
     Maybe<ParentLayerIntRect> clipDeferredFromChildren;
     if (ApplyAsyncContentTransformToTree(root, &foundRoot, clipDeferredFromChildren)) {
 #if defined(MOZ_ANDROID_APZ)
       MOZ_ASSERT(foundRoot);
       if (foundRoot && mFixedLayerMargins != ScreenMargin()) {
         MoveScrollbarForLayerMargin(root, mRootScrollableId, mFixedLayerMargins);
       }
@@ -1397,16 +1397,25 @@ AsyncCompositionManager::TransformShadow
 #endif
 
       for (uint32_t i = 0; i < scrollableLayers.Length(); i++) {
         if (scrollableLayers[i]) {
           TransformScrollableLayer(scrollableLayers[i]);
         }
       }
     }
+
+    // Advance APZ animations to the next expected vsync timestamp, if we can
+    // get it.
+    TimeStamp nextFrame = aCurrentFrame;
+    TimeDuration vsyncrate = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate();
+    if (vsyncrate != TimeDuration::Forever()) {
+      nextFrame += vsyncrate;
+    }
+    wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), nextFrame);
   }
 
   LayerComposite* rootComposite = root->AsLayerComposite();
 
   gfx::Matrix4x4 trans = rootComposite->GetShadowTransform();
   trans *= gfx::Matrix4x4::From2D(mWorldTransform);
   rootComposite->SetShadowTransform(trans);
 
--- a/ipc/chromium/src/base/process_util_mac.mm
+++ b/ipc/chromium/src/base/process_util_mac.mm
@@ -124,16 +124,17 @@ bool LaunchApp(const std::vector<std::st
     case PROCESS_ARCH_I386:
       cpu_types[0] = CPU_TYPE_X86;
       break;
     case PROCESS_ARCH_X86_64:
       cpu_types[0] = CPU_TYPE_X86_64;
       break;
     case PROCESS_ARCH_PPC:
       cpu_types[0] = CPU_TYPE_POWERPC;
+      break;
     default:
       cpu_types[0] = CPU_TYPE_ANY;
       break;
   }
 
   // Initialize spawn attributes.
   posix_spawnattr_t spawnattr;
   if (posix_spawnattr_init(&spawnattr) != 0) {
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1325,16 +1325,18 @@ if test "$GNU_CXX"; then
     # -Wunused-label - catches unused goto labels
     # -Wunused-value - catches unused expression results
     # -Wwrite-strings - catches non-const char* pointers to string literals
     #
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
 
+    MOZ_CXX_SUPPORTS_WARNING(-W, class-varargs, ac_cxx_has_wclass_varargs)
+
     # Treat some warnings as errors if --enable-warnings-as-errors:
     if test "$MOZ_ENABLE_WARNINGS_AS_ERRORS"; then
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=char-subscripts"
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=comment"
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=endif-labels"
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=ignored-qualifiers"
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=int-to-pointer-cast"
         _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces"
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -1031,17 +1031,17 @@ BacktrackingAllocator::tryMergeReusedReg
     if (!postRange)
         return false;
 
     inputRange->distributeUses(preRange);
     inputRange->distributeUses(postRange);
     MOZ_ASSERT(!inputRange->hasUses());
 
     JitSpew(JitSpew_RegAlloc, "  splitting reused input at %u to try to help grouping",
-            inputOf(def.ins()));
+            inputOf(def.ins()).bits());
 
     LiveBundle* firstBundle = inputRange->bundle();
     input.removeRange(inputRange);
     input.addRange(preRange);
     input.addRange(postRange);
 
     firstBundle->removeRange(inputRange);
     firstBundle->addRange(preRange);
--- a/js/src/jit/Safepoints.cpp
+++ b/js/src/jit/Safepoints.cpp
@@ -160,17 +160,17 @@ MapSlotsToBitset(BitSet& stackSet, BitSe
 
 void
 SafepointWriter::writeGcSlots(LSafepoint* safepoint)
 {
     LSafepoint::SlotList& slots = safepoint->gcSlots();
 
 #ifdef JS_JITSPEW
     for (uint32_t i = 0; i < slots.length(); i++)
-        JitSpew(JitSpew_Safepoints, "    gc slot: %d", slots[i]);
+        JitSpew(JitSpew_Safepoints, "    gc slot: %u", slots[i].slot);
 #endif
 
     MapSlotsToBitset(frameSlots_, argumentSlots_, stream_, slots);
 }
 
 void
 SafepointWriter::writeSlotsOrElementsSlots(LSafepoint* safepoint)
 {
@@ -190,17 +190,17 @@ SafepointWriter::writeSlotsOrElementsSlo
 
 void
 SafepointWriter::writeValueSlots(LSafepoint* safepoint)
 {
     LSafepoint::SlotList& slots = safepoint->valueSlots();
 
 #ifdef JS_JITSPEW
     for (uint32_t i = 0; i < slots.length(); i++)
-        JitSpew(JitSpew_Safepoints, "    gc value: %d", slots[i]);
+        JitSpew(JitSpew_Safepoints, "    gc value: %u", slots[i].slot);
 #endif
 
     MapSlotsToBitset(frameSlots_, argumentSlots_, stream_, slots);
 }
 
 #if defined(JS_JITSPEW) && defined(JS_NUNBOX32)
 static void
 DumpNunboxPart(const LAllocation& a)
--- a/layout/base/AccessibleCaret.cpp
+++ b/layout/base/AccessibleCaret.cpp
@@ -121,17 +121,17 @@ AccessibleCaret::SetAppearance(Appearanc
 
 void
 AccessibleCaret::SetSelectionBarEnabled(bool aEnabled)
 {
   if (mSelectionBarEnabled == aEnabled) {
     return;
   }
 
-  AC_LOG("Set selection bar %s", __FUNCTION__, aEnabled ? "Enabled" : "Disabled");
+  AC_LOG("Set selection bar %s", aEnabled ? "Enabled" : "Disabled");
 
   ErrorResult rv;
   CaretElement()->ClassList()->Toggle(NS_LITERAL_STRING("no-bar"),
                                       Optional<bool>(!aEnabled), rv);
   MOZ_ASSERT(!rv.Failed());
 
   mSelectionBarEnabled = aEnabled;
 }
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2079,16 +2079,21 @@ nsDocumentViewer::Hide(void)
     // and we don't want the presshell n' all that to be thrown away
     // just because the window is hidden.
 
     return NS_OK;
   }
 
   nsCOMPtr<nsIDocShell> docShell(mContainer);
   if (docShell) {
+#ifdef DEBUG
+    nsCOMPtr<nsIContentViewer> currentViewer;
+    docShell->GetContentViewer(getter_AddRefs(currentViewer));
+    MOZ_ASSERT(currentViewer == this);
+#endif
     nsCOMPtr<nsILayoutHistoryState> layoutState;
     mPresShell->CaptureHistoryState(getter_AddRefs(layoutState));
   }
 
   DestroyPresShell();
 
   DestroyPresContext();
 
--- a/layout/base/nsILayoutHistoryState.h
+++ b/layout/base/nsILayoutHistoryState.h
@@ -13,18 +13,18 @@
 
 #include "nsISupports.h"
 #include "nsStringFwd.h"
 
 class nsPresState;
 template<typename> struct already_AddRefed;
 
 #define NS_ILAYOUTHISTORYSTATE_IID \
-{ 0x5208993e, 0xd812, 0x431e, \
-  { 0x95, 0x9c, 0xc3, 0x84, 0x5b, 0x6e, 0x5a, 0xce } }
+{ 0xaef27cb3, 0x4df9, 0x4eeb, \
+  { 0xb0, 0xb0, 0xac, 0x56, 0xcf, 0x86, 0x1d, 0x04 } }
 
 class nsILayoutHistoryState : public nsISupports {
  public: 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ILAYOUTHISTORYSTATE_IID)
 
   /**
    * Set |aState| as the state object for |aKey|.
    * This _transfers_ownership_ of |aState| to the LayoutHistoryState.
@@ -48,16 +48,21 @@ class nsILayoutHistoryState : public nsI
    */
   virtual bool HasStates() const = 0;
 
   /**
    * Sets whether this history can contain only scroll position history
    * or all possible history
    */
   virtual void SetScrollPositionOnly(const bool aFlag) = 0;
+
+  /**
+   * Resets nsPresState::GetScrollState of all nsPresState objects to 0,0.
+   */
+  virtual void ResetScrollState() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsILayoutHistoryState,
                               NS_ILAYOUTHISTORYSTATE_IID)
 
 already_AddRefed<nsILayoutHistoryState>
 NS_NewLayoutHistoryState();
 
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -165,35 +165,37 @@ PrintDisplayItemTo(nsDisplayListBuilder*
   nsRect rect = aItem->GetBounds(aBuilder, &snap);
   nsRect layerRect = rect - (*aItem->GetAnimatedGeometryRoot())->GetOffsetToCrossDoc(aItem->ReferenceFrame());
   nscolor color;
   nsRect vis = aItem->GetVisibleRect();
   nsRect component = aItem->GetComponentAlphaBounds(aBuilder);
   nsDisplayList* list = aItem->GetChildren();
   const DisplayItemClip& clip = aItem->GetClip();
   nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
+
 #ifdef MOZ_DUMP_PAINTING
   if (aDumpHtml && aItem->Painted()) {
     nsCString string(aItem->Name());
     string.Append('-');
     string.AppendInt((uint64_t)aItem);
     aStream << nsPrintfCString("<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
   }
 #endif
+
   aStream << nsPrintfCString("%s p=0x%p f=0x%p(%s) %sbounds(%d,%d,%d,%d) layerBounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) scrollClip(%s)%s ref=0x%p agr=0x%p",
           aItem->Name(), aItem, (void*)f, NS_ConvertUTF16toUTF8(contentData).get(),
           (aItem->ZIndex() ? nsPrintfCString("z=%d ", aItem->ZIndex()).get() : ""),
           rect.x, rect.y, rect.width, rect.height,
           layerRect.x, layerRect.y, layerRect.width, layerRect.height,
           vis.x, vis.y, vis.width, vis.height,
           component.x, component.y, component.width, component.height,
           clip.ToString().get(),
           DisplayItemScrollClip::ToString(aItem->ScrollClip()).get(),
           aItem->IsUniform(aBuilder, &color) ? " uniform" : "",
-          aItem->ReferenceFrame(), *aItem->GetAnimatedGeometryRoot());
+          aItem->ReferenceFrame(), aItem->GetAnimatedGeometryRoot());
 
   nsRegionRectIterator iter(opaque);
   for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
     aStream << nsPrintfCString(" (opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height);
   }
 
   if (aItem->ShouldFixToViewport(aBuilder)) {
     aStream << " fixed";
--- a/layout/base/nsLayoutHistoryState.cpp
+++ b/layout/base/nsLayoutHistoryState.cpp
@@ -31,17 +31,18 @@ public:
   virtual nsPresState*
   GetState(const nsCString& aKey) override;
   virtual void
   RemoveState(const nsCString& aKey) override;
   virtual bool
   HasStates() const override;
   virtual void
   SetScrollPositionOnly(const bool aFlag) override;
-
+  virtual void
+  ResetScrollState() override;
 
 private:
   ~nsLayoutHistoryState() {}
   bool mScrollPositionOnly;
 
   nsClassHashtable<nsCStringHashKey,nsPresState> mStates;
 };
 
@@ -89,8 +90,19 @@ nsLayoutHistoryState::HasStates() const
   return mStates.Count() != 0;
 }
 
 void
 nsLayoutHistoryState::SetScrollPositionOnly(const bool aFlag)
 {
   mScrollPositionOnly = aFlag;
 }
+
+void
+nsLayoutHistoryState::ResetScrollState()
+{
+  for (auto iter = mStates.Iter(); !iter.Done(); iter.Next()) {
+    nsPresState* state = iter.UserData();
+    if (state) {
+      state->SetScrollState(nsPoint(0, 0));
+    }
+  }
+}
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -418,17 +418,17 @@ nsContainerFrame::CreateViewForFrame(nsI
   // parent view.
   ReparentFrameViewTo(aFrame, viewManager, view, parentView);
 
   // Remember our view
   aFrame->SetView(view);
 
   NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
                ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
-                aFrame));
+                aFrame, view));
 }
 
 /**
  * Position the view associated with |aKidFrame|, if there is one. A
  * container frame should call this method after positioning a frame,
  * but before |Reflow|.
  */
 void
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -12,16 +12,17 @@
 #include "mozilla/dom/FontFaceSetBinding.h"
 #include "mozilla/dom/FontFaceSetIterator.h"
 #include "mozilla/dom/FontFaceSetLoadEvent.h"
 #include "mozilla/dom/FontFaceSetLoadEventBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/SizePrintfMacros.h"
 #include "mozilla/Snprintf.h"
 #include "mozilla/Telemetry.h"
 #include "nsCORSListenerProxy.h"
 #include "nsCSSParser.h"
 #include "nsDeviceContext.h"
 #include "nsFontFaceLoader.h"
 #include "nsIConsoleService.h"
 #include "nsIContentPolicy.h"
@@ -787,17 +788,17 @@ FontFaceSet::UpdateRules(const nsTArray<
     CheckLoadingStarted();
     CheckLoadingFinished();
   }
 
   // local rules have been rebuilt, so clear the flag
   mUserFontSet->mLocalRulesUsed = false;
 
   if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) {
-    LOG(("userfonts (%p) userfont rules update (%s) rule count: %d",
+    LOG(("userfonts (%p) userfont rules update (%s) rule count: %" PRIuSIZE,
          mUserFontSet.get(),
          (modified ? "modified" : "not modified"),
          mRuleFaces.Length()));
   }
 
   return modified;
 }
 
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1808,27 +1808,27 @@ Loader::SheetComplete(SheetLoadData* aLo
   uint32_t count = datasToNotify.Length();
   mDatasToNotifyOn += count;
   for (uint32_t i = 0; i < count; ++i) {
     --mDatasToNotifyOn;
 
     SheetLoadData* data = datasToNotify[i];
     NS_ASSERTION(data && data->mMustNotify, "How did this data get here?");
     if (data->mObserver) {
-      LOG(("  Notifying observer 0x%x for data 0x%x.  wasAlternate: %d",
+      LOG(("  Notifying observer %p for data %p.  wasAlternate: %d",
            data->mObserver.get(), data, data->mWasAlternate));
       data->mObserver->StyleSheetLoaded(data->mSheet, data->mWasAlternate,
                                         aStatus);
     }
 
     nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> >::ForwardIterator iter(mObservers);
     nsCOMPtr<nsICSSLoaderObserver> obs;
     while (iter.HasMore()) {
       obs = iter.GetNext();
-      LOG(("  Notifying global observer 0x%x for data 0x%s.  wasAlternate: %d",
+      LOG(("  Notifying global observer %p for data %p.  wasAlternate: %d",
            obs.get(), data, data->mWasAlternate));
       obs->StyleSheetLoaded(data->mSheet, data->mWasAlternate, aStatus);
     }
   }
 
   if (mSheets->mLoadingDatas.Count() == 0 && mSheets->mPendingDatas.Count() > 0) {
     LOG(("  No more loading sheets; starting alternates"));
     StartAlternateLoads();
--- a/media/mtransport/transportlayerdtls.cpp
+++ b/media/mtransport/transportlayerdtls.cpp
@@ -864,16 +864,17 @@ void TransportLayerDtls::Handshake() {
     TL_SET_STATE(TS_OPEN);
   } else {
     int32_t err = PR_GetError();
     switch(err) {
       case SSL_ERROR_RX_MALFORMED_HANDSHAKE:
         MOZ_MTLOG(ML_ERROR, LAYER_INFO << "Malformed DTLS message; ignoring");
         // If this were TLS (and not DTLS), this would be fatal, but
         // here we're required to ignore bad messages, so fall through
+        MOZ_FALLTHROUGH;
       case PR_WOULD_BLOCK_ERROR:
         MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "Handshake would have blocked");
         PRIntervalTime timeout;
         rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout);
         if (rv == SECSuccess) {
           uint32_t timeout_ms = PR_IntervalToMilliseconds(timeout);
 
           MOZ_MTLOG(ML_DEBUG,
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -751,20 +751,24 @@ SessionStore.prototype = {
     if (aEntry.referrerURI) {
       entry.referrer = aEntry.referrerURI.spec;
     }
 
     if (aEntry.contentType) {
       entry.contentType = aEntry.contentType;
     }
 
-    let x = {}, y = {};
-    aEntry.getScrollPosition(x, y);
-    if (x.value != 0 || y.value != 0) {
-      entry.scroll = x.value + "," + y.value;
+    if (aEntry.scrollRestorationIsManual) {
+      entry.scrollRestorationIsManual = true;
+    } else {
+      let x = {}, y = {};
+      aEntry.getScrollPosition(x, y);
+      if (x.value != 0 || y.value != 0) {
+        entry.scroll = x.value + "," + y.value;
+      }
     }
 
     if (aEntry.owner) {
       try {
         let binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIObjectOutputStream);
         let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
         pipe.init(false, false, 0, 0xffffffff, null);
         binaryStream.setOutputStream(pipe.outputStream);
@@ -857,17 +861,19 @@ SessionStore.prototype = {
     if (aEntry.structuredCloneState && aEntry.structuredCloneVersion) {
       shEntry.stateData =
         Cc["@mozilla.org/docshell/structured-clone-container;1"].
         createInstance(Ci.nsIStructuredCloneContainer);
 
       shEntry.stateData.initFromBase64(aEntry.structuredCloneState, aEntry.structuredCloneVersion);
     }
 
-    if (aEntry.scroll) {
+    if (aEntry.scrollRestorationIsManual) {
+      shEntry.scrollRestorationIsManual = true;
+    } else if (aEntry.scroll) {
       let scrollPos = aEntry.scroll.split(",");
       scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
       shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
     }
 
     let childDocIdents = {};
     if (aEntry.docIdentifier) {
       // If we have a serialized document identifier, try to find an SHEntry
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -11,16 +11,17 @@
 #pragma warning( disable : 4275 4530 ) // See msvc-stl-wrapper.template.h
 #include <map>
 #pragma warning( pop )
 
 #define MOZ_NO_MOZALLOC
 #include "nsAutoPtr.h"
 
 #include "nsWindowsDllInterceptor.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/WindowsVersion.h"
 #include "nsWindowsHelpers.h"
 
 using namespace mozilla;
 
 #define ALL_VERSIONS   ((unsigned long long)-1LL)
 
 // DLLs sometimes ship without a version number, particularly early
@@ -473,40 +474,40 @@ DllBlockSet::Write(HANDLE file)
       WriteFile(file, ";", 1, &nBytes, nullptr);
     }
   }
   MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { }
 
   ::LeaveCriticalSection(&sLock);
 }
 
-static
-wchar_t* getFullPath (PWCHAR filePath, wchar_t* fname)
+static UniquePtr<wchar_t[]>
+getFullPath (PWCHAR filePath, wchar_t* fname)
 {
   // In Windows 8, the first parameter seems to be used for more than just the
   // path name.  For example, its numerical value can be 1.  Passing a non-valid
   // pointer to SearchPathW will cause a crash, so we need to check to see if we
   // are handed a valid pointer, and otherwise just pass nullptr to SearchPathW.
   PWCHAR sanitizedFilePath = (intptr_t(filePath) < 4096) ? nullptr : filePath;
 
   // figure out the length of the string that we need
   DWORD pathlen = SearchPathW(sanitizedFilePath, fname, L".dll", 0, nullptr,
                               nullptr);
   if (pathlen == 0) {
     return nullptr;
   }
 
-  wchar_t* full_fname = new wchar_t[pathlen+1];
+  auto full_fname = MakeUnique<wchar_t[]>(pathlen+1);
   if (!full_fname) {
     // couldn't allocate memory?
     return nullptr;
   }
 
   // now actually grab it
-  SearchPathW(sanitizedFilePath, fname, L".dll", pathlen + 1, full_fname,
+  SearchPathW(sanitizedFilePath, fname, L".dll", pathlen + 1, full_fname.get(),
               nullptr);
   return full_fname;
 }
 
 // No builtin function to find the last character matching a set
 static wchar_t* lastslash(wchar_t* s, int len)
 {
   for (wchar_t* c = s + len - 1; c >= s; --c) {
@@ -524,17 +525,17 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
 #define DLLNAME_MAX 128
   char dllName[DLLNAME_MAX+1];
   wchar_t *dll_part;
   char *dot;
   DllBlockInfo *info;
 
   int len = moduleFileName->Length / 2;
   wchar_t *fname = moduleFileName->Buffer;
-  nsAutoArrayPtr<wchar_t> full_fname;
+  UniquePtr<wchar_t[]> full_fname;
 
   // The filename isn't guaranteed to be null terminated, but in practice
   // it always will be; ensure that this is so, and bail if not.
   // This is done instead of the more robust approach because of bug 527122,
   // where lots of weird things were happening when we tried to make a copy.
   if (moduleFileName->MaximumLength < moduleFileName->Length+2 ||
       fname[len] != 0)
   {
@@ -647,33 +648,33 @@ patched_LdrLoadDll (PWCHAR filePath, PUL
       full_fname = getFullPath(filePath, fname);
       if (!full_fname) {
         // uh, we couldn't find the DLL at all, so...
         printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
         return STATUS_DLL_NOT_FOUND;
       }
 
       if (info->flags & DllBlockInfo::USE_TIMESTAMP) {
-        fVersion = GetTimestamp(full_fname);
+        fVersion = GetTimestamp(full_fname.get());
         if (fVersion > info->maxVersion) {
           load_ok = true;
         }
       } else {
         DWORD zero;
-        DWORD infoSize = GetFileVersionInfoSizeW(full_fname, &zero);
+        DWORD infoSize = GetFileVersionInfoSizeW(full_fname.get(), &zero);
 
         // If we failed to get the version information, we block.
 
         if (infoSize != 0) {
-          nsAutoArrayPtr<unsigned char> infoData(new unsigned char[infoSize]);
+          auto infoData = MakeUnique<unsigned char[]>(infoSize);
           VS_FIXEDFILEINFO *vInfo;
           UINT vInfoLen;
 
-          if (GetFileVersionInfoW(full_fname, 0, infoSize, infoData) &&
-              VerQueryValueW(infoData, L"\\", (LPVOID*) &vInfo, &vInfoLen))
+          if (GetFileVersionInfoW(full_fname.get(), 0, infoSize, infoData.get()) &&
+              VerQueryValueW(infoData.get(), L"\\", (LPVOID*) &vInfo, &vInfoLen))
           {
             fVersion =
               ((unsigned long long)vInfo->dwFileVersionMS) << 32 |
               ((unsigned long long)vInfo->dwFileVersionLS);
 
             // finally do the version check, and if it's greater than our block
             // version, keep loading
             if (fVersion > info->maxVersion)
@@ -699,17 +700,17 @@ continue_loading:
     // Check to ensure that the DLL has ASLR.
     full_fname = getFullPath(filePath, fname);
     if (!full_fname) {
       // uh, we couldn't find the DLL at all, so...
       printf_stderr("LdrLoadDll: Blocking load of '%s' (SearchPathW didn't find it?)\n", dllName);
       return STATUS_DLL_NOT_FOUND;
     }
 
-    if (IsVistaOrLater() && !CheckASLR(full_fname)) {
+    if (IsVistaOrLater() && !CheckASLR(full_fname.get())) {
       printf_stderr("LdrLoadDll: Blocking load of '%s'.  XPCOM components must support ASLR.\n", dllName);
       return STATUS_DLL_NOT_FOUND;
     }
   }
 
   return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
 }
 
--- a/netwerk/protocol/res/nsResProtocolHandler.cpp
+++ b/netwerk/protocol/res/nsResProtocolHandler.cpp
@@ -16,56 +16,37 @@
 #include "nsEscape.h"
 
 #include "mozilla/Omnijar.h"
 
 using mozilla::dom::ContentParent;
 using mozilla::LogLevel;
 using mozilla::Unused;
 
-#define kAPP           NS_LITERAL_CSTRING("app")
-#define kGRE           NS_LITERAL_CSTRING("gre")
+#define kAPP           "app"
+#define kGRE           "gre"
 
 nsresult
 nsResProtocolHandler::Init()
 {
     nsresult rv;
-    nsAutoCString appURI, greURI;
-    rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, appURI);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE, greURI);
+    rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, mAppURI);
     NS_ENSURE_SUCCESS(rv, rv);
-
-    //
-    // make resource:/// point to the application directory or omnijar
-    //
-    nsCOMPtr<nsIURI> uri;
-    rv = NS_NewURI(getter_AddRefs(uri), appURI.Length() ? appURI : greURI);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = SetSubstitution(EmptyCString(), uri);
+    rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE, mGREURI);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    //
-    // make resource://app/ point to the application directory or omnijar
-    //
-    rv = SetSubstitution(kAPP, uri);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    //
-    // make resource://gre/ point to the GRE directory
-    //
-    if (appURI.Length()) { // We already have greURI in uri if appURI.Length() is 0.
-        rv = NS_NewURI(getter_AddRefs(uri), greURI);
-        NS_ENSURE_SUCCESS(rv, rv);
+    // mozilla::Omnijar::GetURIString always returns a string ending with /,
+    // and we want to remove it.
+    mGREURI.Truncate(mGREURI.Length() - 1);
+    if (mAppURI.Length()) {
+      mAppURI.Truncate(mAppURI.Length() - 1);
+    } else {
+      mAppURI = mGREURI;
     }
 
-    rv = SetSubstitution(kGRE, uri);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     //XXXbsmedberg Neil wants a resource://pchrome/ for the profile chrome dir...
     // but once I finish multiple chrome registration I'm not sure that it is needed
 
     // XXX dveditz: resource://pchrome/ defeats profile directory salting
     // if web content can load it. Tread carefully.
 
     return rv;
 }
@@ -78,25 +59,41 @@ NS_IMPL_QUERY_INTERFACE(nsResProtocolHan
                         nsISubstitutingProtocolHandler, nsIProtocolHandler,
                         nsISupportsWeakReference)
 NS_IMPL_ADDREF_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler)
 NS_IMPL_RELEASE_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler)
 
 nsresult
 nsResProtocolHandler::GetSubstitutionInternal(const nsACString& root, nsIURI **result)
 {
-    // try invoking the directory service for "resource:root"
+    nsAutoCString uri;
 
-    nsAutoCString key;
-    key.AssignLiteral("resource:");
-    key.Append(root);
+    if (!ResolveSpecialCases(root, NS_LITERAL_CSTRING("/"), uri)) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    return NS_NewURI(result, uri);
+}
 
-    nsCOMPtr<nsIFile> file;
-    nsresult rv = NS_GetSpecialDirectory(key.get(), getter_AddRefs(file));
-    if (NS_FAILED(rv))
-        return NS_ERROR_NOT_AVAILABLE;
-        
-    rv = IOService()->NewFileURI(file, result);
-    if (NS_FAILED(rv))
-        return NS_ERROR_NOT_AVAILABLE;
+bool
+nsResProtocolHandler::ResolveSpecialCases(const nsACString& aHost,
+                                          const nsACString& aPath,
+                                          nsACString& aResult)
+{
+    if (aHost.Equals("") || aHost.Equals(kAPP)) {
+        aResult.Assign(mAppURI);
+    } else if (aHost.Equals(kGRE)) {
+        aResult.Assign(mGREURI);
+    } else {
+        return false;
+    }
+    aResult.Append(aPath);
+    return true;
+}
 
-    return NS_OK;
+nsresult
+nsResProtocolHandler::SetSubstitution(const nsACString& aRoot, nsIURI* aBaseURI)
+{
+    MOZ_ASSERT(!aRoot.Equals(""));
+    MOZ_ASSERT(!aRoot.Equals(kAPP));
+    MOZ_ASSERT(!aRoot.Equals(kGRE));
+    return SubstitutingProtocolHandler::SetSubstitution(aRoot, aBaseURI);
 }
--- a/netwerk/protocol/res/nsResProtocolHandler.h
+++ b/netwerk/protocol/res/nsResProtocolHandler.h
@@ -18,23 +18,46 @@ class nsResProtocolHandler final : publi
                                    public mozilla::SubstitutingProtocolHandler,
                                    public nsSupportsWeakReference
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIRESPROTOCOLHANDLER
 
     NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::)
-    NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::)
 
     nsResProtocolHandler()
       : SubstitutingProtocolHandler("resource", URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE,
                                     /* aEnforceFileOrJar = */ false)
     {}
 
     nsresult Init();
 
+    NS_IMETHOD SetSubstitution(const nsACString& aRoot, nsIURI* aBaseURI) override;
+
+    NS_IMETHOD GetSubstitution(const nsACString& aRoot, nsIURI** aResult) override
+    {
+        return mozilla::SubstitutingProtocolHandler::GetSubstitution(aRoot, aResult);
+    }
+
+    NS_IMETHOD HasSubstitution(const nsACString& aRoot, bool* aResult) override
+    {
+        return mozilla::SubstitutingProtocolHandler::HasSubstitution(aRoot, aResult);
+    }
+
+    NS_IMETHOD ResolveURI(nsIURI *aResURI, nsACString& aResult) override
+    {
+        return mozilla::SubstitutingProtocolHandler::ResolveURI(aResURI, aResult);
+    }
+
 protected:
     nsresult GetSubstitutionInternal(const nsACString& aRoot, nsIURI** aResult) override;
     virtual ~nsResProtocolHandler() {}
+
+    bool ResolveSpecialCases(const nsACString& aHost, const nsACString& aPath,
+                             nsACString& aResult) override;
+
+private:
+    nsCString mAppURI;
+    nsCString mGREURI;
 };
 
 #endif /* nsResProtocolHandler_h___ */
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -5078,17 +5078,17 @@ nsWindow::ProcessMessage(UINT msg, WPARA
         *aRetValue = 1;
         result = true;
       }
       break;
 
     case WM_MOUSEMOVE:
     {
       if (!mMousePresent) {
-        // First MOOUSEMOVE over the client area. Ask for MOUSELEAVE
+        // First MOUSEMOVE over the client area. Ask for MOUSELEAVE
         TRACKMOUSEEVENT mTrack;
         mTrack.cbSize = sizeof(TRACKMOUSEEVENT);
         mTrack.dwFlags = TME_LEAVE;
         mTrack.dwHoverTime = 0;
         mTrack.hwndTrack = mWnd;
         TrackMouseEvent(&mTrack);
       }
       mMousePresent = true;