Bug 597315 Part 2 (session restore) - Frameset history does not work properly when restoring a tab [r=dietrich, a=blocking2.0:betaN+]
authorPaul O’Shannessy <paul@oshannessy.com>
Mon, 27 Dec 2010 16:22:47 -0500
changeset 59695 e736115286a855d64331db958f019b5203cf0cca
parent 59694 93a8fb0292bab50e6b1816ef49d531531e48131f
child 59696 8531d0ed4546193a9d174f35c337463448088ee2
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersdietrich, blocking2
bugs597315
milestone2.0b9pre
Bug 597315 Part 2 (session restore) - Frameset history does not work properly when restoring a tab [r=dietrich, a=blocking2.0:betaN+]
browser/components/sessionstore/src/nsSessionStore.js
browser/components/sessionstore/test/browser/Makefile.in
browser/components/sessionstore/test/browser/browser_597315.js
browser/components/sessionstore/test/browser/browser_597315_a.html
browser/components/sessionstore/test/browser/browser_597315_b.html
browser/components/sessionstore/test/browser/browser_597315_c.html
browser/components/sessionstore/test/browser/browser_597315_c1.html
browser/components/sessionstore/test/browser/browser_597315_c2.html
browser/components/sessionstore/test/browser/browser_597315_index.html
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -1578,16 +1578,17 @@ SessionStoreService.prototype = {
     var cacheKey = aEntry.cacheKey;
     if (cacheKey && cacheKey instanceof Ci.nsISupportsPRUint32 &&
         cacheKey.data != 0) {
       // XXXbz would be better to have cache keys implement
       // nsISerializable or something.
       entry.cacheKey = cacheKey.data;
     }
     entry.ID = aEntry.ID;
+    entry.docshellID = aEntry.docshellID;
     
     if (aEntry.referrerURI)
       entry.referrer = aEntry.referrerURI.spec;
 
     if (aEntry.contentType)
       entry.contentType = aEntry.contentType;
     
     var x = {}, y = {};
@@ -2693,17 +2694,22 @@ SessionStoreService.prototype = {
       // restore those aspects of the currently active documents which are not
       // preserved in the plain history entries (mainly scroll state and text data)
       browser.__SS_restore_data = tabData.entries[activeIndex] || {};
       browser.__SS_restore_pageStyle = tabData.pageStyle || "";
       browser.__SS_restore_tab = aTab;
 
       didStartLoad = true;
       try {
-        browser.webNavigation.gotoIndex(activeIndex);
+        // In order to work around certain issues in session history, we need to
+        // force session history to update its internal index and call reload
+        // instead of gotoIndex. c.f. bug 597315
+        browser.webNavigation.sessionHistory.getEntryAtIndex(activeIndex, true);
+        browser.webNavigation.sessionHistory.
+          QueryInterface(Ci.nsISHistory_2_0_BRANCH).reloadCurrentEntry();
       }
       catch (ex) {
         // ignore page load errors
         aTab.removeAttribute("busy");
         didStartLoad = false;
       }
     }
 
@@ -2808,16 +2814,19 @@ SessionStoreService.prototype = {
       if (!id) {
         for (id = Date.now(); id in aIdMap.used; id++);
         aIdMap[aEntry.ID] = id;
         aIdMap.used[id] = true;
       }
       shEntry.ID = id;
     }
 
+    if (aEntry.docshellID)
+      shEntry.docshellID = aEntry.docshellID;
+
     if (aEntry.stateData) {
       shEntry.stateData = aEntry.stateData;
     }
 
     if (aEntry.scroll) {
       var scrollPos = (aEntry.scroll || "0,0").split(",");
       scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
       shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -117,16 +117,23 @@ include $(topsrcdir)/config/rules.mk
 	browser_579868.js \
 	browser_579879.js \
 	browser_580512.js \
 	browser_581593.js \
 	browser_586147.js \
 	browser_586068-cascaded_restore.js \
 	browser_589246.js \
 	browser_590268.js \
+	browser_597315.js \
+	browser_597315_index.html \
+	browser_597315_a.html \
+	browser_597315_b.html \
+	browser_597315_c.html \
+	browser_597315_c1.html \
+	browser_597315_c2.html \
 	browser_600545.js \
 	browser_607016.js \
 	$(NULL)
 
 ifneq ($(OS_ARCH),Darwin)
 _BROWSER_TEST_FILES += \
 	browser_597071.js \
 	$(NULL)
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_597315.js
@@ -0,0 +1,95 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is sessionstore test code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Paul O’Shannessy <paul@oshannessy.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+Cu.import("resource://gre/modules/Services.jsm");
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+         getService(Ci.nsISessionStore);
+
+function test() {
+  /** Test for Bug 597315 - Frameset history does not work properly when restoring a tab **/
+  waitForExplicitFinish();
+
+  let testURL = getRootDirectory(gTestPath) + "browser_597315_index.html";
+  let tab = gBrowser.addTab(testURL);
+  gBrowser.selectedTab = tab;
+
+  waitForLoadsInBrowser(tab.linkedBrowser, 4, function() {
+    let browser_b = tab.linkedBrowser.contentDocument.getElementsByTagName("frame")[1];
+    let document_b = browser_b.contentDocument;
+    let links = document_b.getElementsByTagName("a");
+
+    // We're going to click on the first link, so listen for another load event
+    waitForLoadsInBrowser(tab.linkedBrowser, 1, function() {
+      waitForLoadsInBrowser(tab.linkedBrowser, 1, function() {
+
+        gBrowser.removeTab(tab);
+        // wait for 4 loads again...
+        let newTab = ss.undoCloseTab(window, 0);
+
+        waitForLoadsInBrowser(newTab.linkedBrowser, 4, function() {
+          gBrowser.goBack();
+          waitForLoadsInBrowser(newTab.linkedBrowser, 1, function() {
+
+            let expectedURLEnds = ["a.html", "b.html", "c1.html"];
+            let frames = newTab.linkedBrowser.contentDocument.getElementsByTagName("frame");
+            for (let i = 0; i < frames.length; i++) {
+              is(frames[i].contentDocument.location,
+                 getRootDirectory(gTestPath) + "browser_597315_" + expectedURLEnds[i],
+                 "frame " + i + " has the right url");
+            }
+            gBrowser.removeTab(newTab);
+            executeSoon(finish);
+          });
+        });
+      });
+      EventUtils.sendMouseEvent({type:"click"}, links[1], browser_b.contentWindow);
+    });
+    EventUtils.sendMouseEvent({type:"click"}, links[0], browser_b.contentWindow);
+  });
+}
+
+// helper function
+function waitForLoadsInBrowser(aBrowser, aLoadCount, aCallback) {
+  let loadCount = 0;
+  aBrowser.addEventListener("load", function(aEvent) {
+    if (++loadCount < aLoadCount)
+      return;
+
+    aBrowser.removeEventListener("load", arguments.callee, true);
+    aCallback();
+  }, true);
+}
new file mode 100755
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_597315_a.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    I'm A!
+  </body>
+</html>
new file mode 100755
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_597315_b.html
@@ -0,0 +1,10 @@
+<html>
+  <body>
+    I'm B!<br/>
+    <a target="c" href="browser_597315_c1.html">click me first</a><br/>
+    <a target="c" href="browser_597315_c2.html">then click me</a><br/>
+    Close this tab.<br/>
+    Restore this tab.<br/>
+    Click back.<br/>
+  </body>
+</html>
new file mode 100755
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_597315_c.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    I'm C!
+  </body>
+</html>
new file mode 100755
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_597315_c1.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    I'm C1!
+  </body>
+</html>
new file mode 100755
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_597315_c2.html
@@ -0,0 +1,5 @@
+<html>
+  <body>
+    I'm C2!
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_597315_index.html
@@ -0,0 +1,10 @@
+<html>
+  <frameset cols="20%,80%">
+    <frameset rows="30%,70%">
+      <frame src="browser_597315_a.html"/>
+      <frame src="browser_597315_b.html"/>
+    </frameset>
+    <frame src="browser_597315_c.html" name="c"/>
+  </frameset>
+</html>
+