+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ Update expected results of old tests:
+ * fast/dom/Window/window-appendages-cleared-expected.txt:
+ * fast/dom/Window/window-properties-expected.txt:
+ * http/tests/security/cross-frame-access-enumeration-expected.txt:
+
+ New tests:
+ * fast/loader/stateobjects: Added.
+ * fast/loader/stateobjects/document-destroyed-navigate-back-expected.txt: Added.
+ * fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll-expected.txt: Added.
+ * fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html: Added.
+ * fast/loader/stateobjects/document-destroyed-navigate-back.html: Added.
+ * fast/loader/stateobjects/popstate-after-load-complete-addeventlistener-expected.txt: Added.
+ * fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html: Added.
+ * fast/loader/stateobjects/popstate-after-load-complete-body-attribute-expected.txt: Added.
+ * fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html: Added.
+ * fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute-expected.txt: Added.
+ * fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html: Added.
+ * fast/loader/stateobjects/popstate-after-load-complete-window-attribute-expected.txt: Added.
+ * fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html: Added.
+ * fast/loader/stateobjects/pushstate-object-types-expected.txt: Added.
+ * fast/loader/stateobjects/pushstate-object-types.html: Added.
+ * fast/loader/stateobjects/pushstate-then-replacestate-expected.txt: Added.
+ * fast/loader/stateobjects/pushstate-then-replacestate.html: Added.
+ * fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange-expected.txt: Added.
+ * fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html: Added.
+ * fast/loader/stateobjects/replacestate-then-pushstate-expected.txt: Added.
+ * fast/loader/stateobjects/replacestate-then-pushstate.html: Added.
+ * fast/loader/stateobjects/resources: Added.
+ * fast/loader/stateobjects/resources/navigate-back.html: Added.
+ * http/tests/loading/state-object-security-exception-expected.txt: Added.
+ * http/tests/loading/state-object-security-exception.html: Added.
+
2009-12-03 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
Reviewed by Xan Lopez.
PASS history.forward == "LEFTOVER" is false
PASS history.go == "LEFTOVER" is false
PASS history.length == "LEFTOVER" is false
+PASS history.pushState == "LEFTOVER" is false
+PASS history.replaceState == "LEFTOVER" is false
PASS location.assign == "LEFTOVER" is false
PASS location.hash == "LEFTOVER" is false
PASS location.host == "LEFTOVER" is false
window.history.forward [function]
window.history.go [function]
window.history.length [number]
+window.history.pushState [function]
+window.history.replaceState [function]
window.innerHeight [number]
window.innerWidth [number]
window.length [number]
window.onpause [null]
window.onplay [null]
window.onplaying [null]
+window.onpopstate [null]
window.onprogress [null]
window.onratechange [null]
window.onreset [null]
--- /dev/null
+main frame - has 1 onunload handler(s)
+ALERT: History length is 2
+ALERT: State popped - FirstEntry (type string)
+ALERT: State popped - SecondEntry (type string)
+ALERT: Navigating back...
+main frame - has 1 onunload handler(s)
+ALERT: History length is 2
+ALERT: window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html?SecondEntryShouldNeverBeReactivated
+main frame - has 1 onunload handler(s)
+ALERT: History length is 1
+ALERT: window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html?FirstEntryShouldNeverBeReactivated
+ALERT: Test completed
+This test:
+-Builds up a list of state object entries.
+-Navigates through them to verify that the popstate event is fired.
+-Navigates away to a new document, with the old document being destroyed.
+-Navigates back to the state object entries and verifies the popstate event is not fired.
+
+History length is 1
+window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html?FirstEntryShouldNeverBeReactivated
+Test completed
+
--- /dev/null
+main frame - has 1 onunload handler(s)
+ALERT: History length is 2
+ALERT: State popped - FirstEntry (type string)
+ALERT: hashChanged - location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#FirstEntry
+ALERT: State popped - SecondEntry (type string)
+ALERT: hashChanged - location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#SecondEntry
+ALERT: Navigating back...
+main frame - has 1 onunload handler(s)
+ALERT: History length is 2
+ALERT: window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#SecondEntryShouldNeverBeReactivated
+ALERT: hashChanged - location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#FirstEntryShouldNeverBeReactivated
+ALERT: Test completed
+This test:
+-Builds up a list of state object entries with fragment URL.
+-Navigates through them to verify that the popstate and hashchanged events are fired.
+-Navigates away to a new document, with the old document being destroyed.
+-Navigates back to the state object entries and verifies the popstate event is not fired.
+
+History length is 2
+window.location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#SecondEntryShouldNeverBeReactivated
+hashChanged - location is file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html#FirstEntryShouldNeverBeReactivated
+Test completed
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ if (!sessionStorage.stage)
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+ // alert the messages also so DumpRenderTree can capture and log messages across multiple documents.
+ alert(txt);
+}
+
+function endTest(msg)
+{
+ log(msg);
+ sessionStorage.clear();
+ if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+function runSecondStageOfTest()
+{
+ log("History length is " + history.length);
+ log("window.location is " + window.location);
+ sessionStorage.stage = 3;
+ history.back();
+}
+
+function runThirdStageOfTest()
+{
+ log("History length is " + history.length);
+ log("window.location is " + window.location);
+ endTest("Test completed");
+}
+
+function loaded()
+{
+ if (sessionStorage.stage) {
+ if (sessionStorage.stage == 2)
+ runSecondStageOfTest();
+ else if (sessionStorage.stage == 3)
+ endTest("Shouldn't reach this case when doing fragment scrolls");
+ else
+ endTest("Unexpected stage value");
+ } else
+ runFirstStageOfTest();
+}
+
+function runFirstStageOfTest()
+{
+ history.replaceState("FirstEntry", null, "#FirstEntry");
+ history.pushState("SecondEntry", null, "#SecondEntry");
+
+ log("History length is " + history.length);
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state == "FirstEntry") {
+ history.replaceState("FirstEntryShouldNeverBeReactivated", null, "#FirstEntryShouldNeverBeReactivated");
+ history.forward();
+ } else if (event.state == "SecondEntry") {
+ history.replaceState("SecondEntryShouldNeverBeReactivated", null, "#SecondEntryShouldNeverBeReactivated");
+ window.location = "resources/navigate-back.html";
+ } else
+ endTest("Unexpected state popped - " + event.state);
+}
+
+function hashChanged()
+{
+ log("hashChanged - location is " + window.location);
+ if (window.location.hash == "#FirstEntryShouldNeverBeReactivated")
+ endTest("Test completed");
+}
+
+</script>
+<body onload="loaded();" onpopstate="statePopped();" onhashchange="hashChanged();" onunload="/* disable page cache */">
+<pre>
+This test:
+-Builds up a list of state object entries with fragment URL.
+-Navigates through them to verify that the popstate and hashchanged events are fired.
+-Navigates away to a new document, with the old document being destroyed.
+-Navigates back to the state object entries and verifies the popstate event is not fired.
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ if (!sessionStorage.stage)
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+ // alert the messages also so DumpRenderTree can capture and log messages across multiple documents.
+ alert(txt);
+}
+
+function endTest(msg)
+{
+ log(msg);
+ sessionStorage.clear();
+ if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+function runSecondStageOfTest()
+{
+ log("History length is " + history.length);
+ log("window.location is " + window.location);
+ sessionStorage.stage = 3;
+ history.back();
+}
+
+function runThirdStageOfTest()
+{
+ log("History length is " + history.length);
+ log("window.location is " + window.location);
+ endTest("Test completed");
+}
+
+function loaded()
+{
+ if (sessionStorage.stage) {
+ if (sessionStorage.stage == 2)
+ runSecondStageOfTest();
+ else if (sessionStorage.stage == 3)
+ runThirdStageOfTest();
+ else
+ endTest("Unexpected stage value");
+ } else
+ runFirstStageOfTest();
+}
+
+function runFirstStageOfTest()
+{
+ history.replaceState("FirstEntry", null, "?FirstEntry");
+ history.pushState("SecondEntry", null, "?SecondEntry");
+
+ log("History length is " + history.length);
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state == "FirstEntry") {
+ history.replaceState("FirstEntryShouldNeverBeReactivated", null, "?FirstEntryShouldNeverBeReactivated");
+ history.forward();
+ } else if (event.state == "SecondEntry") {
+ history.replaceState("SecondEntryShouldNeverBeReactivated", null, "?SecondEntryShouldNeverBeReactivated");
+ window.location = "resources/navigate-back.html";
+ } else
+ endTest("Unexpected state popped - " + event.state);
+}
+
+</script>
+<body onload="loaded();" onpopstate="statePopped();" onunload="/* disable page cache */">
+<pre>
+This test:
+-Builds up a list of state object entries.
+-Navigates through them to verify that the popstate event is fired.
+-Navigates away to a new document, with the old document being destroyed.
+-Navigates back to the state object entries and verifies the popstate event is not fired.
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+This test does the following:
+-Listens for the popstate event using addEventListener
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+
+History length is 2
+State popped - null (type object)
+State popped - StateStringData (type string)
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function runTest()
+{
+ history.pushState("StateStringData", "New title");
+ log("History length is " + history.length);
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state == null)
+ history.forward();
+ else if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+window.addEventListener("popstate", statePopped);
+
+</script>
+<body onload="runTest();">
+<pre>
+This test does the following:
+-Listens for the popstate event using addEventListener
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+This test does the following:
+-Uses body.onpopstate to add a popstate handler (both by using the inline attribute and a script-assigned attribute)
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+
+History length is 2
+State popped - null (type object)
+State popped - StateStringData (type string)
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function runTest()
+{
+ history.pushState("StateStringData", "New title");
+ log("History length is " + history.length);
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state == null) {
+ document.body.onpopstate = statePopped;
+ history.forward();
+ } else if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+</script>
+<body onload="runTest();">
+<pre>
+This test does the following:
+-Uses body.onpopstate to add a popstate handler (both by using the inline attribute and a script-assigned attribute)
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+</pre><br>
+<pre id="logger"></pre>
+</body>
+<script>
+document.body.onpopstate = statePopped;
+</script>
+</html>
--- /dev/null
+This test does the following:
+-Uses body.onpopstate to add a popstate handler (both by using the inline attribute and a script-assigned attribute)
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+
+History length is 2
+State popped - null (type object)
+State popped - StateStringData (type string)
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function runTest()
+{
+ history.pushState("StateStringData", "New title");
+ log("History length is " + history.length);
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state == null) {
+ document.body.onpopstate = statePopped;
+ history.forward();
+ } else if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+</script>
+<body onload="runTest();" onpopstate="statePopped();">
+<pre>
+This test does the following:
+-Uses body.onpopstate to add a popstate handler (both by using the inline attribute and a script-assigned attribute)
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+This test does the following:
+-Uses window.onpopstate to add a popstate handler
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+
+History length is 2
+State popped - null (type object)
+State popped - StateStringData (type string)
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function runTest()
+{
+ history.pushState("StateStringData", "New title");
+ log("History length is " + history.length);
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state == null)
+ history.forward();
+ else if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+window.onpopstate = statePopped;
+
+</script>
+<body onload="runTest();">
+<pre>
+This test does the following:
+-Uses window.onpopstate to add a popstate handler
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+This test calls pushState with state objects of all the different object types supported by the HTML5 "internal structured cloning algorithm" and makes sure the events contain the expected objects when the states are popped.
+
+State popped - [object Object] (type object)
+State popped - [object Object] (type object)
+State popped - (type object)
+State popped - null (type object)
+State popped - Wed Dec 31 1969 16:00:00 GMT-0800 (PST) (type object)
+State popped - String (type string)
+State popped - 42 (type number)
+State popped - true (type boolean)
+State popped - false (type boolean)
+State popped - null (type object)
+State popped - undefined (type undefined)
+State popped - FirstEntry (type string)
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function runTest()
+{
+ history.replaceState("FirstEntry", "Initial entry");
+ history.pushState(undefined, "undefined entry");
+ history.pushState(null, "null entry");
+ history.pushState(false, "false entry");
+ history.pushState(true, "true entry");
+ history.pushState(42, "Number entry");
+ history.pushState("String", "String entry");
+ history.pushState(new Date(0), "Date entry");
+ history.pushState(new RegExp, "RegExp entry");
+ history.pushState(new Array, "Array entry");
+ history.pushState(new Object, "Object entry");
+ history.pushState(new Error, "Error entry");
+
+/* The following are not yet well enough supported in WebKit to meaningfully test here:
+history.pushState([ImageData], "ImageData entry");
+history.pushState([Blob], "Blob entry");
+history.pushState([File], "File entry");
+history.pushState([FileList], "FileList entry");
+*/
+
+ history.pushState("BufferEntry", "Last entry");
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state != "FirstEntry")
+ history.back();
+ else if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+</script>
+<body onload="runTest();" onpopstate="statePopped();">
+<pre id="someelement">
+This test calls pushState with state objects of all the different object types supported by the HTML5 "internal structured cloning algorithm" and makes sure the events contain the expected objects when the states are popped.
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+This test does the following:
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Makes a call to replaceState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event represents the replaced state object
+
+History length is 2
+History length is 2
+State popped - null (type object)
+State popped - 1 (type number)
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function runTest()
+{
+ history.pushState("StateStringData", "New title");
+ log("History length is " + history.length);
+ history.replaceState(1, "Replaced title");
+ log("History length is " + history.length);
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state == null)
+ history.forward();
+ else if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+</script>
+<body onload="runTest();" onpopstate="statePopped();">
+<pre>
+This test does the following:
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Makes a call to replaceState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event represents the replaced state object
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+This test pushes a series of state objects with different URLs and fragment identifiers meant to test the hashChange event as states are popped.
+
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withsomeotherquery
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withsomeotherquery#
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withsomeotherquery
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withsomeotherquery#somehash
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withsomeotherquery#someotherhash
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withquery#someotherhash
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withquery#
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withquery#somehash
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withquery
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withquery#
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html?withquery
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/some-other.html
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html#
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html#
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html#otherhash
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html#hash
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html#
+Hash change fired
+State popped with event null (type object) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html#
+State popped with event OriginalEntry (type string) and location file:///Volumes/Data/svn/OpenSource/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function runTest()
+{
+ history.replaceState("OriginalEntry", "original");
+ history.pushState(null, null, "#");
+ history.pushState(null, null, "");
+ history.pushState(null, null, "#hash");
+ history.pushState(null, null, "#otherhash");
+ history.pushState(null, null, "#");
+ history.pushState(null, null, null);
+ history.pushState(null, null, "some-other.html");
+ history.pushState(null, null, "some-other.html?withquery");
+ history.pushState(null, null, "some-other.html?withquery#");
+ history.pushState(null, null, "some-other.html?withquery");
+ history.pushState(null, null, "some-other.html?withquery#somehash");
+ history.pushState(null, null, "some-other.html?withquery#");
+ history.pushState(null, null, "some-other.html?withquery#someotherhash");
+ history.pushState(null, null, "some-other.html?withsomeotherquery#someotherhash");
+ history.pushState(null, null, "some-other.html?withsomeotherquery#somehash");
+ history.pushState(null, null, "some-other.html?withsomeotherquery");
+ history.pushState(null, null, "some-other.html?withsomeotherquery#");
+ history.pushState(null, null, "some-other.html?withsomeotherquery");
+
+ history.pushState("BufferEntry", "Last entry");
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped with event " + event.state + " (type " + typeof event.state + ") and location " + window.location);
+ if (event.state != "OriginalEntry")
+ history.back();
+ else if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+function hashChanged()
+{
+ log("Hash change fired");
+}
+
+</script>
+<body onload="runTest();" onpopstate="statePopped();" onhashchange="hashChanged();">
+<pre>
+This test pushes a series of state objects with different URLs and fragment identifiers meant to test the hashChange event as states are popped.
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+This test does the following:
+-Makes a call to replaceState()
+-Makes sure the history length is correct
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+
+History length is 1
+History length is 2
+State popped - OriginalHistoryItem (type string)
+State popped - NewHistoryItem (type string)
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+ layoutTestController.waitUntilDone();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function runTest()
+{
+ history.replaceState("OriginalHistoryItem", "Replaced title");
+ log("History length is " + history.length);
+ history.pushState("NewHistoryItem", "Pushed title");
+ log("History length is " + history.length);
+ history.back();
+}
+
+function statePopped()
+{
+ log("State popped - " + event.state + " (type " + typeof event.state + ")");
+ if (event.state == "OriginalHistoryItem")
+ history.forward();
+ else if (window.layoutTestController)
+ layoutTestController.notifyDone();
+}
+
+</script>
+<body onload="runTest();" onpopstate="statePopped();">
+<pre>
+This test does the following:
+-Makes a call to replaceState()
+-Makes sure the history length is correct
+-Makes a call to pushState()
+-Makes sure the history length is correct
+-Goes back, and makes sure the popstate event is correct
+-Goes forward, and makes sure the popstate event is correct
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
--- /dev/null
+<html>
+<body onload="alert('Navigating back...'); sessionStorage.stage = 2; history.back();"></body>
+</html>
--- /dev/null
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+This test makes sure that calls to pushState() and replaceState() with URLs that violate the security origin check fail as expected.
+
+Trying to pushState() with url http://localhost/test.html failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to replaceState() with url http://localhost/test.html failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to pushState() with url http://localhost:8001/test.html failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to replaceState() with url http://localhost:8001/test.html failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to pushState() with url http://www.webkit.org/test.html failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to replaceState() with url http://www.webkit.org/test.html failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to pushState() with url http://www.webkit.org/ failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to replaceState() with url http://www.webkit.org/ failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to pushState() with url ftp://www.webkit.org/ failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to replaceState() with url ftp://www.webkit.org/ failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to pushState() with url file://anyfile.html/ failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+Trying to replaceState() with url file://anyfile.html/ failed with exception Error: SECURITY_ERR: DOM Exception 18
+History length is 1
+
--- /dev/null
+<html>
+<head>
+<script>
+
+if (window.layoutTestController) {
+ layoutTestController.clearBackForwardList();
+ layoutTestController.dumpAsText();
+}
+
+function log(txt)
+{
+ document.getElementById("logger").innerText += txt + "\n";
+}
+
+function tryURL(url)
+{
+ try {
+ history.pushState(null, null, url);
+ log("Trying to pushState() with url " + url + " succeeded, but should've failed.");
+ } catch(e) {
+ log("Trying to pushState() with url " + url + " failed with exception " + e);
+ }
+ log("History length is " + history.length);
+
+ try {
+ history.replaceState(null, null, url);
+ log("Trying to replaceState() with url " + url + " succeeded, but should've failed.");
+ } catch(e) {
+ log("Trying to replaceState() with url " + url + " failed with exception " + e);
+ }
+ log("History length is " + history.length);
+}
+
+var URLsToTry = new Array(
+"http://localhost/test.html",
+"http://localhost:8001/test.html",
+"http://www.webkit.org/test.html",
+"http://www.webkit.org/",
+"ftp://www.webkit.org/",
+"file://anyfile.html/"
+);
+
+function runTest()
+{
+ for (n in URLsToTry)
+ tryURL(URLsToTry[n]);
+}
+
+</script>
+<body onload="runTest();">
+<pre>
+This test makes sure that calls to pushState() and replaceState() with URLs that violate the security origin check fail as expected.
+</pre><br>
+<pre id="logger"></pre>
+</body>
+</html>
CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
+
This tests that variable names can't be enumerated cross domain (see http://bugs.webkit.org/show_bug.cgi?id=16387)
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ Tests: fast/loader/stateobjects/document-destroyed-navigate-back.html
+ fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html
+ fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html
+ fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html
+ fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html
+ fast/loader/stateobjects/pushstate-object-types.html
+ fast/loader/stateobjects/pushstate-then-replacestate.html
+ fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html
+ fast/loader/stateobjects/replacestate-then-pushstate.html
+ http/tests/loading/state-object-security-exception.html
+
+ Derived sources and project file changes:
+ * DerivedSources.cpp:
+ * DerivedSources.make:
+ * GNUmakefile.am
+ * WebCore.pro
+ * WebCore.vcproj/WebCore.vcproj:
+ * WebCore.xcodeproj/project.pbxproj:
+
+ Add the new PopStateEvent:
+ * dom/PopStateEvent.cpp: Added.
+ (WebCore::PopStateEvent::PopStateEvent):
+ (WebCore::PopStateEvent::initPopStateEvent):
+ * dom/PopStateEvent.h: Added.
+ (WebCore::PopStateEvent::create):
+ (WebCore::PopStateEvent::isPopStateEvent):
+ (WebCore::PopStateEvent::state):
+ * dom/PopStateEvent.idl: Added.
+ * bindings/js/JSPopStateEventCustom.cpp: Added.
+ (WebCore::JSPopStateEvent::initPopStateEvent):
+ (WebCore::JSPopStateEvent::state):
+ * bindings/js/JSEventCustom.cpp:
+ (WebCore::toJS):
+ * dom/Event.cpp:
+ (WebCore::Event::isPopStateEvent):
+ * dom/Event.h:
+ * dom/EventNames.h:
+
+ Add the "onpopstate" attribute:
+ * html/HTMLAttributeNames.in:
+ * html/HTMLBodyElement.cpp:
+ (WebCore::HTMLBodyElement::parseMappedAttribute):
+ * html/HTMLBodyElement.idl:
+ * html/HTMLFrameSetElement.cpp:
+ (WebCore::HTMLFrameSetElement::parseMappedAttribute):
+ * html/HTMLFrameSetElement.h:
+ * html/HTMLFrameSetElement.idl:
+ * page/DOMWindow.h:
+ * page/DOMWindow.idl:
+
+ Add pushState and replaceState management to the loader and history machinery:
+ * bindings/js/JSHistoryCustom.cpp:
+ (WebCore::JSHistory::pushState):
+ (WebCore::JSHistory::replaceState):
+ * loader/HistoryController.cpp:
+ (WebCore::HistoryController::updateForSameDocumentNavigation): Augmented from "scrollToAnchor()", combining
+ both the same-document fragment scroll case with the new same-document state object activation case.
+ (WebCore::HistoryController::pushState):
+ (WebCore::HistoryController::replaceState):
+ * loader/HistoryController.h:
+ * history/BackForwardList.cpp:
+ (WebCore::BackForwardList::addItem): Use insertItemAfterCurrent.
+ (WebCore::BackForwardList::insertItemAfterCurrent): Optionally insert the item without clearing the forward
+ list, as pushStateItem might've selectively cleared only certain items, with the bulk of the forward list
+ meant to remain.
+ (WebCore::BackForwardList::pushStateItem): Clear the forward list *only* for the state item's document, then
+ insert the new item.
+ (WebCore::BackForwardList::removeItem):
+ * history/BackForwardList.h:
+ * page/History.cpp:
+ (WebCore::History::urlForState):
+ (WebCore::History::stateObjectAdded):
+ * page/History.h:
+ * page/History.idl:
+
+ Let HistoryItems and Documents associate with each other, as well as letting HistoryItems contain state objects:
+ * history/HistoryItem.cpp:
+ (WebCore::HistoryItem::HistoryItem):
+ (WebCore::HistoryItem::~HistoryItem):
+ (WebCore::HistoryItem::setStateObject):
+ (WebCore::HistoryItem::setDocument):
+ (WebCore::HistoryItem::documentDetached):
+ * history/HistoryItem.h:
+ (WebCore::HistoryItem::stateObject):
+ (WebCore::HistoryItem::document):
+ * dom/Document.cpp:
+ (WebCore::Document::detach): Notify all back/forward history items owned by this Document that it
+ is going away.
+ (WebCore::Document::registerHistoryItem): Manage the list of back/forward history items this document owns.
+ (WebCore::Document::unregisterHistoryItem): Ditto.
+ * dom/Document.h:
+
+ Add the ability for Documents, DocumentLoaders, and FrameLoaderClients to be notified when a Documents
+ URL changes as the result of pushState(), replaceState(), or a popstate navigation:
+ * dom/Document.cpp:
+ (WebCore::Document::implicitClose): If there's a pending state object, dispatch the popstate event.
+ (WebCore::Document::updateURLForPushOrReplaceState):
+ (WebCore::Document::statePopped): If loading is complete, dispatch the popstate event. Otherwise, set
+ the pending state object.
+ * loader/DocumentLoader.cpp:
+ (WebCore::DocumentLoader::replaceRequestURLForSameDocumentNavigation):
+ * loader/DocumentLoader.h:
+ * loader/FrameLoaderClient.h:
+ * loader/EmptyClients.h:
+ (WebCore::EmptyFrameLoaderClient::dispatchDidChangeStateObjectForPageForFrame):
+
+ Change handling of "loading a HistoryItem" to distinguish between new-Document navigations and same-Document
+ navigations, combining the old concept of anchor scrolls with the new concept of state object navigations:
+ * loader/FrameLoader.cpp:
+ (WebCore::FrameLoader::loadInSameDocument):
+ (WebCore::FrameLoader::continueFragmentScrollAfterNavigationPolicy):
+ (WebCore::FrameLoader::navigateWithinDocument):
+ (WebCore::FrameLoader::navigateToDifferentDocument):
+ (WebCore::FrameLoader::loadItem):
+ * loader/FrameLoader.h:
+ * page/Page.cpp:
+ (WebCore::Page::goToItem): Changed to allow state object activations to pass through without the load stopping.
+
2009-12-03 Pavel Feldman <pfeldman@chromium.org>
Not reviewed: chromium build fix.
#include "JSPageTransitionEvent.cpp"
#include "JSPlugin.cpp"
#include "JSPluginArray.cpp"
+#include "JSPopStateEvent.cpp"
#include "JSProcessingInstruction.cpp"
#include "JSProgressEvent.cpp"
#include "JSRange.cpp"
PageTransitionEvent \
Plugin \
PluginArray \
+ PopStateEvent \
PositionError \
ProcessingInstruction \
ProgressEvent \
WebCore/dom/Notation.idl \
WebCore/dom/OverflowEvent.idl \
WebCore/dom/PageTransitionEvent.idl \
+ WebCore/dom/PopStateEvent.idl \
WebCore/dom/ProcessingInstruction.idl \
WebCore/dom/ProgressEvent.idl \
WebCore/dom/Range.idl \
WebCore/bindings/js/JSPluginCustom.cpp \
WebCore/bindings/js/JSPluginElementFunctions.cpp \
WebCore/bindings/js/JSPluginElementFunctions.h \
+ WebCore/bindings/js/JSPopStateEventCustom.cpp \
+ WebCore/bindings/js/JSPopStateEventCustom.h \
WebCore/bindings/js/JSQuarantinedObjectWrapper.cpp \
WebCore/bindings/js/JSQuarantinedObjectWrapper.h \
WebCore/bindings/js/JSStorageCustom.h \
WebCore/dom/PageTransitionEvent.h \
WebCore/dom/Position.cpp \
WebCore/dom/Position.h \
+ WebCore/dom/PopStateEvent.cpp \
+ WebCore/dom/PopStateEvent.h \
WebCore/dom/PositionIterator.cpp \
WebCore/dom/PositionIterator.h \
WebCore/dom/ProcessingInstruction.cpp \
dom/Notation.idl \
dom/OverflowEvent.idl \
dom/PageTransitionEvent.idl \
+ dom/PopStateEvent.idl \
dom/ProcessingInstruction.idl \
dom/ProgressEvent.idl \
dom/RangeException.idl \
bindings/js/JSEventListener.cpp \
bindings/js/JSLazyEventListener.cpp \
bindings/js/JSPluginElementFunctions.cpp \
+ bindings/js/JSPopStateEventCustom.cpp \
bindings/js/ScriptArray.cpp \
bindings/js/ScriptCachedFrameData.cpp \
bindings/js/ScriptCallFrame.cpp \
dom/OptionElement.cpp \
dom/OverflowEvent.cpp \
dom/PageTransitionEvent.cpp \
+ dom/PopStateEvent.cpp \
dom/Position.cpp \
dom/PositionIterator.cpp \
dom/ProcessingInstruction.cpp \
RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPluginArray.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPopStateEvent.cpp"\r
+ >\r
+ <FileConfiguration\r
+ Name="Debug|Win32"\r
+ ExcludedFromBuild="true"\r
+ >\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ />\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Release|Win32"\r
+ ExcludedFromBuild="true"\r
+ >\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ />\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Debug_Internal|Win32"\r
+ ExcludedFromBuild="true"\r
+ >\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ />\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Debug_Cairo|Win32"\r
+ ExcludedFromBuild="true"\r
+ >\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ />\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Release_Cairo|Win32"\r
+ ExcludedFromBuild="true"\r
+ >\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ />\r
+ </FileConfiguration>\r
+ <FileConfiguration\r
+ Name="Debug_All|Win32"\r
+ ExcludedFromBuild="true"\r
+ >\r
+ <Tool\r
+ Name="VCCLCompilerTool"\r
+ />\r
+ </FileConfiguration>\r
+ </File>\r
+ <File\r
+ RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPopStateEvent.h"\r
+ >\r
+ </File>\r
<File\r
RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPositionError.cpp"\r
>\r
RelativePath="..\dom\default\PlatformMessagePortChannel.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath="..\dom\PopStateEvent.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\dom\PopStateEvent.h"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\dom\Position.cpp"\r
>\r
RelativePath="..\bindings\js\JSPluginElementFunctions.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath="..\bindings\js\JSPopStateEventCustom.cpp"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\bindings\js\JSQuarantinedObjectWrapper.cpp"\r
>\r
RelativePath="..\inspector\front-end\Color.js"\r
>\r
</File>\r
- <File\r
- RelativePath="..\inspector\front-end\ConsolePanel.js"\r
- >\r
- </File>\r
+ <File\r
+ RelativePath="..\inspector\front-end\ConsolePanel.js"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\inspector\front-end\ConsoleView.js"\r
>\r
>\r
</File>\r
<File\r
- RelativePath="..\inspector\front-end\TimelineOverviewPane.js"\r
+ RelativePath="..\inspector\front-end\TimelineGrid.js"\r
>\r
</File>\r
<File\r
- RelativePath="..\inspector\front-end\TimelineGrid.js"\r
+ RelativePath="..\inspector\front-end\TimelineOverviewPane.js"\r
>\r
</File>\r
<File\r
51741D100B07259A00ED442C /* BackForwardList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51741D0C0B07259A00ED442C /* BackForwardList.cpp */; };
51741D110B07259A00ED442C /* HistoryItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 51741D0D0B07259A00ED442C /* HistoryItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
51741D120B07259A00ED442C /* HistoryItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51741D0E0B07259A00ED442C /* HistoryItem.cpp */; };
+ 5174E20A10A1F44F00F95E6F /* PopStateEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5174E20810A1F44F00F95E6F /* PopStateEvent.h */; };
+ 5174E20C10A1F49A00F95E6F /* PopStateEvent.idl in Resources */ = {isa = PBXBuildFile; fileRef = 5174E20B10A1F49A00F95E6F /* PopStateEvent.idl */; };
+ 5189F01810B3781300F3C739 /* JSPopStateEventCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5189F01710B3781300F3C739 /* JSPopStateEventCustom.cpp */; };
+ 5189F01D10B37BD900F3C739 /* JSPopStateEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5189F01B10B37BD900F3C739 /* JSPopStateEvent.cpp */; };
+ 5189F01E10B37BD900F3C739 /* JSPopStateEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5189F01C10B37BD900F3C739 /* JSPopStateEvent.h */; };
+ 5189F0DE10B46B0E00F3C739 /* PopStateEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5189F0DD10B46B0E00F3C739 /* PopStateEvent.cpp */; };
518A34C11026C831001B6896 /* WebSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 518A34BE1026C831001B6896 /* WebSocket.cpp */; };
518A34C21026C831001B6896 /* WebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 518A34BF1026C831001B6896 /* WebSocket.h */; };
518A34C71026C8C9001B6896 /* JSWebSocketConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 518A34C41026C8C9001B6896 /* JSWebSocketConstructor.cpp */; };
51741D0C0B07259A00ED442C /* BackForwardList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BackForwardList.cpp; sourceTree = "<group>"; };
51741D0D0B07259A00ED442C /* HistoryItem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HistoryItem.h; sourceTree = "<group>"; };
51741D0E0B07259A00ED442C /* HistoryItem.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HistoryItem.cpp; sourceTree = "<group>"; };
+ 5174E20810A1F44F00F95E6F /* PopStateEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopStateEvent.h; sourceTree = "<group>"; };
+ 5174E20B10A1F49A00F95E6F /* PopStateEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PopStateEvent.idl; sourceTree = "<group>"; };
+ 5189F01710B3781300F3C739 /* JSPopStateEventCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPopStateEventCustom.cpp; sourceTree = "<group>"; };
+ 5189F01B10B37BD900F3C739 /* JSPopStateEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPopStateEvent.cpp; sourceTree = "<group>"; };
+ 5189F01C10B37BD900F3C739 /* JSPopStateEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPopStateEvent.h; sourceTree = "<group>"; };
+ 5189F0DD10B46B0E00F3C739 /* PopStateEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PopStateEvent.cpp; sourceTree = "<group>"; };
518A34BE1026C831001B6896 /* WebSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocket.cpp; sourceTree = "<group>"; };
518A34BF1026C831001B6896 /* WebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocket.h; sourceTree = "<group>"; };
518A34C01026C831001B6896 /* WebSocket.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebSocket.idl; sourceTree = "<group>"; };
1A0D573F0A5C7867007EDD4C /* JSOverflowEvent.h */,
E1284BB010449FFA00EAEB52 /* JSPageTransitionEvent.cpp */,
E1284BAF10449FFA00EAEB52 /* JSPageTransitionEvent.h */,
+ 5189F01B10B37BD900F3C739 /* JSPopStateEvent.cpp */,
+ 5189F01C10B37BD900F3C739 /* JSPopStateEvent.h */,
933A14B60B7D1D5200A53FFD /* JSTextEvent.cpp */,
933A14B70B7D1D5200A53FFD /* JSTextEvent.h */,
A86629CA09DA2B47009633A5 /* JSUIEvent.cpp */,
BCD9C2610C17AA67005C90A2 /* JSNodeListCustom.cpp */,
A9C6E64A0D7465E7006442E9 /* JSPluginArrayCustom.cpp */,
A9C6E64B0D7465E7006442E9 /* JSPluginCustom.cpp */,
+ 5189F01710B3781300F3C739 /* JSPopStateEventCustom.cpp */,
51DCE8010CAC9F1C00488358 /* JSSQLResultSetRowListCustom.cpp */,
1AD2316D0CD269E700C1F194 /* JSSQLTransactionCustom.cpp */,
51D0C5150DAA90B7003B3831 /* JSStorageCustom.cpp */,
E1284AD910447AEB00EAEB52 /* PageTransitionEvent.idl */,
41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */,
41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */,
+ 5189F0DD10B46B0E00F3C739 /* PopStateEvent.cpp */,
+ 5174E20810A1F44F00F95E6F /* PopStateEvent.h */,
+ 5174E20B10A1F49A00F95E6F /* PopStateEvent.idl */,
BE91FC8C06133666005E3790 /* Position.cpp */,
BE91FC8B06133666005E3790 /* Position.h */,
37919C210B7D188600A56998 /* PositionIterator.cpp */,
1479FAF0109AE37500DED655 /* RenderRubyBase.h in Headers */,
1479FAF2109AE37500DED655 /* RenderRubyRun.h in Headers */,
1479FAF4109AE37500DED655 /* RenderRubyText.h in Headers */,
+ 5174E20A10A1F44F00F95E6F /* PopStateEvent.h in Headers */,
18C5FCA610A3991F0048438D /* WebKitSharedScript.h in Headers */,
18C5FCA910A3991F0048438D /* WebKitSharedScriptRepository.h in Headers */,
18C5FCB810A3C6F20048438D /* SharedScriptContext.h in Headers */,
E124748410AA161D00B79493 /* AuthenticationClient.h in Headers */,
9382DF5810A8D5C900925652 /* ColorSpace.h in Headers */,
AB31C91E10AE1B8E000C7B92 /* LineClampValue.h in Headers */,
+ 5189F01E10B37BD900F3C739 /* JSPopStateEvent.h in Headers */,
6E47E66110B7944B00B186C8 /* WebGLGetInfo.h in Headers */,
7A0E76DB10BF059800A0276E /* JSInjectedScriptHost.h in Headers */,
7A0E76FA10BF08ED00A0276E /* InjectedScriptHost.h in Headers */,
85136CA80AED665900F90A3D /* westResizeCursor.png in Resources */,
1AB1AE7A0C051FDE00139F4F /* zoomInCursor.png in Resources */,
1AB1AE7B0C051FDE00139F4F /* zoomOutCursor.png in Resources */,
+ 5174E20C10A1F49A00F95E6F /* PopStateEvent.idl in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
1479FAEF109AE37500DED655 /* RenderRubyBase.cpp in Sources */,
1479FAF1109AE37500DED655 /* RenderRubyRun.cpp in Sources */,
1479FAF3109AE37500DED655 /* RenderRubyText.cpp in Sources */,
+ 5189F01810B3781300F3C739 /* JSPopStateEventCustom.cpp in Sources */,
+ 5189F01D10B37BD900F3C739 /* JSPopStateEvent.cpp in Sources */,
+ 5189F0DE10B46B0E00F3C739 /* PopStateEvent.cpp in Sources */,
18C5FCA510A3991F0048438D /* WebKitSharedScript.cpp in Sources */,
18C5FCA810A3991F0048438D /* WebKitSharedScriptRepository.cpp in Sources */,
18C5FCB710A3C6F20048438D /* SharedScriptContext.cpp in Sources */,
#include "JSMutationEvent.h"
#include "JSOverflowEvent.h"
#include "JSPageTransitionEvent.h"
+#include "JSPopStateEvent.h"
#include "JSProgressEvent.h"
#include "JSTextEvent.h"
#include "JSUIEvent.h"
#include "MutationEvent.h"
#include "OverflowEvent.h"
#include "PageTransitionEvent.h"
+#include "PopStateEvent.h"
#include "ProgressEvent.h"
#include "TextEvent.h"
#include "UIEvent.h"
else if (event->isErrorEvent())
wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, ErrorEvent, event);
#endif
+ else if (event->isPopStateEvent())
+ wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, PopStateEvent, event);
else
wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, Event, event);
Base::getOwnPropertyNames(exec, propertyNames);
}
+JSValue JSHistory::pushState(ExecState* exec, const ArgList& args)
+{
+ RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, args.at(0));
+ if (exec->hadException())
+ return jsUndefined();
+
+ String title = valueToStringWithUndefinedOrNullCheck(exec, args.at(1));
+ if (exec->hadException())
+ return jsUndefined();
+
+ String url;
+ if (args.size() > 2) {
+ url = valueToStringWithUndefinedOrNullCheck(exec, args.at(2));
+ if (exec->hadException())
+ return jsUndefined();
+ }
+
+ ExceptionCode ec = 0;
+ impl()->stateObjectAdded(historyState.release(), title, url, History::StateObjectPush, ec);
+ setDOMException(exec, ec);
+
+ return jsUndefined();
+}
+
+JSValue JSHistory::replaceState(ExecState* exec, const ArgList& args)
+{
+ RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, args.at(0));
+ if (exec->hadException())
+ return jsUndefined();
+
+ String title = valueToStringWithUndefinedOrNullCheck(exec, args.at(1));
+ if (exec->hadException())
+ return jsUndefined();
+
+ String url;
+ if (args.size() > 2) {
+ url = valueToStringWithUndefinedOrNullCheck(exec, args.at(2));
+ if (exec->hadException())
+ return jsUndefined();
+ }
+
+ ExceptionCode ec = 0;
+ impl()->stateObjectAdded(historyState.release(), title, url, History::StateObjectReplace, ec);
+ setDOMException(exec, ec);
+
+ return jsUndefined();
+}
+
} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "JSPopStateEvent.h"
+
+#include "PopStateEvent.h"
+
+using namespace JSC;
+
+namespace WebCore {
+
+JSValue JSPopStateEvent::initPopStateEvent(ExecState* exec, const ArgList& args)
+{
+ const UString& typeArg = args.at(0).toString(exec);
+ bool canBubbleArg = args.at(1).toBoolean(exec);
+ bool cancelableArg = args.at(2).toBoolean(exec);
+ RefPtr<SerializedScriptValue> stateObjectArg = SerializedScriptValue::create(exec, args.at(3));
+
+ PopStateEvent* event = static_cast<PopStateEvent*>(impl());
+ event->initPopStateEvent(typeArg, canBubbleArg, cancelableArg, stateObjectArg.release());
+ return jsUndefined();
+}
+
+JSC::JSValue JSPopStateEvent::state(JSC::ExecState* exec) const
+{
+ SerializedScriptValue* object = static_cast<PopStateEvent*>(impl())->state();
+ if (!object)
+ return JSC::jsNull();
+
+ return object->deserialize(exec);
+}
+
+} // namespace WebCore
#include "PageGroup.h"
#include "PageTransitionEvent.h"
#include "PlatformKeyboardEvent.h"
+#include "PopStateEvent.h"
#include "ProcessingInstruction.h"
#include "ProgressEvent.h"
#include "RegisteredEventListener.h"
if (render)
render->destroy();
+ HashSet<RefPtr<HistoryItem> > associatedHistoryItems;
+ associatedHistoryItems.swap(m_associatedHistoryItems);
+ HashSet<RefPtr<HistoryItem> >::iterator end = associatedHistoryItems.end();
+ for (HashSet<RefPtr<HistoryItem> >::iterator i = associatedHistoryItems.begin(); i != end; ++i)
+ (*i)->documentDetached(this);
+
// This is required, as our Frame might delete itself as soon as it detaches
// us. However, this violates Node::detach() symantics, as it's never
// possible to re-attach. Eventually Document::detach() should be renamed,
ImageLoader::dispatchPendingEvents();
dispatchWindowLoadEvent();
dispatchWindowEvent(PageTransitionEvent::create(eventNames().pageshowEvent, false), this);
+ if (m_pendingStateObject)
+ dispatchWindowEvent(PopStateEvent::create(m_pendingStateObject.release()));
+
if (f)
f->loader()->handledOnloadEvents();
#ifdef INSTRUMENT_LAYOUT_SCHEDULING
initDNSPrefetch();
}
+void Document::updateURLForPushOrReplaceState(const KURL& url)
+{
+ Frame* f = frame();
+ if (!f)
+ return;
+
+ setURL(url);
+ f->loader()->documentLoader()->replaceRequestURLForSameDocumentNavigation(url);
+}
+
+void Document::statePopped(SerializedScriptValue* stateObject)
+{
+ Frame* f = frame();
+ if (!f)
+ return;
+
+ if (f->loader()->isComplete())
+ dispatchWindowEvent(PopStateEvent::create(stateObject));
+ else
+ m_pendingStateObject = stateObject;
+}
+
+void Document::registerHistoryItem(HistoryItem* item)
+{
+ ASSERT(!m_associatedHistoryItems.contains(item));
+ m_associatedHistoryItems.add(item);
+}
+
+void Document::unregisterHistoryItem(HistoryItem* item)
+{
+ ASSERT(m_associatedHistoryItems.contains(item) || m_associatedHistoryItems.isEmpty());
+ m_associatedHistoryItems.remove(item);
+}
+
void Document::updateSandboxFlags()
{
if (m_frame && securityOrigin())
class EventListener;
class Frame;
class FrameView;
- class HitTestRequest;
class HTMLCanvasElement;
class HTMLCollection;
class HTMLAllCollection;
class HTMLHeadElement;
class HTMLInputElement;
class HTMLMapElement;
+ class HistoryItem;
+ class HitTestRequest;
class InspectorTimelineAgent;
class IntPoint;
class DOMWrapperWorld;
class RenderView;
class ScriptElementData;
class SecurityOrigin;
+ class SerializedScriptValue;
class SegmentedString;
class Settings;
class StyleSheet;
// that already contains content.
void setSecurityOrigin(SecurityOrigin*);
+ void updateURLForPushOrReplaceState(const KURL&);
+ void statePopped(SerializedScriptValue*);
+ void registerHistoryItem(HistoryItem* item);
+ void unregisterHistoryItem(HistoryItem* item);
+
void updateSandboxFlags(); // Set sandbox flags as determined by the frame.
bool processingLoadEvent() const { return m_processingLoadEvent; }
Element* m_cssTarget;
bool m_processingLoadEvent;
+ RefPtr<SerializedScriptValue> m_pendingStateObject;
+ HashSet<RefPtr<HistoryItem> > m_associatedHistoryItems;
double m_startTime;
bool m_overMinimumLayoutThreshold;
return false;
}
+bool Event::isPopStateEvent() const
+{
+ return false;
+}
+
bool Event::isProgressEvent() const
{
return false;
virtual bool isBeforeTextInsertedEvent() const;
virtual bool isOverflowEvent() const;
virtual bool isPageTransitionEvent() const;
+ virtual bool isPopStateEvent() const;
virtual bool isProgressEvent() const;
virtual bool isXMLHttpRequestProgressEvent() const;
virtual bool isWebKitAnimationEvent() const;
macro(pagehide) \
macro(pageshow) \
macro(paste) \
+ macro(popstate) \
macro(readystatechange) \
macro(reset) \
macro(resize) \
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "PopStateEvent.h"
+
+#include "EventNames.h"
+
+namespace WebCore {
+
+PopStateEvent::PopStateEvent(PassRefPtr<SerializedScriptValue> stateObject)
+ : Event(eventNames().popstateEvent, false, true)
+ , m_stateObject(stateObject)
+{
+}
+
+void PopStateEvent::initPopStateEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<SerializedScriptValue> stateObject)
+{
+ if (dispatched())
+ return;
+
+ initEvent(type, canBubble, cancelable);
+
+ m_stateObject = stateObject;
+}
+
+} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef PopStateEvent_h
+#define PopStateEvent_h
+
+#include "Event.h"
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+class SerializedScriptValue;
+
+class PopStateEvent : public Event {
+public:
+ static PassRefPtr<PopStateEvent> create(PassRefPtr<SerializedScriptValue> stateObject)
+ {
+ return adoptRef(new PopStateEvent(stateObject));
+ }
+
+ void initPopStateEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<SerializedScriptValue>);
+ bool isPopStateEvent() const { return true; }
+
+ SerializedScriptValue* state() const { return m_stateObject.get(); }
+
+private:
+ PopStateEvent(PassRefPtr<SerializedScriptValue>);
+
+ RefPtr<SerializedScriptValue> m_stateObject;
+};
+
+} // namespace WebCore
+
+#endif // PopStateEvent_h
--- /dev/null
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+module events {
+
+ interface [
+ GenerateConstructor
+ ] PopStateEvent : Event {
+ [Custom] void initPopStateEvent(in DOMString typeArg,
+ in boolean canBubbleArg,
+ in boolean cancelableArg,
+ in any stateArg);
+
+ readonly attribute [CustomGetter] any state;
+ };
+
+}
#include "Logging.h"
#include "Page.h"
#include "PageCache.h"
+#include "SerializedScriptValue.h"
using namespace std;
}
void BackForwardList::addItem(PassRefPtr<HistoryItem> prpItem)
+{
+ insertItemAfterCurrent(prpItem, true);
+}
+
+void BackForwardList::insertItemAfterCurrent(PassRefPtr<HistoryItem> prpItem, bool removeForwardList)
{
ASSERT(prpItem);
if (m_capacity == 0 || !m_enabled)
return;
// Toss anything in the forward list
- if (m_current != NoCurrentItemIndex) {
+ if (removeForwardList && m_current != NoCurrentItemIndex) {
unsigned targetSize = m_current + 1;
while (m_entries.size() > targetSize) {
RefPtr<HistoryItem> item = m_entries.last();
m_page->mainFrame()->loader()->client()->dispatchDidRemoveBackForwardItem(item.get());
}
- m_entries.append(prpItem);
- m_entryHash.add(m_entries.last());
+ m_entryHash.add(prpItem.get());
+ m_entries.insert(m_current + 1, prpItem);
m_current++;
m_page->mainFrame()->loader()->client()->dispatchDidAddBackForwardItem(currentItem());
}
return m_entries;
}
+void BackForwardList::pushStateItem(PassRefPtr<HistoryItem> newItem)
+{
+ ASSERT(newItem);
+ ASSERT(newItem->document());
+ ASSERT(newItem->stateObject());
+
+ RefPtr<HistoryItem> current = currentItem();
+ ASSERT(current);
+
+ Document* newItemDocument = newItem->document();
+ while (HistoryItem* item = forwardItem()) {
+ if (item->document() != newItemDocument)
+ break;
+ removeItem(item);
+ }
+
+ insertItemAfterCurrent(newItem, false);
+
+ if (!current->document()) {
+ current->setDocument(newItemDocument);
+ current->setStateObject(SerializedScriptValue::create());
+ }
+}
+
void BackForwardList::close()
{
int size = m_entries.size();
else {
size_t count = m_entries.size();
if (m_current >= count)
- m_current = count ? count-1 : NoCurrentItemIndex;
+ m_current = count ? count - 1 : NoCurrentItemIndex;
}
break;
}
namespace WebCore {
+class Document;
class HistoryItem;
class Page;
+class SerializedScriptValue;
+class String;
typedef Vector<RefPtr<HistoryItem> > HistoryItemVector;
typedef HashSet<RefPtr<HistoryItem> > HistoryItemHashSet;
void removeItem(HistoryItem*);
HistoryItemVector& entries();
+ void pushStateItem(PassRefPtr<HistoryItem>);
+
#if ENABLE(WML)
void clearWMLPageHistory();
#endif
private:
BackForwardList(Page*);
+
+ void insertItemAfterCurrent(PassRefPtr<HistoryItem>, bool removeForwardList);
Page* m_page;
#if PLATFORM(CHROMIUM)
, m_lastVisitWasFailure(false)
, m_isTargetItem(false)
, m_visitCount(0)
+ , m_document(0)
{
}
, m_lastVisitWasFailure(false)
, m_isTargetItem(false)
, m_visitCount(0)
+ , m_document(0)
{
iconDatabase()->retainIconForPageURL(m_urlString);
}
, m_lastVisitWasFailure(false)
, m_isTargetItem(false)
, m_visitCount(0)
+ , m_document(0)
{
iconDatabase()->retainIconForPageURL(m_urlString);
}
, m_lastVisitWasFailure(false)
, m_isTargetItem(false)
, m_visitCount(0)
+ , m_document(0)
{
iconDatabase()->retainIconForPageURL(m_urlString);
}
{
ASSERT(!m_cachedPage);
iconDatabase()->releaseIconForPageURL(m_urlString);
+ setDocument(0);
}
inline HistoryItem::HistoryItem(const HistoryItem& item)
#endif
}
+void HistoryItem::setStateObject(PassRefPtr<SerializedScriptValue> object)
+{
+ ASSERT(m_document);
+ m_stateObject = object;
+}
+
+void HistoryItem::setDocument(Document* document)
+{
+ if (m_document == document)
+ return;
+
+ if (m_document)
+ m_document->unregisterHistoryItem(this);
+ if (document)
+ document->registerHistoryItem(this);
+
+ m_document = document;
+}
+
+void HistoryItem::documentDetached(Document* document)
+{
+ ASSERT(m_document == document);
+ m_document = 0;
+ m_stateObject = 0;
+}
+
void HistoryItem::addChildItem(PassRefPtr<HistoryItem> child)
{
ASSERT(!childItemWithTarget(child->target()));
#include "IntPoint.h"
#include "PlatformString.h"
+#include "SerializedScriptValue.h"
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
void setTitle(const String&);
void setIsTargetItem(bool);
+ void setStateObject(PassRefPtr<SerializedScriptValue> object);
+ SerializedScriptValue* stateObject() const { return m_stateObject.get(); }
+ void setDocument(Document* document);
+ Document* document() const { return m_document; }
+ void documentDetached(Document*);
+
void setFormInfoFromRequest(const ResourceRequest&);
void setFormData(PassRefPtr<FormData>);
void setFormContentType(const String&);
OwnPtr<Vector<String> > m_redirectURLs;
+ // Support for HTML5 History
+ RefPtr<SerializedScriptValue> m_stateObject;
+ Document* m_document;
+
// info used to repost form data
RefPtr<FormData> m_formData;
String m_formContentType;
onpause
onplay
onplaying
+onpopstate
onprogress
onratechange
onreset
document()->setWindowAttributeEventListener(eventNames().pagehideEvent, createAttributeEventListener(document()->frame(), attr));
else if (attr->name() == onpageshowAttr)
document()->setWindowAttributeEventListener(eventNames().pageshowEvent, createAttributeEventListener(document()->frame(), attr));
+ else if (attr->name() == onpopstateAttr)
+ document()->setWindowAttributeEventListener(eventNames().popstateEvent, createAttributeEventListener(document()->frame(), attr));
else if (attr->name() == onblurAttr)
document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), attr));
else if (attr->name() == onfocusAttr)
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(load);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(beforeunload);
- DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(message);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(hashchange);
+ DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(message);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(offline);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(online);
+ DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(popstate);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(resize);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(storage);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(unload);
+
#if ENABLE(ORIENTATION_EVENTS)
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(orientationchange);
#endif
attribute [DontEnum] EventListener onmessage;
attribute [DontEnum] EventListener onoffline;
attribute [DontEnum] EventListener ononline;
+ attribute [DontEnum] EventListener onpopstate;
attribute [DontEnum] EventListener onresize;
attribute [DontEnum] EventListener onstorage;
attribute [DontEnum] EventListener onunload;
document()->setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document()->frame(), attr));
else if (attr->name() == onofflineAttr)
document()->setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document()->frame(), attr));
+ else if (attr->name() == onpopstateAttr)
+ document()->setWindowAttributeEventListener(eventNames().popstateEvent, createAttributeEventListener(document()->frame(), attr));
else
HTMLElement::parseMappedAttribute(attr);
}
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(message);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(offline);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(online);
+ DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(popstate);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(resize);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(storage);
DEFINE_WINDOW_ATTRIBUTE_EVENT_LISTENER(unload);
attribute [DontEnum] EventListener onmessage;
attribute [DontEnum] EventListener onoffline;
attribute [DontEnum] EventListener ononline;
+ attribute [DontEnum] EventListener onpopstate;
attribute [DontEnum] EventListener onresize;
attribute [DontEnum] EventListener onstorage;
attribute [DontEnum] EventListener onunload;
return request().url();
}
-void DocumentLoader::replaceRequestURLForAnchorScroll(const KURL& url)
+void DocumentLoader::replaceRequestURLForSameDocumentNavigation(const KURL& url)
{
m_originalRequestCopy.setURL(url);
m_request.setURL(url);
const KURL& responseURL() const;
const String& responseMIMEType() const;
- void replaceRequestURLForAnchorScroll(const KURL&);
+ void replaceRequestURLForSameDocumentNavigation(const KURL&);
bool isStopping() const { return m_isStopping; }
void stopLoading(DatabasePolicy = DatabasePolicyStop);
void setCommitted(bool committed) { m_committed = committed; }
virtual void dispatchDidCancelClientRedirect() { }
virtual void dispatchWillPerformClientRedirect(const KURL&, double, double) { }
virtual void dispatchDidChangeLocationWithinPage() { }
+ virtual void dispatchDidPushStateWithinPage() { }
+ virtual void dispatchDidReplaceStateWithinPage() { }
+ virtual void dispatchDidPopStateWithinPage() { }
virtual void dispatchWillClose() { }
virtual void dispatchDidReceiveIcon() { }
virtual void dispatchDidStartProvisionalLoad() { }
child->loader()->setFirstPartyForCookies(url);
}
-class HashChangeEventTask : public ScriptExecutionContext::Task {
-public:
- static PassOwnPtr<HashChangeEventTask> create(PassRefPtr<Document> document)
- {
- return new HashChangeEventTask(document);
- }
-
- virtual void performTask(ScriptExecutionContext* context)
- {
- ASSERT_UNUSED(context, context->isDocument());
- m_document->dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false));
- }
-
-private:
- HashChangeEventTask(PassRefPtr<Document> document)
- : m_document(document)
- {
- ASSERT(m_document);
- }
-
- RefPtr<Document> m_document;
-};
-
// This does the same kind of work that didOpenURL does, except it relies on the fact
// that a higher level already checked that the URLs match and the scrolling is the right thing to do.
-void FrameLoader::scrollToAnchor(const KURL& url)
-{
- ASSERT(equalIgnoringFragmentIdentifier(url, m_URL));
- if (equalIgnoringFragmentIdentifier(url, m_URL) && !equalIgnoringNullity(url.fragmentIdentifier(), m_URL.fragmentIdentifier())) {
- Document* currentDocument = frame()->document();
- currentDocument->postTask(HashChangeEventTask::create(currentDocument));
+void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* stateObject, bool isNewNavigation)
+{
+ // If we have a state object, we cannot also be a new navigation.
+ ASSERT(!stateObject || (stateObject && !isNewNavigation));
+
+ // Update the data source's request with the new URL to fake the URL change
+ m_frame->document()->setURL(url);
+ documentLoader()->replaceRequestURLForSameDocumentNavigation(url);
+ if (isNewNavigation && !shouldTreatURLAsSameAsCurrent(url) && !stateObject) {
+ // NB: must happen after replaceRequestURLForSameDocumentNavigation(), since we add
+ // based on the current request. Must also happen before we openURL and displace the
+ // scroll position, since adding the BF item will save away scroll state.
+
+ // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
+ // it was done, currItem is now set the that slow doc, and prevItem is whatever was
+ // before it. Adding the b/f item will bump the slow doc down to prevItem, even
+ // though its load is not yet done. I think this all works out OK, for one because
+ // we have already saved away the scroll and doc state for the long slow load,
+ // but it's not an obvious case.
+
+ history()->updateBackForwardListForFragmentScroll();
}
+ bool hashChange = equalIgnoringFragmentIdentifier(url, m_URL) && url.fragmentIdentifier() != m_URL.fragmentIdentifier();
m_URL = url;
- history()->updateForAnchorScroll();
+ history()->updateForSameDocumentNavigation();
// If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor
- m_frame->eventHandler()->stopAutoscrollTimer();
- started();
- if (FrameView* view = m_frame->view())
- view->scrollToFragment(m_URL);
-
+ if (hashChange)
+ m_frame->eventHandler()->stopAutoscrollTimer();
+
// It's important to model this as a load that starts and immediately finishes.
// Otherwise, the parent frame may think we never finished loading.
+ started();
+
+ if (hashChange) {
+ if (FrameView* view = m_frame->view())
+ view->scrollToFragment(m_URL);
+ }
+
m_isComplete = false;
checkCompleted();
+
+ if (isNewNavigation) {
+ // This will clear previousItem from the rest of the frame tree that didn't
+ // doing any loading. We need to make a pass on this now, since for anchor nav
+ // we'll not go through a real load and reach Completed state.
+ checkLoadComplete();
+ }
+
+ if (stateObject) {
+ m_frame->document()->statePopped(stateObject);
+ m_client->dispatchDidPopStateWithinPage();
+ }
+
+ if (hashChange) {
+ m_frame->document()->dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false));
+ m_client->dispatchDidChangeLocationWithinPage();
+ }
+
+ // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
+ m_client->didFinishLoad();
}
bool FrameLoader::isComplete() const
void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
{
- bool isRedirect = m_quickRedirectComing || policyChecker()->loadType() == FrameLoadTypeRedirectWithLockedBackForwardList;
m_quickRedirectComing = false;
if (!shouldContinue)
return;
- KURL url = request.url();
-
- m_documentLoader->replaceRequestURLForAnchorScroll(url);
- if (!isRedirect && !shouldTreatURLAsSameAsCurrent(url)) {
- // NB: must happen after _setURL, since we add based on the current request.
- // Must also happen before we openURL and displace the scroll position, since
- // adding the BF item will save away scroll state.
-
- // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
- // it was done, currItem is now set the that slow doc, and prevItem is whatever was
- // before it. Adding the b/f item will bump the slow doc down to prevItem, even
- // though its load is not yet done. I think this all works out OK, for one because
- // we have already saved away the scroll and doc state for the long slow load,
- // but it's not an obvious case.
-
- history()->updateBackForwardListForFragmentScroll();
- }
-
- scrollToAnchor(url);
-
- if (!isRedirect)
- // This will clear previousItem from the rest of the frame tree that didn't
- // doing any loading. We need to make a pass on this now, since for anchor nav
- // we'll not go through a real load and reach Completed state.
- checkLoadComplete();
-
- m_client->dispatchDidChangeLocationWithinPage();
- m_client->didFinishLoad();
+ bool isRedirect = m_quickRedirectComing || policyChecker()->loadType() == FrameLoadTypeRedirectWithLockedBackForwardList;
+ loadInSameDocument(request.url(), 0, !isRedirect);
}
bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType loadType, const KURL& url)
return frame;
}
-// Loads content into this frame, as specified by history item
+void FrameLoader::navigateWithinDocument(HistoryItem* item)
+{
+ ASSERT(!item->document() || item->document() == m_frame->document());
+
+ // Save user view state to the current history item here since we don't do a normal load.
+ // FIXME: Does form state need to be saved here too?
+ history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
+ if (FrameView* view = m_frame->view())
+ view->setWasScrolledByUser(false);
+
+ history()->setCurrentItem(item);
+
+ // loadInSameDocument() actually changes the URL and notifies load delegates of a "fake" load
+ loadInSameDocument(item->url(), item->stateObject(), false);
+
+ // Restore user view state from the current history item here since we don't do a normal load.
+ // Even though we just manually set the current history item, this ASSERT verifies nothing
+ // inside of loadInSameDocument() caused it to change.
+ ASSERT(history()->currentItem() == item);
+ history()->restoreScrollPositionAndViewState();
+}
+
// FIXME: This function should really be split into a couple pieces, some of
// which should be methods of HistoryController and some of which should be
// methods of FrameLoader.
-void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
-{
- if (!m_frame->page())
- return;
+void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType loadType)
+{
+ // Remember this item so we can traverse any child items as child frames load
+ history()->setProvisionalItem(item);
+
+ // Check if we'll be using the page cache. We only use the page cache
+ // if one exists and it is less than _backForwardCacheExpirationInterval
+ // seconds old. If the cache is expired it gets flushed here.
+ if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) {
+ // FIXME: 1800 should not be hardcoded, it should come from
+ // WebKitBackForwardCacheExpirationIntervalKey in WebKit.
+ // Or we should remove WebKitBackForwardCacheExpirationIntervalKey.
+ if (currentTime() - cachedPage->timeStamp() <= 1800) {
+ loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
+ return;
+ }
+
+ LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", history()->provisionalItem()->url().string().ascii().data());
+ pageCache()->remove(item);
+ }
KURL itemURL = item->url();
KURL itemOriginalURL = item->originalURL();
currentURL = documentLoader()->url();
RefPtr<FormData> formData = item->formData();
- // Are we navigating to an anchor within the page?
- // Note if we have child frames we do a real reload, since the child frames might not
- // match our current frame structure, or they might not have the right content. We could
- // check for all that as an additional optimization.
- // We also do not do anchor-style navigation if we're posting a form or navigating from
- // a page that was resulted from a form post.
- bool shouldScroll = !formData && !(history()->currentItem() && history()->currentItem()->formData()) && history()->urlsMatchItem(item);
-
-#if ENABLE(WML)
- // All WML decks should go through the real load mechanism, not the scroll-to-anchor code
- if (frameContainsWMLContent(m_frame))
- shouldScroll = false;
-#endif
-
- if (shouldScroll) {
- // Must do this maintenance here, since we don't go through a real page reload
- history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
-
- if (FrameView* view = m_frame->view())
- view->setWasScrolledByUser(false);
+ bool addedExtraFields = false;
+ ResourceRequest request(itemURL);
- history()->setCurrentItem(item);
+ if (!item->referrer().isNull())
+ request.setHTTPReferrer(item->referrer());
+
+ // If this was a repost that failed the page cache, we might try to repost the form.
+ NavigationAction action;
+ if (formData) {
+ formData->generateFiles(m_frame->page()->chrome()->client());
- // FIXME: Form state might need to be saved here too.
+ request.setHTTPMethod("POST");
+ request.setHTTPBody(formData);
+ request.setHTTPContentType(item->formContentType());
+ RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
+ addHTTPOriginIfNeeded(request, securityOrigin->toString());
- // We always call scrollToAnchor here, even if the URL doesn't have an
- // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
- scrollToAnchor(item->url());
-
- // must do this maintenance here, since we don't go through a real page reload
- history()->restoreScrollPositionAndViewState();
+ // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
+ // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
+ addExtraFieldsToRequest(request, m_loadType, true, formData);
+ addedExtraFields = true;
- // Fake the URL change by updating the data source's request. This will no longer
- // be necessary if we do the better fix described above.
- documentLoader()->replaceRequestURLForAnchorScroll(itemURL);
-
- m_client->dispatchDidChangeLocationWithinPage();
+ // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
+ // We want to know this before talking to the policy delegate, since it affects whether
+ // we show the DoYouReallyWantToRepost nag.
+ //
+ // This trick has a small bug (3123893) where we might find a cache hit, but then
+ // have the item vanish when we try to use it in the ensuing nav. This should be
+ // extremely rare, but in that case the user will get an error on the navigation.
- // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
- m_client->didFinishLoad();
+ if (ResourceHandle::willLoadFromCache(request, m_frame))
+ action = NavigationAction(itemURL, loadType, false);
+ else {
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ action = NavigationAction(itemURL, NavigationTypeFormResubmitted);
+ }
} else {
- // Remember this item so we can traverse any child items as child frames load
- history()->setProvisionalItem(item);
-
- bool inPageCache = false;
-
- // Check if we'll be using the page cache. We only use the page cache
- // if one exists and it is less than _backForwardCacheExpirationInterval
- // seconds old. If the cache is expired it gets flushed here.
- if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) {
- double interval = currentTime() - cachedPage->timeStamp();
-
- // FIXME: 1800 should not be hardcoded, it should come from
- // WebKitBackForwardCacheExpirationIntervalKey in WebKit.
- // Or we should remove WebKitBackForwardCacheExpirationIntervalKey.
- if (interval <= 1800) {
- loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
- inPageCache = true;
- } else {
- LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", history()->provisionalItem()->url().string().ascii().data());
- pageCache()->remove(item);
- }
+ switch (loadType) {
+ case FrameLoadTypeReload:
+ case FrameLoadTypeReloadFromOrigin:
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ break;
+ case FrameLoadTypeBack:
+ case FrameLoadTypeBackWMLDeckNotAccessible:
+ case FrameLoadTypeForward:
+ case FrameLoadTypeIndexedBackForward:
+ if (itemURL.protocolIs("https"))
+ request.setCachePolicy(ReturnCacheDataElseLoad);
+ break;
+ case FrameLoadTypeStandard:
+ case FrameLoadTypeRedirectWithLockedBackForwardList:
+ break;
+ case FrameLoadTypeSame:
+ default:
+ ASSERT_NOT_REACHED();
}
-
- if (!inPageCache) {
- bool addedExtraFields = false;
- ResourceRequest request(itemURL);
- if (!item->referrer().isNull())
- request.setHTTPReferrer(item->referrer());
-
- // If this was a repost that failed the page cache, we might try to repost the form.
- NavigationAction action;
- if (formData) {
-
- formData->generateFiles(m_frame->page()->chrome()->client());
+ action = NavigationAction(itemOriginalURL, loadType, false);
+ }
+
+ if (!addedExtraFields)
+ addExtraFieldsToRequest(request, m_loadType, true, formData);
- request.setHTTPMethod("POST");
- request.setHTTPBody(formData);
- request.setHTTPContentType(item->formContentType());
- RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
- addHTTPOriginIfNeeded(request, securityOrigin->toString());
-
- // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
- // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
- addExtraFieldsToRequest(request, m_loadType, true, formData);
- addedExtraFields = true;
-
- // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
- // We want to know this before talking to the policy delegate, since it affects whether
- // we show the DoYouReallyWantToRepost nag.
- //
- // This trick has a small bug (3123893) where we might find a cache hit, but then
- // have the item vanish when we try to use it in the ensuing nav. This should be
- // extremely rare, but in that case the user will get an error on the navigation.
-
- if (ResourceHandle::willLoadFromCache(request, m_frame))
- action = NavigationAction(itemURL, loadType, false);
- else {
- request.setCachePolicy(ReloadIgnoringCacheData);
- action = NavigationAction(itemURL, NavigationTypeFormResubmitted);
- }
- } else {
- switch (loadType) {
- case FrameLoadTypeReload:
- case FrameLoadTypeReloadFromOrigin:
- request.setCachePolicy(ReloadIgnoringCacheData);
- break;
- case FrameLoadTypeBack:
- case FrameLoadTypeBackWMLDeckNotAccessible:
- case FrameLoadTypeForward:
- case FrameLoadTypeIndexedBackForward:
- if (itemURL.protocol() != "https")
- request.setCachePolicy(ReturnCacheDataElseLoad);
- break;
- case FrameLoadTypeStandard:
- case FrameLoadTypeRedirectWithLockedBackForwardList:
- break;
- case FrameLoadTypeSame:
- default:
- ASSERT_NOT_REACHED();
- }
+ loadWithNavigationAction(request, action, false, loadType, 0);
+}
- action = NavigationAction(itemOriginalURL, loadType, false);
- }
-
- if (!addedExtraFields)
- addExtraFieldsToRequest(request, m_loadType, true, formData);
+// Loads content into this frame, as specified by history item
+void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
+{
+ // We do same-document navigation in the following cases:
+ // - The HistoryItem has a history state object
+ // - Navigating to an anchor within the page, with no form data stored on the target item or the current history entry,
+ // and the URLs in the frame tree match the history item for fragment scrolling.
+ bool sameDocumentNavigation = (!item->formData() && !(history()->currentItem() && history()->currentItem()->formData()) && history()->urlsMatchItem(item)) || item->document() == m_frame->document();
- loadWithNavigationAction(request, action, false, loadType, 0);
- }
- }
+#if ENABLE(WML)
+ // All WML decks should go through the real load mechanism, not the scroll-to-anchor code
+ // FIXME: Why do WML decks have this different behavior?
+ // Are WML decks incompatible with HTML5 pushState/replaceState which require inter-document history navigations?
+ // Should this new API be disabled for WML pages, or does WML need to update their mechanism to act like normal loads?
+ // If scroll-to-anchor navigations were broken for WML and required them to have different loading behavior, then
+ // state object loads are certainly also broken for them.
+ if (frameContainsWMLContent(m_frame))
+ sameDocumentNavigation = false;
+#endif
+
+ if (sameDocumentNavigation)
+ navigateWithinDocument(item);
+ else
+ navigateToDifferentDocument(item, loadType);
}
void FrameLoader::setMainDocumentError(DocumentLoader* loader, const ResourceError& error)
class ScriptString;
class ScriptValue;
class SecurityOrigin;
+class SerializedScriptValue;
class SharedBuffer;
class SubstituteData;
class TextResourceDecoder;
bool loadPlugin(RenderPart*, const KURL&, const String& mimeType,
const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback);
+ void navigateWithinDocument(HistoryItem*);
+ void navigateToDifferentDocument(HistoryItem*, FrameLoadType);
+
bool loadProvisionalItemFromCachedPage();
void cachePageForHistoryItem(HistoryItem*);
void pageHidden();
Frame* loadSubframe(HTMLFrameOwnerElement*, const KURL&, const String& name, const String& referrer);
- void scrollToAnchor(const KURL&);
+ void loadInSameDocument(const KURL&, SerializedScriptValue* stateObject, bool isNewNavigation);
void provisionalLoadStarted();
virtual void dispatchDidCancelClientRedirect() = 0;
virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate) = 0;
virtual void dispatchDidChangeLocationWithinPage() = 0;
+ virtual void dispatchDidPushStateWithinPage() = 0;
+ virtual void dispatchDidReplaceStateWithinPage() = 0;
+ virtual void dispatchDidPopStateWithinPage() = 0;
virtual void dispatchWillClose() = 0;
virtual void dispatchDidReceiveIcon() = 0;
virtual void dispatchDidStartProvisionalLoad() = 0;
}
}
-void HistoryController::updateForAnchorScroll()
+void HistoryController::updateForSameDocumentNavigation()
{
if (m_frame->loader()->url().isEmpty())
return;
page->backForwardList()->addItem(item);
}
+void HistoryController::pushState(PassRefPtr<SerializedScriptValue> stateObject, const String& title, const String& urlString)
+{
+ Page* page = m_frame->page();
+ ASSERT(page);
+ Frame* mainFrame = page->mainFrame();
+ ASSERT(mainFrame);
+
+ // Get a HistoryItem tree for the current frame tree.
+ RefPtr<HistoryItem> item = createItemTree(m_frame, false);
+
+ // Override data in the target item to reflect the pushState() arguments.
+ HistoryItem* targetItem = item->targetItem();
+ ASSERT(targetItem->isTargetItem());
+ targetItem->setDocument(m_frame->document());
+ targetItem->setTitle(title);
+ targetItem->setStateObject(stateObject);
+ targetItem->setURLString(urlString);
+
+ page->backForwardList()->pushStateItem(item.release());
+}
+
+void HistoryController::replaceState(PassRefPtr<SerializedScriptValue> stateObject, const String& title, const String& urlString)
+{
+ Page* page = m_frame->page();
+ ASSERT(page);
+ HistoryItem* current = page->backForwardList()->currentItem();
+ ASSERT(current);
+
+ ASSERT(!current->document() || current->document() == m_frame->document());
+ current->setDocument(m_frame->document());
+
+ if (!urlString.isEmpty())
+ current->setURLString(urlString);
+ current->setTitle(title);
+ current->setStateObject(stateObject);
+}
+
} // namespace WebCore
class Frame;
class HistoryItem;
+class SerializedScriptValue;
class HistoryController : public Noncopyable {
public:
void updateForRedirectWithLockedBackForwardList();
void updateForClientRedirect();
void updateForCommit();
- void updateForAnchorScroll();
+ void updateForSameDocumentNavigation();
void updateForFrameLoadCompleted();
HistoryItem* currentItem() const { return m_currentItem.get(); }
HistoryItem* provisionalItem() const { return m_provisionalItem.get(); }
void setProvisionalItem(HistoryItem*);
+ void pushState(PassRefPtr<SerializedScriptValue>, const String& title, const String& url);
+ void replaceState(PassRefPtr<SerializedScriptValue>, const String& title, const String& url);
+
private:
PassRefPtr<HistoryItem> createItem(bool useOriginal);
PassRefPtr<HistoryItem> createItemTree(Frame* targetFrame, bool clipAtTarget);
void dispatchLoadEvent();
DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(beforeunload);
DEFINE_ATTRIBUTE_EVENT_LISTENER(blur);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(canplay);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(canplaythrough);
DEFINE_ATTRIBUTE_EVENT_LISTENER(change);
DEFINE_ATTRIBUTE_EVENT_LISTENER(click);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dblclick);
DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragover);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
DEFINE_ATTRIBUTE_EVENT_LISTENER(drop);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(durationchange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(emptied);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(ended);
DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
DEFINE_ATTRIBUTE_EVENT_LISTENER(focus);
DEFINE_ATTRIBUTE_EVENT_LISTENER(hashchange);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
DEFINE_ATTRIBUTE_EVENT_LISTENER(keypress);
DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup);
DEFINE_ATTRIBUTE_EVENT_LISTENER(load);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(loadeddata);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(loadedmetadata);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown);
DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove);
DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout);
DEFINE_ATTRIBUTE_EVENT_LISTENER(online);
DEFINE_ATTRIBUTE_EVENT_LISTENER(pagehide);
DEFINE_ATTRIBUTE_EVENT_LISTENER(pageshow);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(pause);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(play);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(playing);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(popstate);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(progress);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(ratechange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(reset);
DEFINE_ATTRIBUTE_EVENT_LISTENER(resize);
DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(seeked);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(seeking);
DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(stalled);
DEFINE_ATTRIBUTE_EVENT_LISTENER(storage);
DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(unload);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(beforeunload);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(canplay);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(canplaythrough);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(durationchange);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(emptied);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(ended);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(loadeddata);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(loadedmetadata);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(pause);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(play);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(playing);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(ratechange);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(seeked);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(seeking);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(suspend);
DEFINE_ATTRIBUTE_EVENT_LISTENER(timeupdate);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(unload);
DEFINE_ATTRIBUTE_EVENT_LISTENER(volumechange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(waiting);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart);
DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitbeginfullscreen);
DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitendfullscreen);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(progress);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(stalled);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(suspend);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
+
#if ENABLE(ORIENTATION_EVENTS)
DEFINE_ATTRIBUTE_EVENT_LISTENER(orientationchange);
#endif
attribute EventListener onpause;
attribute EventListener onplay;
attribute EventListener onplaying;
+ attribute EventListener onpopstate;
attribute EventListener onprogress;
attribute EventListener onratechange;
attribute EventListener onresize;
#include "config.h"
#include "History.h"
+#include "ExceptionCode.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "HistoryItem.h"
#include "Page.h"
namespace WebCore {
m_frame->redirectScheduler()->scheduleHistoryNavigation(distance);
}
+KURL History::urlForState(const String& urlString)
+{
+ KURL baseURL = m_frame->loader()->baseURL();
+ if (urlString.isEmpty())
+ return baseURL;
+
+ KURL absoluteURL(baseURL, urlString);
+ if (!absoluteURL.isValid())
+ return KURL();
+
+ if (absoluteURL.string().left(absoluteURL.pathStart()) != baseURL.string().left(baseURL.pathStart()))
+ return KURL();
+
+ return absoluteURL;
+}
+
+void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& title, const String& urlString, StateObjectType stateObjectType, ExceptionCode& ec)
+{
+ if (!m_frame)
+ return;
+ ASSERT(m_frame->page());
+
+ KURL fullURL = urlForState(urlString);
+ if (!fullURL.isValid()) {
+ ec = SECURITY_ERR;
+ return;
+ }
+
+ if (stateObjectType == StateObjectPush)
+ m_frame->loader()->history()->pushState(data, title, fullURL.string());
+ else if (stateObjectType == StateObjectReplace)
+ m_frame->loader()->history()->replaceState(data, title, fullURL.string());
+
+ if (!urlString.isEmpty()) {
+ m_frame->document()->updateURLForPushOrReplaceState(fullURL);
+ if (stateObjectType == StateObjectPush)
+ m_frame->loader()->client()->dispatchDidPushStateWithinPage();
+ else if (stateObjectType == StateObjectReplace)
+ m_frame->loader()->client()->dispatchDidReplaceStateWithinPage();
+ }
+}
+
} // namespace WebCore
#ifndef History_h
#define History_h
+#include "KURL.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
namespace WebCore {
- class Frame;
+class Frame;
+class SerializedScriptValue;
+class String;
+typedef int ExceptionCode;
- class History : public RefCounted<History> {
- public:
- static PassRefPtr<History> create(Frame* frame) { return adoptRef(new History(frame)); }
-
- Frame* frame() const;
- void disconnectFrame();
+class History : public RefCounted<History> {
+public:
+ static PassRefPtr<History> create(Frame* frame) { return adoptRef(new History(frame)); }
+
+ Frame* frame() const;
+ void disconnectFrame();
- unsigned length() const;
- void back();
- void forward();
- void go(int distance);
+ unsigned length() const;
+ void back();
+ void forward();
+ void go(int distance);
- private:
- History(Frame*);
-
- Frame* m_frame;
+ enum StateObjectType {
+ StateObjectPush,
+ StateObjectReplace
};
+ void stateObjectAdded(PassRefPtr<SerializedScriptValue>, const String& title, const String& url, StateObjectType, ExceptionCode&);
+
+private:
+ History(Frame*);
+
+ KURL urlForState(const String& url);
+
+ Frame* m_frame;
+};
} // namespace WebCore
[DoNotCheckDomainSecurity] void back();
[DoNotCheckDomainSecurity] void forward();
[DoNotCheckDomainSecurity] void go(in long distance);
+
+ [Custom] void pushState(in any data, in DOMString title, in optional DOMString url)
+ raises(DOMException);
+ [Custom] void replaceState(in any data, in DOMString title, in optional DOMString url)
+ raises(DOMException);
};
}
#include "config.h"
#include "Page.h"
+#include "BackForwardList.h"
#include "Base64.h"
#include "CSSStyleSelector.h"
#include "Chrome.h"
void Page::goToItem(HistoryItem* item, FrameLoadType type)
{
- // Abort any current load if we're going to a history item
+#if !ASSERT_DISABLED
+ // If we're navigating to an item with history state for a Document other than the
+ // current Document, the new Document had better be in the page cache.
+ if (item->stateObject() && item->document() != m_mainFrame->document())
+ ASSERT(item->document()->inPageCache());
+#endif
- // Define what to do with any open database connections. By default we stop them and terminate the database thread.
- DatabasePolicy databasePolicy = DatabasePolicyStop;
+ // Abort any current load unless we're navigating the current document to a new state object
+ if (!item->stateObject() || item->document() != m_mainFrame->document()) {
+ // Define what to do with any open database connections. By default we stop them and terminate the database thread.
+ DatabasePolicy databasePolicy = DatabasePolicyStop;
#if ENABLE(DATABASE)
- // If we're navigating the history via a fragment on the same document, then we do not want to stop databases.
- const KURL& currentURL = m_mainFrame->loader()->url();
- const KURL& newURL = item->url();
-
- if (newURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(currentURL, newURL))
- databasePolicy = DatabasePolicyContinue;
+ // If we're navigating the history via a fragment on the same document, then we do not want to stop databases.
+ const KURL& currentURL = m_mainFrame->loader()->url();
+ const KURL& newURL = item->url();
+
+ if (newURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(currentURL, newURL))
+ databasePolicy = DatabasePolicyContinue;
#endif
- m_mainFrame->loader()->stopAllLoaders(databasePolicy);
+
+ m_mainFrame->loader()->stopAllLoaders(databasePolicy);
+ }
+
m_mainFrame->loader()->history()->goToItem(item, type);
}
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ * src/FrameLoaderClientImpl.cpp:
+ (WebKit::FrameLoaderClientImpl::dispatchDidPushStateWithinPage):
+ (WebKit::FrameLoaderClientImpl::dispatchDidReplaceStateWithinPage):
+ (WebKit::FrameLoaderClientImpl::dispatchDidPopStateWithinPage):
+ * src/FrameLoaderClientImpl.h:
+
2009-12-03 Pavel Feldman <pfeldman@chromium.org>
Reviewed by Timothy Hatcher.
webView->client()->didStopLoading();
}
+void FrameLoaderClientImpl::dispatchDidPushStateWithinPage()
+{
+ // FIXME
+}
+
+void FrameLoaderClientImpl::dispatchDidReplaceStateWithinPage()
+{
+ // FIXME
+}
+
+void FrameLoaderClientImpl::dispatchDidPopStateWithinPage()
+{
+ // FIXME
+}
+
void FrameLoaderClientImpl::dispatchWillClose()
{
if (m_webFrame->client())
virtual void dispatchDidCancelClientRedirect();
virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&, double interval, double fireDate);
virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchDidPushStateWithinPage();
+ virtual void dispatchDidReplaceStateWithinPage();
+ virtual void dispatchDidPopStateWithinPage();
virtual void dispatchWillClose();
virtual void dispatchDidReceiveIcon();
virtual void dispatchDidStartProvisionalLoad();
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ * WebCoreSupport/FrameLoaderClientGtk.cpp:
+ (WebKit::FrameLoaderClient::dispatchDidPushStateWithinPage):
+ (WebKit::FrameLoaderClient::dispatchDidReplaceStateWithinPage):
+ (WebKit::FrameLoaderClient::dispatchDidPopStateWithinPage):
+ * WebCoreSupport/FrameLoaderClientGtk.h:
+
2009-12-03 Pavel Feldman <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
Reviewed by Timothy Hatcher.
g_object_notify(G_OBJECT(webView), "uri");
}
+void FrameLoaderClient::dispatchDidPushStateWithinPage()
+{
+ notImplemented();
+}
+
+void FrameLoaderClient::dispatchDidReplaceStateWithinPage()
+{
+ notImplemented();
+}
+
+void FrameLoaderClient::dispatchDidPopStateWithinPage()
+{
+ notImplemented();
+}
+
void FrameLoaderClient::dispatchWillClose()
{
notImplemented();
virtual void dispatchDidCancelClientRedirect();
virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&, double, double);
virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchDidPushStateWithinPage();
+ virtual void dispatchDidReplaceStateWithinPage();
+ virtual void dispatchDidPopStateWithinPage();
virtual void dispatchWillClose();
virtual void dispatchDidReceiveIcon();
virtual void dispatchDidStartProvisionalLoad();
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ * WebCoreSupport/WebFrameLoaderClient.h:
+ * WebCoreSupport/WebFrameLoaderClient.mm:
+ (WebFrameLoaderClient::dispatchDidPushStateWithinPage):
+ (WebFrameLoaderClient::dispatchDidReplaceStateWithinPage):
+ (WebFrameLoaderClient::dispatchDidPopStateWithinPage):
+ * WebView/WebDelegateImplementationCaching.h:
+ * WebView/WebFrameLoadDelegatePrivate.h:
+ * WebView/WebView.mm:
+ (-[WebView _cacheFrameLoadDelegateImplementations]):
+
2009-12-03 Pavel Feldman <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
Reviewed by Timothy Hatcher.
virtual void dispatchDidCancelClientRedirect();
virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&, double interval, double fireDate);
virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchDidPushStateWithinPage();
+ virtual void dispatchDidReplaceStateWithinPage();
+ virtual void dispatchDidPopStateWithinPage();
+
virtual void dispatchWillClose();
virtual void dispatchDidReceiveIcon();
virtual void dispatchDidStartProvisionalLoad();
CallFrameLoadDelegate(implementations->didChangeLocationWithinPageForFrameFunc, webView, @selector(webView:didChangeLocationWithinPageForFrame:), m_webFrame.get());
}
+void WebFrameLoaderClient::dispatchDidPushStateWithinPage()
+{
+ WebView *webView = getWebView(m_webFrame.get());
+ WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
+ if (implementations->didPushStateWithinPageForFrameFunc)
+ CallFrameLoadDelegate(implementations->didPushStateWithinPageForFrameFunc, webView, @selector(webView:didPushStateWithinPageForFrame:), m_webFrame.get());
+}
+
+void WebFrameLoaderClient::dispatchDidReplaceStateWithinPage()
+{
+ WebView *webView = getWebView(m_webFrame.get());
+ WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
+ if (implementations->didReplaceStateWithinPageForFrameFunc)
+ CallFrameLoadDelegate(implementations->didReplaceStateWithinPageForFrameFunc, webView, @selector(webView:didReplaceStateWithinPageForFrame:), m_webFrame.get());
+}
+
+void WebFrameLoaderClient::dispatchDidPopStateWithinPage()
+{
+ WebView *webView = getWebView(m_webFrame.get());
+ WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(webView);
+ if (implementations->didPopStateWithinPageForFrameFunc)
+ CallFrameLoadDelegate(implementations->didPopStateWithinPageForFrameFunc, webView, @selector(webView:didPopStateWithinPageForFrame:), m_webFrame.get());
+}
+
void WebFrameLoaderClient::dispatchWillClose()
{
WebView *webView = getWebView(m_webFrame.get());
IMP didCancelClientRedirectForFrameFunc;
IMP willPerformClientRedirectToURLDelayFireDateForFrameFunc;
IMP didChangeLocationWithinPageForFrameFunc;
+ IMP didPushStateWithinPageForFrameFunc;
+ IMP didReplaceStateWithinPageForFrameFunc;
+ IMP didPopStateWithinPageForFrameFunc;
IMP willCloseFrameFunc;
IMP didStartProvisionalLoadForFrameFunc;
IMP didReceiveTitleForFrameFunc;
- (void)webView:(WebView *)webView didClearWindowObjectForFrame:(WebFrame *)frame inScriptWorld:(WebScriptWorld *)world;
+- (void)webView:(WebView *)webView didPushStateWithinPageForFrame:(WebFrame *)frame;
+- (void)webView:(WebView *)webView didReplaceStateWithinPageForFrame:(WebFrame *)frame;
+- (void)webView:(WebView *)webView didPopStateWithinPageForFrame:(WebFrame *)frame;
+
@end
cache->didCancelClientRedirectForFrameFunc = getMethod(delegate, @selector(webView:didCancelClientRedirectForFrame:));
cache->didChangeLocationWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didChangeLocationWithinPageForFrame:));
+ cache->didPushStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPushStateWithinPageForFrame:));
+ cache->didReplaceStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didReplaceStateWithinPageForFrame:));
+ cache->didPopStateWithinPageForFrameFunc = getMethod(delegate, @selector(webView:didPopStateWithinPageForFrame:));
cache->didClearWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearWindowObject:forFrame:));
cache->didClearWindowObjectForFrameInScriptWorldFunc = getMethod(delegate, @selector(webView:didClearWindowObjectForFrame:inScriptWorld:));
cache->didClearInspectorWindowObjectForFrameFunc = getMethod(delegate, @selector(webView:didClearInspectorWindowObject:forFrame:));
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ * WebCoreSupport/FrameLoaderClientQt.cpp:
+ (WebCore::FrameLoaderClientQt::dispatchDidPushStateWithinPage):
+ (WebCore::FrameLoaderClientQt::dispatchDidReplaceStateWithinPage):
+ (WebCore::FrameLoaderClientQt::dispatchDidPopStateWithinPage):
+ * WebCoreSupport/FrameLoaderClientQt.h:
+
2009-12-03 Pavel Feldman <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
Reviewed by Timothy Hatcher.
m_webFrame->page()->d->updateNavigationActions();
}
+void FrameLoaderClientQt::dispatchDidPushStateWithinPage()
+{
+ if (dumpFrameLoaderCallbacks)
+ printf("%s - dispatchDidPushStateWithinPage\n", qPrintable(drtDescriptionSuitableForTestResult(m_frame)));
+
+ notImplemented();
+}
+
+void FrameLoaderClientQt::dispatchDidReplaceStateWithinPage()
+{
+ if (dumpFrameLoaderCallbacks)
+ printf("%s - dispatchDidReplaceStateWithinPage\n", qPrintable(drtDescriptionSuitableForTestResult(m_frame)));
+
+ notImplemented();
+}
+
+void FrameLoaderClientQt::dispatchDidPopStateWithinPage()
+{
+ if (dumpFrameLoaderCallbacks)
+ printf("%s - dispatchDidPopStateWithinPage\n", qPrintable(drtDescriptionSuitableForTestResult(m_frame)));
+
+ notImplemented();
+}
void FrameLoaderClientQt::dispatchWillClose()
{
virtual void dispatchDidCancelClientRedirect();
virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate);
virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchDidPushStateWithinPage();
+ virtual void dispatchDidReplaceStateWithinPage();
+ virtual void dispatchDidPopStateWithinPage();
virtual void dispatchWillClose();
virtual void dispatchDidReceiveIcon();
virtual void dispatchDidStartProvisionalLoad();
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ * Interfaces/IWebFrameLoadDelegatePrivate2.idl:
+ * WebCoreSupport/WebFrameLoaderClient.cpp:
+ (WebFrameLoaderClient::dispatchDidPushStateWithinPage):
+ (WebFrameLoaderClient::dispatchDidReplaceStateWithinPage):
+ (WebFrameLoaderClient::dispatchDidPopStateWithinPage):
+ * WebCoreSupport/WebFrameLoaderClient.h:
+
2009-12-03 Pavel Feldman <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
Reviewed by Timothy Hatcher.
HRESULT didRunInsecureContent([in] IWebView* sender, [in] IWebSecurityOrigin* origin);
HRESULT didClearWindowObjectForFrameInScriptWorld([in] IWebView* webView, [in] IWebFrame* frame, [in] IWebScriptWorld*);
+
+ HRESULT didPushStateWithinPageForFrame([in] IWebView* webView, [in] IWebFrame* frame);
+ HRESULT didReplaceStateWithinPageForFrame([in] IWebView* webView, [in] IWebFrame* frame);
+ HRESULT didPopStateWithinPageForFrame([in] IWebView* webView, [in] IWebFrame* frame);
}
frameLoadDelegate->didChangeLocationWithinPageForFrame(webView, m_webFrame);
}
+void WebFrameLoaderClient::dispatchDidPushStateWithinPage()
+{
+ WebView* webView = m_webFrame->webView();
+ COMPtr<IWebFrameLoadDelegatePrivate> frameLoadDelegatePriv;
+ if (FAILED(webView->frameLoadDelegatePrivate(&frameLoadDelegatePriv)) || !frameLoadDelegatePriv)
+ return;
+
+ COMPtr<IWebFrameLoadDelegatePrivate2> frameLoadDelegatePriv2(Query, frameLoadDelegatePriv);
+ if (!frameLoadDelegatePriv2)
+ return;
+
+ frameLoadDelegatePriv2->didPushStateWithinPageForFrame(webView, m_webFrame);
+}
+
+void WebFrameLoaderClient::dispatchDidReplaceStateWithinPage()
+{
+ WebView* webView = m_webFrame->webView();
+ COMPtr<IWebFrameLoadDelegatePrivate> frameLoadDelegatePriv;
+ if (FAILED(webView->frameLoadDelegatePrivate(&frameLoadDelegatePriv)) || !frameLoadDelegatePriv)
+ return;
+
+ COMPtr<IWebFrameLoadDelegatePrivate2> frameLoadDelegatePriv2(Query, frameLoadDelegatePriv);
+ if (!frameLoadDelegatePriv2)
+ return;
+
+ frameLoadDelegatePriv2->didReplaceStateWithinPageForFrame(webView, m_webFrame);
+}
+
+void WebFrameLoaderClient::dispatchDidPopStateWithinPage()
+{
+ WebView* webView = m_webFrame->webView();
+ COMPtr<IWebFrameLoadDelegatePrivate> frameLoadDelegatePriv;
+ if (FAILED(webView->frameLoadDelegatePrivate(&frameLoadDelegatePriv)) || !frameLoadDelegatePriv)
+ return;
+
+ COMPtr<IWebFrameLoadDelegatePrivate2> frameLoadDelegatePriv2(Query, frameLoadDelegatePriv);
+ if (!frameLoadDelegatePriv2)
+ return;
+
+ frameLoadDelegatePriv2->didPopStateWithinPageForFrame(webView, m_webFrame);
+}
void WebFrameLoaderClient::dispatchWillClose()
{
WebView* webView = m_webFrame->webView();
virtual void dispatchDidCancelClientRedirect();
virtual void dispatchWillPerformClientRedirect(const WebCore::KURL&, double interval, double fireDate);
virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchDidPushStateWithinPage();
+ virtual void dispatchDidReplaceStateWithinPage();
+ virtual void dispatchDidPopStateWithinPage();
virtual void dispatchWillClose();
virtual void dispatchDidReceiveIcon();
virtual void dispatchDidStartProvisionalLoad();
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ * WebKitSupport/FrameLoaderClientWx.cpp:
+ (WebCore::FrameLoaderClientWx::dispatchDidPushStateWithinPage):
+ (WebCore::FrameLoaderClientWx::dispatchDidReplaceStateWithinPage):
+ (WebCore::FrameLoaderClientWx::dispatchDidPopStateWithinPage):
+ * WebKitSupport/FrameLoaderClientWx.h:
+
2009-12-03 Pavel Feldman <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
Reviewed by Timothy Hatcher.
notImplemented();
}
+void FrameLoaderClientWx::dispatchDidPushStateWithinPage()
+{
+ notImplemented();
+}
+
+void FrameLoaderClientWx::dispatchDidReplaceStateWithinPage()
+{
+ notImplemented();
+}
+
+void FrameLoaderClientWx::dispatchDidPopStateWithinPage()
+{
+ notImplemented();
+}
void FrameLoaderClientWx::dispatchWillClose()
{
virtual void dispatchDidCancelClientRedirect();
virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate);
virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchDidPushStateWithinPage();
+ virtual void dispatchDidReplaceStateWithinPage();
+ virtual void dispatchDidPopStateWithinPage();
virtual void dispatchWillClose();
virtual void dispatchDidReceiveIcon();
virtual void dispatchDidStartProvisionalLoad();
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ Keep DRT-win building...
+
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+ (FrameLoadDelegate::didPushStateWithinPageForFrame):
+ (FrameLoadDelegate::didReplaceStateWithinPageForFrame):
+ (FrameLoadDelegate::didPopStateWithinPageForFrame):
+
2009-12-03 Andras Becsi <abecsi@inf.u-szeged.hu>
Unreviewed build fix.
virtual HRESULT STDMETHODCALLTYPE didClearWindowObjectForFrameInScriptWorld(IWebView*, IWebFrame*, IWebScriptWorld*);
+ virtual HRESULT STDMETHODCALLTYPE didPushStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didReplaceStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
+ virtual HRESULT STDMETHODCALLTYPE didPopStateWithinPageForFrame(
+ /* [in] */ IWebView *sender,
+ /* [in] */ IWebFrame *frame) { return E_NOTIMPL; }
+
private:
void didClearWindowObjectForFrameInIsolatedWorld(IWebFrame*, IWebScriptWorld*);
void didClearWindowObjectForFrameInStandardWorld(IWebFrame*);