Bug 1750973, don't replace the nsILayoutHistoryState object when doing same document history navigations, r=peterv a=RyanVM
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Fri, 04 Feb 2022 11:37:14 +0000
changeset 678364 ddfc73cee5fde6259489573850abfb6df666ba8b
parent 678363 bb5ecdace89bb89b41d6a37d5c2303986db7bd37
child 678365 0d9f7b8a7c3b49e91872fd3340084895677f9044
push id2767
push userryanvm@gmail.com
push dateWed, 16 Feb 2022 14:27:41 +0000
treeherdermozilla-release@b881a697c484 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, RyanVM
bugs1750973
milestone97.0.1
Bug 1750973, don't replace the nsILayoutHistoryState object when doing same document history navigations, r=peterv a=RyanVM Differential Revision: https://phabricator.services.mozilla.com/D137703
docshell/base/nsDocShell.cpp
docshell/test/navigation/file_bug1750973.html
docshell/test/navigation/mochitest.ini
docshell/test/navigation/test_bug1750973.html
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8874,17 +8874,30 @@ nsresult nsDocShell::HandleSameDocumentN
   } else {
     if (aLoadState->LoadIsFromSessionHistory()) {
       MOZ_LOG(
           gSHLog, LogLevel::Debug,
           ("Moving the loading entry to the active entry on nsDocShell %p to "
            "%s",
            this, mLoadingEntry->mInfo.GetURI()->GetSpecOrDefault().get()));
       bool hadActiveEntry = !!mActiveEntry;
+
+      nsCOMPtr<nsILayoutHistoryState> currentLayoutHistoryState;
+      if (mActiveEntry) {
+        currentLayoutHistoryState = mActiveEntry->GetLayoutHistoryState();
+      }
       mActiveEntry = MakeUnique<SessionHistoryInfo>(mLoadingEntry->mInfo);
+      if (currentLayoutHistoryState) {
+        // Restore the existing nsILayoutHistoryState object, since it is
+        // possibly being used by the layout. When doing a new load, the
+        // shared state is copied from the existing active entry, so this
+        // special case is needed only with the history loads.
+        mActiveEntry->SetLayoutHistoryState(currentLayoutHistoryState);
+      }
+
       // We're passing in mCurrentURI, which could be null. SessionHistoryCommit
       // does require a non-null uri if this is for a refresh load of the same
       // URI, but in that case mCurrentURI won't be null here.
       mBrowsingContext->SessionHistoryCommit(
           *mLoadingEntry, mLoadType, mCurrentURI, hadActiveEntry, true, true,
           /* No expiration update on the same document loads*/
           false);
       // FIXME Need to set postdata.
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/file_bug1750973.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <script>
+    function test() {
+      history.scrollRestoration = "manual";
+      document.getElementById("initialfocus").focus();
+      history.pushState('data', '', '');
+      history.back();
+    }
+
+    window.onpopstate = function() {
+      window.onscroll = function() {
+        window.onscroll = null;
+        document.documentElement.style.display = "none";
+        // focus() triggers recreation of the nsIFrames without a reflow.
+        document.getElementById("focustarget").focus();
+        document.documentElement.style.display = "";
+        // Flush the layout.
+        document.documentElement.getBoundingClientRect();
+        opener.isnot(window.scrollY, 0, "The page should have been scrolled down(1)");
+        requestAnimationFrame(
+          function() {
+            // Extra timeout to ensure we're called after rAF has triggered a
+            // reflow.
+            setTimeout(function() {
+              opener.isnot(window.scrollY, 0, "The page should have been scrolled down(2)");
+              window.close();
+              opener.SimpleTest.finish();
+            });
+        });
+      }
+      window.scrollTo(0, 1000);
+    }
+  </script>
+</head>
+<body onload="setTimeout(test)">
+<div style="position: fixed;">
+  <input type="button" value="" id="initialfocus">
+  <input type="button" value="" id="focustarget">
+</div>
+<div style="border: 1px solid black; width: 100px; height: 9000px;"></div>
+</body>
+</html>
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -93,16 +93,18 @@ support-files =
 [test_beforeunload_and_bfcache.html]
 support-files = file_beforeunload_and_bfcache.html
 [test_bug13871.html]
 [test_bug1583110.html]
 support-files = file_bug1583110.html
 [test_bug1706090.html]
 support-files = file_bug1706090.html
 skip-if = fission # The test is currently for the old bfcache implementation
+[test_bug1750973.html]
+support-files = file_bug1750973.html
 [test_bug270414.html]
 [test_bug278916.html]
 [test_bug279495.html]
 [test_bug344861.html]
 skip-if = toolkit == "android"
 [test_bug386782.html]
 [test_bug430624.html]
 [test_bug430723.html]
new file mode 100644
--- /dev/null
+++ b/docshell/test/navigation/test_bug1750973.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>The layout state restoration when reframing the root element</title>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+  <script>
+    SimpleTest.waitForExplicitFinish();
+    function test() {
+      window.open("file_bug1750973.html");
+    }
+  </script>
+</head>
+<body onload="setTimeout(test)">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>