[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

beidson at apple.com beidson at apple.com
Thu Apr 8 00:14:42 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 08c617589ca4fe180ff37f80fe4d16d3b192d9ee
Author: beidson at apple.com <beidson at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Dec 3 19:04:40 2009 +0000

    <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
    
    Reviewed by Sam Weinig.
    
    WebCore:
    
    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.
    
    WebKit/chromium:
    
    * src/FrameLoaderClientImpl.cpp:
    (WebKit::FrameLoaderClientImpl::dispatchDidPushStateWithinPage):
    (WebKit::FrameLoaderClientImpl::dispatchDidReplaceStateWithinPage):
    (WebKit::FrameLoaderClientImpl::dispatchDidPopStateWithinPage):
    * src/FrameLoaderClientImpl.h:
    
    WebKit/gtk:
    
    * WebCoreSupport/FrameLoaderClientGtk.cpp:
    (WebKit::FrameLoaderClient::dispatchDidPushStateWithinPage):
    (WebKit::FrameLoaderClient::dispatchDidReplaceStateWithinPage):
    (WebKit::FrameLoaderClient::dispatchDidPopStateWithinPage):
    * WebCoreSupport/FrameLoaderClientGtk.h:
    
    WebKit/mac:
    
    * WebCoreSupport/WebFrameLoaderClient.h:
    * WebCoreSupport/WebFrameLoaderClient.mm:
    (WebFrameLoaderClient::dispatchDidPushStateWithinPage):
    (WebFrameLoaderClient::dispatchDidReplaceStateWithinPage):
    (WebFrameLoaderClient::dispatchDidPopStateWithinPage):
    * WebView/WebDelegateImplementationCaching.h:
    * WebView/WebFrameLoadDelegatePrivate.h:
    * WebView/WebView.mm:
    (-[WebView _cacheFrameLoadDelegateImplementations]):
    
    WebKit/qt:
    
    * WebCoreSupport/FrameLoaderClientQt.cpp:
    (WebCore::FrameLoaderClientQt::dispatchDidPushStateWithinPage):
    (WebCore::FrameLoaderClientQt::dispatchDidReplaceStateWithinPage):
    (WebCore::FrameLoaderClientQt::dispatchDidPopStateWithinPage):
    * WebCoreSupport/FrameLoaderClientQt.h:
    
    WebKit/win:
    
    * Interfaces/IWebFrameLoadDelegatePrivate2.idl:
    * WebCoreSupport/WebFrameLoaderClient.cpp:
    (WebFrameLoaderClient::dispatchDidPushStateWithinPage):
    (WebFrameLoaderClient::dispatchDidReplaceStateWithinPage):
    (WebFrameLoaderClient::dispatchDidPopStateWithinPage):
    * WebCoreSupport/WebFrameLoaderClient.h:
    
    WebKit/wx:
    
    * WebKitSupport/FrameLoaderClientWx.cpp:
    (WebCore::FrameLoaderClientWx::dispatchDidPushStateWithinPage):
    (WebCore::FrameLoaderClientWx::dispatchDidReplaceStateWithinPage):
    (WebCore::FrameLoaderClientWx::dispatchDidPopStateWithinPage):
    * WebKitSupport/FrameLoaderClientWx.h:
    
    WebKitTools:
    
    Keep DRT-win building...
    
    * DumpRenderTree/win/FrameLoadDelegate.h:
    (FrameLoadDelegate::didPushStateWithinPageForFrame):
    (FrameLoadDelegate::didReplaceStateWithinPageForFrame):
    (FrameLoadDelegate::didPopStateWithinPageForFrame):
    
    LayoutTests:
    
    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.
    
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@51644 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 4bef668..965fa11 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,41 @@
+2009-12-03  Brady Eidson  <beidson at 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 at collabora.co.uk>
 
         Reviewed by Xan Lopez.
diff --git a/LayoutTests/fast/dom/Window/window-appendages-cleared-expected.txt b/LayoutTests/fast/dom/Window/window-appendages-cleared-expected.txt
index 63ef8fd..272aa7f 100644
--- a/LayoutTests/fast/dom/Window/window-appendages-cleared-expected.txt
+++ b/LayoutTests/fast/dom/Window/window-appendages-cleared-expected.txt
@@ -2,6 +2,8 @@ PASS history.back == "LEFTOVER" is false
 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
diff --git a/LayoutTests/fast/dom/Window/window-properties-expected.txt b/LayoutTests/fast/dom/Window/window-properties-expected.txt
index 420c518..c0f2831 100644
--- a/LayoutTests/fast/dom/Window/window-properties-expected.txt
+++ b/LayoutTests/fast/dom/Window/window-properties-expected.txt
@@ -1737,6 +1737,8 @@ window.history.back [function]
 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]
@@ -1813,6 +1815,7 @@ window.onpageshow [null]
 window.onpause [null]
 window.onplay [null]
 window.onplaying [null]
+window.onpopstate [null]
 window.onprogress [null]
 window.onratechange [null]
 window.onreset [null]
diff --git a/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-expected.txt b/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-expected.txt
new file mode 100644
index 0000000..23fc936
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-expected.txt
@@ -0,0 +1,22 @@
+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
+
diff --git a/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll-expected.txt b/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll-expected.txt
new file mode 100644
index 0000000..9a76bb2
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll-expected.txt
@@ -0,0 +1,23 @@
+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
+
diff --git a/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html b/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html
new file mode 100644
index 0000000..4444358
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html
@@ -0,0 +1,95 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html b/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html
new file mode 100644
index 0000000..d910249
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html
@@ -0,0 +1,88 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener-expected.txt b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener-expected.txt
new file mode 100644
index 0000000..061ea73
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener-expected.txt
@@ -0,0 +1,11 @@
+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)
+
diff --git a/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html
new file mode 100644
index 0000000..75b969f
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html
@@ -0,0 +1,46 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute-expected.txt b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute-expected.txt
new file mode 100644
index 0000000..43ea542
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute-expected.txt
@@ -0,0 +1,11 @@
+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)
+
diff --git a/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html
new file mode 100644
index 0000000..9505736
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html
@@ -0,0 +1,48 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute-expected.txt b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute-expected.txt
new file mode 100644
index 0000000..43ea542
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute-expected.txt
@@ -0,0 +1,11 @@
+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)
+
diff --git a/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html
new file mode 100644
index 0000000..26fca1c
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html
@@ -0,0 +1,45 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute-expected.txt b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute-expected.txt
new file mode 100644
index 0000000..c9d4b29
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute-expected.txt
@@ -0,0 +1,11 @@
+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)
+
diff --git a/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html
new file mode 100644
index 0000000..62569a5
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html
@@ -0,0 +1,46 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/pushstate-object-types-expected.txt b/LayoutTests/fast/loader/stateobjects/pushstate-object-types-expected.txt
new file mode 100644
index 0000000..5952194
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/pushstate-object-types-expected.txt
@@ -0,0 +1,15 @@
+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)
+
diff --git a/LayoutTests/fast/loader/stateobjects/pushstate-object-types.html b/LayoutTests/fast/loader/stateobjects/pushstate-object-types.html
new file mode 100644
index 0000000..8f31981
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/pushstate-object-types.html
@@ -0,0 +1,58 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate-expected.txt b/LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate-expected.txt
new file mode 100644
index 0000000..d7fafd9
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate-expected.txt
@@ -0,0 +1,13 @@
+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)
+
diff --git a/LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate.html b/LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate.html
new file mode 100644
index 0000000..976013e
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate.html
@@ -0,0 +1,47 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange-expected.txt b/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange-expected.txt
new file mode 100644
index 0000000..a4cb868
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange-expected.txt
@@ -0,0 +1,34 @@
+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
+
diff --git a/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html b/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html
new file mode 100644
index 0000000..a148687
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html
@@ -0,0 +1,63 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate-expected.txt b/LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate-expected.txt
new file mode 100644
index 0000000..5870bd1
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate-expected.txt
@@ -0,0 +1,13 @@
+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)
+
diff --git a/LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate.html b/LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate.html
new file mode 100644
index 0000000..826264a
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate.html
@@ -0,0 +1,47 @@
+<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>
diff --git a/LayoutTests/fast/loader/stateobjects/resources/navigate-back.html b/LayoutTests/fast/loader/stateobjects/resources/navigate-back.html
new file mode 100644
index 0000000..eda9cc5
--- /dev/null
+++ b/LayoutTests/fast/loader/stateobjects/resources/navigate-back.html
@@ -0,0 +1,3 @@
+<html>
+<body onload="alert('Navigating back...'); sessionStorage.stage = 2; history.back();"></body>
+</html>
diff --git a/LayoutTests/http/tests/loading/state-object-security-exception-expected.txt b/LayoutTests/http/tests/loading/state-object-security-exception-expected.txt
new file mode 100644
index 0000000..ad3b829
--- /dev/null
+++ b/LayoutTests/http/tests/loading/state-object-security-exception-expected.txt
@@ -0,0 +1,32 @@
+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
+
diff --git a/LayoutTests/http/tests/loading/state-object-security-exception.html b/LayoutTests/http/tests/loading/state-object-security-exception.html
new file mode 100644
index 0000000..8a027b2
--- /dev/null
+++ b/LayoutTests/http/tests/loading/state-object-security-exception.html
@@ -0,0 +1,56 @@
+<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>
diff --git a/LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt b/LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
index 25a71de..26b4365 100644
--- a/LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
+++ b/LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
@@ -10,6 +10,10 @@ CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http
 
 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)
 
 
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 1a7d5b0..f0b3445 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,127 @@
+2009-12-03  Brady Eidson  <beidson at 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 at chromium.org>
 
         Not reviewed: chromium build fix.
diff --git a/WebCore/DerivedSources.cpp b/WebCore/DerivedSources.cpp
index bce87d2..e96b606 100644
--- a/WebCore/DerivedSources.cpp
+++ b/WebCore/DerivedSources.cpp
@@ -181,6 +181,7 @@
 #include "JSPageTransitionEvent.cpp"
 #include "JSPlugin.cpp"
 #include "JSPluginArray.cpp"
+#include "JSPopStateEvent.cpp"
 #include "JSProcessingInstruction.cpp"
 #include "JSProgressEvent.cpp"
 #include "JSRange.cpp"
diff --git a/WebCore/DerivedSources.make b/WebCore/DerivedSources.make
index 9e03f13..3f192fc 100644
--- a/WebCore/DerivedSources.make
+++ b/WebCore/DerivedSources.make
@@ -228,6 +228,7 @@ DOM_CLASSES = \
     PageTransitionEvent \
     Plugin \
     PluginArray \
+    PopStateEvent \
     PositionError \
     ProcessingInstruction \
     ProgressEvent \
diff --git a/WebCore/GNUmakefile.am b/WebCore/GNUmakefile.am
index 834029b..2d8eb2f 100644
--- a/WebCore/GNUmakefile.am
+++ b/WebCore/GNUmakefile.am
@@ -141,6 +141,7 @@ IDL_BINDINGS += \
 	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 \
@@ -432,6 +433,8 @@ webcore_sources += \
 	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 \
@@ -772,6 +775,8 @@ webcore_sources += \
 	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 \
diff --git a/WebCore/WebCore.pro b/WebCore/WebCore.pro
index 79f03bb..a8106c1 100644
--- a/WebCore/WebCore.pro
+++ b/WebCore/WebCore.pro
@@ -361,6 +361,7 @@ IDL_BINDINGS += \
     dom/Notation.idl \
     dom/OverflowEvent.idl \
     dom/PageTransitionEvent.idl \
+    dom/PopStateEvent.idl \
     dom/ProcessingInstruction.idl \
     dom/ProgressEvent.idl \
     dom/RangeException.idl \
@@ -756,6 +757,7 @@ SOURCES += \
     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 \
@@ -897,6 +899,7 @@ SOURCES += \
     dom/OptionElement.cpp \
     dom/OverflowEvent.cpp \
     dom/PageTransitionEvent.cpp \
+    dom/PopStateEvent.cpp \
     dom/Position.cpp \
     dom/PositionIterator.cpp \
     dom/ProcessingInstruction.cpp \
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index aa53a85..d2e4e6b 100644
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -9211,6 +9211,62 @@
 				>
 			</File>
 			<File
+				RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPopStateEvent.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Internal|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_All|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPopStateEvent.h"
+				>
+			</File>
+			<File
 				RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPositionError.cpp"
 				>
 				<FileConfiguration
@@ -28795,6 +28851,14 @@
 				>
 			</File>
 			<File
+				RelativePath="..\dom\PopStateEvent.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\dom\PopStateEvent.h"
+				>
+			</File>
+			<File
 				RelativePath="..\dom\Position.cpp"
 				>
 			</File>
@@ -38334,6 +38398,10 @@
 					>
 				</File>
 				<File
+					RelativePath="..\bindings\js\JSPopStateEventCustom.cpp"
+					>
+				</File>
+				<File
 					RelativePath="..\bindings\js\JSQuarantinedObjectWrapper.cpp"
 					>
 					<FileConfiguration
@@ -42389,10 +42457,10 @@
 					RelativePath="..\inspector\front-end\Color.js"
 					>
 				</File>
-                <File
-                    RelativePath="..\inspector\front-end\ConsolePanel.js"
-                    >
-                </File>
+				<File
+					RelativePath="..\inspector\front-end\ConsolePanel.js"
+					>
+				</File>
 				<File
 					RelativePath="..\inspector\front-end\ConsoleView.js"
 					>
@@ -42606,11 +42674,11 @@
 					>
 				</File>
 				<File
-					RelativePath="..\inspector\front-end\TimelineOverviewPane.js"
+					RelativePath="..\inspector\front-end\TimelineGrid.js"
 					>
 				</File>
 				<File
-					RelativePath="..\inspector\front-end\TimelineGrid.js"
+					RelativePath="..\inspector\front-end\TimelineOverviewPane.js"
 					>
 				</File>
 				<File
diff --git a/WebCore/WebCore.xcodeproj/project.pbxproj b/WebCore/WebCore.xcodeproj/project.pbxproj
index 2bfbdb5..4b7d4d0 100644
--- a/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -1027,6 +1027,12 @@
 		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 */; };
@@ -6333,6 +6339,12 @@
 		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>"; };
@@ -13503,6 +13515,8 @@
 				1A0D573F0A5C7867007EDD4C /* JSOverflowEvent.h */,
 				E1284BB010449FFA00EAEB52 /* JSPageTransitionEvent.cpp */,
 				E1284BAF10449FFA00EAEB52 /* JSPageTransitionEvent.h */,
+				5189F01B10B37BD900F3C739 /* JSPopStateEvent.cpp */,
+				5189F01C10B37BD900F3C739 /* JSPopStateEvent.h */,
 				933A14B60B7D1D5200A53FFD /* JSTextEvent.cpp */,
 				933A14B70B7D1D5200A53FFD /* JSTextEvent.h */,
 				A86629CA09DA2B47009633A5 /* JSUIEvent.cpp */,
@@ -14577,6 +14591,7 @@
 				BCD9C2610C17AA67005C90A2 /* JSNodeListCustom.cpp */,
 				A9C6E64A0D7465E7006442E9 /* JSPluginArrayCustom.cpp */,
 				A9C6E64B0D7465E7006442E9 /* JSPluginCustom.cpp */,
+				5189F01710B3781300F3C739 /* JSPopStateEventCustom.cpp */,
 				51DCE8010CAC9F1C00488358 /* JSSQLResultSetRowListCustom.cpp */,
 				1AD2316D0CD269E700C1F194 /* JSSQLTransactionCustom.cpp */,
 				51D0C5150DAA90B7003B3831 /* JSStorageCustom.cpp */,
@@ -15710,6 +15725,9 @@
 				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 */,
@@ -18211,12 +18229,14 @@
 				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 */,
@@ -18323,6 +18343,7 @@
 				85136CA80AED665900F90A3D /* westResizeCursor.png in Resources */,
 				1AB1AE7A0C051FDE00139F4F /* zoomInCursor.png in Resources */,
 				1AB1AE7B0C051FDE00139F4F /* zoomOutCursor.png in Resources */,
+				5174E20C10A1F49A00F95E6F /* PopStateEvent.idl in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -20364,6 +20385,9 @@
 				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 */,
diff --git a/WebCore/bindings/js/JSEventCustom.cpp b/WebCore/bindings/js/JSEventCustom.cpp
index 2c6e130..85a7a95 100644
--- a/WebCore/bindings/js/JSEventCustom.cpp
+++ b/WebCore/bindings/js/JSEventCustom.cpp
@@ -42,6 +42,7 @@
 #include "JSMutationEvent.h"
 #include "JSOverflowEvent.h"
 #include "JSPageTransitionEvent.h"
+#include "JSPopStateEvent.h"
 #include "JSProgressEvent.h"
 #include "JSTextEvent.h"
 #include "JSUIEvent.h"
@@ -57,6 +58,7 @@
 #include "MutationEvent.h"
 #include "OverflowEvent.h"
 #include "PageTransitionEvent.h"
+#include "PopStateEvent.h"
 #include "ProgressEvent.h"
 #include "TextEvent.h"
 #include "UIEvent.h"
@@ -140,6 +142,8 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Event* event)
     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);
 
diff --git a/WebCore/bindings/js/JSHistoryCustom.cpp b/WebCore/bindings/js/JSHistoryCustom.cpp
index b24b1ff..db2ebde 100644
--- a/WebCore/bindings/js/JSHistoryCustom.cpp
+++ b/WebCore/bindings/js/JSHistoryCustom.cpp
@@ -163,4 +163,52 @@ void JSHistory::getOwnPropertyNames(ExecState* exec, PropertyNameArray& property
     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
diff --git a/WebCore/bindings/js/JSPopStateEventCustom.cpp b/WebCore/bindings/js/JSPopStateEventCustom.cpp
new file mode 100644
index 0000000..ee86a09
--- /dev/null
+++ b/WebCore/bindings/js/JSPopStateEventCustom.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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
diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp
index 723c6dc..923efa2 100644
--- a/WebCore/dom/Document.cpp
+++ b/WebCore/dom/Document.cpp
@@ -98,6 +98,7 @@
 #include "PageGroup.h"
 #include "PageTransitionEvent.h"
 #include "PlatformKeyboardEvent.h"
+#include "PopStateEvent.h"
 #include "ProcessingInstruction.h"
 #include "ProgressEvent.h"
 #include "RegisteredEventListener.h"
@@ -1470,6 +1471,12 @@ void Document::detach()
     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,
@@ -1741,6 +1748,9 @@ void Document::implicitClose()
     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
@@ -4337,6 +4347,40 @@ void Document::setSecurityOrigin(SecurityOrigin* securityOrigin)
     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())
diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h
index 3aee2d6..54c563b 100644
--- a/WebCore/dom/Document.h
+++ b/WebCore/dom/Document.h
@@ -67,7 +67,6 @@ namespace WebCore {
     class EventListener;
     class Frame;
     class FrameView;
-    class HitTestRequest;
     class HTMLCanvasElement;
     class HTMLCollection;
     class HTMLAllCollection;
@@ -77,6 +76,8 @@ namespace WebCore {
     class HTMLHeadElement;
     class HTMLInputElement;
     class HTMLMapElement;
+    class HistoryItem;
+    class HitTestRequest;
     class InspectorTimelineAgent;
     class IntPoint;
     class DOMWrapperWorld;
@@ -93,6 +94,7 @@ namespace WebCore {
     class RenderView;
     class ScriptElementData;
     class SecurityOrigin;
+    class SerializedScriptValue;
     class SegmentedString;
     class Settings;
     class StyleSheet;
@@ -887,6 +889,11 @@ public:
     //       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; }
@@ -1067,6 +1074,8 @@ private:
     Element* m_cssTarget;
     
     bool m_processingLoadEvent;
+    RefPtr<SerializedScriptValue> m_pendingStateObject;
+    HashSet<RefPtr<HistoryItem> > m_associatedHistoryItems;
     double m_startTime;
     bool m_overMinimumLayoutThreshold;
 
diff --git a/WebCore/dom/Event.cpp b/WebCore/dom/Event.cpp
index 65906a1..ed1140a 100644
--- a/WebCore/dom/Event.cpp
+++ b/WebCore/dom/Event.cpp
@@ -136,6 +136,11 @@ bool Event::isPageTransitionEvent() const
     return false;
 }
 
+bool Event::isPopStateEvent() const
+{
+    return false;
+}
+
 bool Event::isProgressEvent() const
 {
     return false;
diff --git a/WebCore/dom/Event.h b/WebCore/dom/Event.h
index 3b36e02..ec768e9 100644
--- a/WebCore/dom/Event.h
+++ b/WebCore/dom/Event.h
@@ -111,6 +111,7 @@ namespace WebCore {
         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;
diff --git a/WebCore/dom/EventNames.h b/WebCore/dom/EventNames.h
index ffa5a2e..8c3e3e4 100644
--- a/WebCore/dom/EventNames.h
+++ b/WebCore/dom/EventNames.h
@@ -84,6 +84,7 @@ namespace WebCore {
     macro(pagehide) \
     macro(pageshow) \
     macro(paste) \
+    macro(popstate) \
     macro(readystatechange) \
     macro(reset) \
     macro(resize) \
diff --git a/WebCore/dom/PopStateEvent.cpp b/WebCore/dom/PopStateEvent.cpp
new file mode 100644
index 0000000..b9ad862
--- /dev/null
+++ b/WebCore/dom/PopStateEvent.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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
diff --git a/WebCore/dom/PopStateEvent.h b/WebCore/dom/PopStateEvent.h
new file mode 100644
index 0000000..2fb8d06
--- /dev/null
+++ b/WebCore/dom/PopStateEvent.h
@@ -0,0 +1,57 @@
+/*
+ * 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
diff --git a/WebCore/dom/PopStateEvent.idl b/WebCore/dom/PopStateEvent.idl
new file mode 100644
index 0000000..c6775ec
--- /dev/null
+++ b/WebCore/dom/PopStateEvent.idl
@@ -0,0 +1,40 @@
+/*
+ * 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;
+    };
+
+}
diff --git a/WebCore/history/BackForwardList.cpp b/WebCore/history/BackForwardList.cpp
index 0aad98b..3550e37 100644
--- a/WebCore/history/BackForwardList.cpp
+++ b/WebCore/history/BackForwardList.cpp
@@ -34,6 +34,7 @@
 #include "Logging.h"
 #include "Page.h"
 #include "PageCache.h"
+#include "SerializedScriptValue.h"
 
 using namespace std;
 
@@ -58,12 +59,17 @@ BackForwardList::~BackForwardList()
 
 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();
@@ -84,8 +90,8 @@ void BackForwardList::addItem(PassRefPtr<HistoryItem> prpItem)
         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());
 }
@@ -235,6 +241,30 @@ HistoryItemVector& BackForwardList::entries()
     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();
@@ -267,7 +297,7 @@ void BackForwardList::removeItem(HistoryItem* item)
             else {
                 size_t count = m_entries.size();
                 if (m_current >= count)
-                    m_current = count ? count-1 : NoCurrentItemIndex;
+                    m_current = count ? count - 1 : NoCurrentItemIndex;
             }
             break;
         }
diff --git a/WebCore/history/BackForwardList.h b/WebCore/history/BackForwardList.h
index fdc3360..88398a5 100644
--- a/WebCore/history/BackForwardList.h
+++ b/WebCore/history/BackForwardList.h
@@ -35,8 +35,11 @@
 
 namespace WebCore {
 
+class Document;
 class HistoryItem;
 class Page;
+class SerializedScriptValue;
+class String;
 
 typedef Vector<RefPtr<HistoryItem> > HistoryItemVector;
 typedef HashSet<RefPtr<HistoryItem> > HistoryItemHashSet;
@@ -96,12 +99,16 @@ public:
     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) 
diff --git a/WebCore/history/HistoryItem.cpp b/WebCore/history/HistoryItem.cpp
index 2ca29e3..e604ac5 100644
--- a/WebCore/history/HistoryItem.cpp
+++ b/WebCore/history/HistoryItem.cpp
@@ -48,6 +48,7 @@ HistoryItem::HistoryItem()
     , m_lastVisitWasFailure(false)
     , m_isTargetItem(false)
     , m_visitCount(0)
+    , m_document(0)
 {
 }
 
@@ -60,6 +61,7 @@ HistoryItem::HistoryItem(const String& urlString, const String& title, double ti
     , m_lastVisitWasFailure(false)
     , m_isTargetItem(false)
     , m_visitCount(0)
+    , m_document(0)
 {    
     iconDatabase()->retainIconForPageURL(m_urlString);
 }
@@ -74,6 +76,7 @@ HistoryItem::HistoryItem(const String& urlString, const String& title, const Str
     , m_lastVisitWasFailure(false)
     , m_isTargetItem(false)
     , m_visitCount(0)
+    , m_document(0)
 {
     iconDatabase()->retainIconForPageURL(m_urlString);
 }
@@ -89,6 +92,7 @@ HistoryItem::HistoryItem(const KURL& url, const String& target, const String& pa
     , m_lastVisitWasFailure(false)
     , m_isTargetItem(false)
     , m_visitCount(0)
+    , m_document(0)
 {    
     iconDatabase()->retainIconForPageURL(m_urlString);
 }
@@ -97,6 +101,7 @@ HistoryItem::~HistoryItem()
 {
     ASSERT(!m_cachedPage);
     iconDatabase()->releaseIconForPageURL(m_urlString);
+    setDocument(0);
 }
 
 inline HistoryItem::HistoryItem(const HistoryItem& item)
@@ -387,6 +392,32 @@ void HistoryItem::setIsTargetItem(bool flag)
 #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()));
diff --git a/WebCore/history/HistoryItem.h b/WebCore/history/HistoryItem.h
index d991470..4c91e76 100644
--- a/WebCore/history/HistoryItem.h
+++ b/WebCore/history/HistoryItem.h
@@ -28,6 +28,7 @@
 
 #include "IntPoint.h"
 #include "PlatformString.h"
+#include "SerializedScriptValue.h"
 #include <wtf/OwnPtr.h>
 #include <wtf/PassOwnPtr.h>
 
@@ -132,6 +133,12 @@ public:
     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&);
@@ -235,6 +242,10 @@ private:
 
     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;
diff --git a/WebCore/html/HTMLAttributeNames.in b/WebCore/html/HTMLAttributeNames.in
index 596c458..0e91c88 100644
--- a/WebCore/html/HTMLAttributeNames.in
+++ b/WebCore/html/HTMLAttributeNames.in
@@ -182,6 +182,7 @@ onpaste
 onpause
 onplay
 onplaying
+onpopstate
 onprogress
 onratechange
 onreset
diff --git a/WebCore/html/HTMLBodyElement.cpp b/WebCore/html/HTMLBodyElement.cpp
index a356bf3..35133c0 100644
--- a/WebCore/html/HTMLBodyElement.cpp
+++ b/WebCore/html/HTMLBodyElement.cpp
@@ -139,6 +139,8 @@ void HTMLBodyElement::parseMappedAttribute(MappedAttribute *attr)
         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)
diff --git a/WebCore/html/HTMLBodyElement.h b/WebCore/html/HTMLBodyElement.h
index e898c88..76b49a1 100644
--- a/WebCore/html/HTMLBodyElement.h
+++ b/WebCore/html/HTMLBodyElement.h
@@ -52,13 +52,15 @@ public:
     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
diff --git a/WebCore/html/HTMLBodyElement.idl b/WebCore/html/HTMLBodyElement.idl
index 2e93e2e..b2f0c65 100644
--- a/WebCore/html/HTMLBodyElement.idl
+++ b/WebCore/html/HTMLBodyElement.idl
@@ -40,6 +40,7 @@ module html {
         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;
diff --git a/WebCore/html/HTMLFrameSetElement.cpp b/WebCore/html/HTMLFrameSetElement.cpp
index cbeba87..6c1630b 100644
--- a/WebCore/html/HTMLFrameSetElement.cpp
+++ b/WebCore/html/HTMLFrameSetElement.cpp
@@ -151,6 +151,8 @@ void HTMLFrameSetElement::parseMappedAttribute(MappedAttribute *attr)
         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);
 }
diff --git a/WebCore/html/HTMLFrameSetElement.h b/WebCore/html/HTMLFrameSetElement.h
index 2b2d7ea..0c75efe 100644
--- a/WebCore/html/HTMLFrameSetElement.h
+++ b/WebCore/html/HTMLFrameSetElement.h
@@ -79,6 +79,7 @@ public:
     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);
diff --git a/WebCore/html/HTMLFrameSetElement.idl b/WebCore/html/HTMLFrameSetElement.idl
index b44a071..6ab1a8b 100644
--- a/WebCore/html/HTMLFrameSetElement.idl
+++ b/WebCore/html/HTMLFrameSetElement.idl
@@ -37,6 +37,7 @@ module html {
         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;
diff --git a/WebCore/loader/DocumentLoader.cpp b/WebCore/loader/DocumentLoader.cpp
index 820cb36..1507fe9 100644
--- a/WebCore/loader/DocumentLoader.cpp
+++ b/WebCore/loader/DocumentLoader.cpp
@@ -199,7 +199,7 @@ const KURL& DocumentLoader::url() const
     return request().url();
 }
 
-void DocumentLoader::replaceRequestURLForAnchorScroll(const KURL& url)
+void DocumentLoader::replaceRequestURLForSameDocumentNavigation(const KURL& url)
 {
     m_originalRequestCopy.setURL(url);
     m_request.setURL(url);
diff --git a/WebCore/loader/DocumentLoader.h b/WebCore/loader/DocumentLoader.h
index 70d5afd..76a5aee 100644
--- a/WebCore/loader/DocumentLoader.h
+++ b/WebCore/loader/DocumentLoader.h
@@ -88,7 +88,7 @@ namespace WebCore {
         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; }
diff --git a/WebCore/loader/EmptyClients.h b/WebCore/loader/EmptyClients.h
index bf34a1b..8f7a572 100644
--- a/WebCore/loader/EmptyClients.h
+++ b/WebCore/loader/EmptyClients.h
@@ -202,6 +202,9 @@ public:
     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() { }
diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp
index 52453c6..2047c8d 100644
--- a/WebCore/loader/FrameLoader.cpp
+++ b/WebCore/loader/FrameLoader.cpp
@@ -1703,52 +1703,70 @@ void FrameLoader::setFirstPartyForCookies(const KURL& url)
         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
@@ -3362,40 +3380,13 @@ void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument
 
 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)
@@ -3670,14 +3661,51 @@ Frame* FrameLoader::findFrameForNavigation(const AtomicString& name)
     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();
@@ -3686,138 +3714,96 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
         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)
diff --git a/WebCore/loader/FrameLoader.h b/WebCore/loader/FrameLoader.h
index 6c676b9..7304bfd 100644
--- a/WebCore/loader/FrameLoader.h
+++ b/WebCore/loader/FrameLoader.h
@@ -73,6 +73,7 @@ class ScriptSourceCode;
 class ScriptString;
 class ScriptValue;
 class SecurityOrigin;
+class SerializedScriptValue;
 class SharedBuffer;
 class SubstituteData;
 class TextResourceDecoder;
@@ -350,6 +351,9 @@ private:
     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();
@@ -424,7 +428,7 @@ private:
 
     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();
 
diff --git a/WebCore/loader/FrameLoaderClient.h b/WebCore/loader/FrameLoaderClient.h
index bccbb8a..99505b8 100644
--- a/WebCore/loader/FrameLoaderClient.h
+++ b/WebCore/loader/FrameLoaderClient.h
@@ -117,6 +117,9 @@ namespace WebCore {
         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;
diff --git a/WebCore/loader/HistoryController.cpp b/WebCore/loader/HistoryController.cpp
index 501640a..f7d1f98 100644
--- a/WebCore/loader/HistoryController.cpp
+++ b/WebCore/loader/HistoryController.cpp
@@ -402,7 +402,7 @@ void HistoryController::updateForCommit()
     }
 }
 
-void HistoryController::updateForAnchorScroll()
+void HistoryController::updateForSameDocumentNavigation()
 {
     if (m_frame->loader()->url().isEmpty())
         return;
@@ -624,4 +624,41 @@ void HistoryController::updateBackForwardListClippedAtTarget(bool doClip)
     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
diff --git a/WebCore/loader/HistoryController.h b/WebCore/loader/HistoryController.h
index 4ecae69..7c4a1ac 100644
--- a/WebCore/loader/HistoryController.h
+++ b/WebCore/loader/HistoryController.h
@@ -39,6 +39,7 @@ namespace WebCore {
 
 class Frame;
 class HistoryItem;
+class SerializedScriptValue;
 
 class HistoryController : public Noncopyable {
 public:
@@ -65,7 +66,7 @@ public:
     void updateForRedirectWithLockedBackForwardList();
     void updateForClientRedirect();
     void updateForCommit();
-    void updateForAnchorScroll();
+    void updateForSameDocumentNavigation();
     void updateForFrameLoadCompleted();
 
     HistoryItem* currentItem() const { return m_currentItem.get(); }
@@ -75,6 +76,9 @@ public:
     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);
diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h
index fefb7b9..146f390 100644
--- a/WebCore/page/DOMWindow.h
+++ b/WebCore/page/DOMWindow.h
@@ -248,9 +248,13 @@ namespace WebCore {
         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);
@@ -259,13 +263,22 @@ namespace WebCore {
         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);
@@ -276,41 +289,30 @@ namespace WebCore {
         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
diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl
index e833998..f92016a 100644
--- a/WebCore/page/DOMWindow.idl
+++ b/WebCore/page/DOMWindow.idl
@@ -252,6 +252,7 @@ module window {
         attribute EventListener onpause;
         attribute EventListener onplay;
         attribute EventListener onplaying;
+        attribute EventListener onpopstate;
         attribute EventListener onprogress;
         attribute EventListener onratechange;
         attribute EventListener onresize;
diff --git a/WebCore/page/History.cpp b/WebCore/page/History.cpp
index bf7a313..ea9819e 100644
--- a/WebCore/page/History.cpp
+++ b/WebCore/page/History.cpp
@@ -26,8 +26,11 @@
 #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 {
@@ -77,4 +80,46 @@ void History::go(int distance)
     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
diff --git a/WebCore/page/History.h b/WebCore/page/History.h
index f0df2de..66a6a03 100644
--- a/WebCore/page/History.h
+++ b/WebCore/page/History.h
@@ -26,30 +26,42 @@
 #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
 
diff --git a/WebCore/page/History.idl b/WebCore/page/History.idl
index 914d441..3790552 100644
--- a/WebCore/page/History.idl
+++ b/WebCore/page/History.idl
@@ -39,6 +39,11 @@ module window {
         [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);
     };
 
 }
diff --git a/WebCore/page/Page.cpp b/WebCore/page/Page.cpp
index 4321e08..c4f33d6 100644
--- a/WebCore/page/Page.cpp
+++ b/WebCore/page/Page.cpp
@@ -21,6 +21,7 @@
 #include "config.h"
 #include "Page.h"
 
+#include "BackForwardList.h"
 #include "Base64.h"
 #include "CSSStyleSelector.h"
 #include "Chrome.h"
@@ -277,20 +278,30 @@ void Page::goBackOrForward(int distance)
 
 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);
 }
 
diff --git a/WebKit/chromium/ChangeLog b/WebKit/chromium/ChangeLog
index 88e7d97..9c48a15 100644
--- a/WebKit/chromium/ChangeLog
+++ b/WebKit/chromium/ChangeLog
@@ -1,3 +1,15 @@
+2009-12-03  Brady Eidson  <beidson at 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 at chromium.org>
 
         Reviewed by Timothy Hatcher.
diff --git a/WebKit/chromium/src/FrameLoaderClientImpl.cpp b/WebKit/chromium/src/FrameLoaderClientImpl.cpp
index 7f3dddc..74189b8 100644
--- a/WebKit/chromium/src/FrameLoaderClientImpl.cpp
+++ b/WebKit/chromium/src/FrameLoaderClientImpl.cpp
@@ -599,6 +599,21 @@ void FrameLoaderClientImpl::dispatchDidChangeLocationWithinPage()
         webView->client()->didStopLoading();
 }
 
+void FrameLoaderClientImpl::dispatchDidPushStateWithinPage()
+{
+    // FIXME
+}
+
+void FrameLoaderClientImpl::dispatchDidReplaceStateWithinPage()
+{
+    // FIXME
+}
+
+void FrameLoaderClientImpl::dispatchDidPopStateWithinPage()
+{
+    // FIXME
+}
+
 void FrameLoaderClientImpl::dispatchWillClose()
 {
     if (m_webFrame->client())
diff --git a/WebKit/chromium/src/FrameLoaderClientImpl.h b/WebKit/chromium/src/FrameLoaderClientImpl.h
index 7d7c685..4ddfe5f 100644
--- a/WebKit/chromium/src/FrameLoaderClientImpl.h
+++ b/WebKit/chromium/src/FrameLoaderClientImpl.h
@@ -95,6 +95,9 @@ public:
     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();
diff --git a/WebKit/gtk/ChangeLog b/WebKit/gtk/ChangeLog
index 4142116..c0c42d4 100644
--- a/WebKit/gtk/ChangeLog
+++ b/WebKit/gtk/ChangeLog
@@ -1,3 +1,15 @@
+2009-12-03  Brady Eidson  <beidson at 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 at dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
diff --git a/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp b/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp
index 1b1c9c8..1b6bfa7 100644
--- a/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp
+++ b/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp
@@ -669,6 +669,21 @@ void FrameLoaderClient::dispatchDidChangeLocationWithinPage()
         g_object_notify(G_OBJECT(webView), "uri");
 }
 
+void FrameLoaderClient::dispatchDidPushStateWithinPage()
+{
+    notImplemented();
+}
+
+void FrameLoaderClient::dispatchDidReplaceStateWithinPage()
+{
+    notImplemented();
+}
+
+void FrameLoaderClient::dispatchDidPopStateWithinPage()
+{
+    notImplemented();
+}
+
 void FrameLoaderClient::dispatchWillClose()
 {
     notImplemented();
diff --git a/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h b/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h
index c62a1fe..cace770 100644
--- a/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h
+++ b/WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h
@@ -76,6 +76,9 @@ namespace WebKit {
         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();
diff --git a/WebKit/mac/ChangeLog b/WebKit/mac/ChangeLog
index af84eaa..576fd22 100644
--- a/WebKit/mac/ChangeLog
+++ b/WebKit/mac/ChangeLog
@@ -1,3 +1,19 @@
+2009-12-03  Brady Eidson  <beidson at 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 at dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
diff --git a/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.h b/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.h
index fb3c232..2774783 100644
--- a/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.h
+++ b/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.h
@@ -91,6 +91,10 @@ private:
     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();
diff --git a/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm b/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm
index 2297e23..9816e01 100644
--- a/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm
+++ b/WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm
@@ -538,6 +538,30 @@ void WebFrameLoaderClient::dispatchDidChangeLocationWithinPage()
         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());   
diff --git a/WebKit/mac/WebView/WebDelegateImplementationCaching.h b/WebKit/mac/WebView/WebDelegateImplementationCaching.h
index 8f0d145..684934a 100644
--- a/WebKit/mac/WebView/WebDelegateImplementationCaching.h
+++ b/WebKit/mac/WebView/WebDelegateImplementationCaching.h
@@ -57,6 +57,9 @@ struct WebFrameLoadDelegateImplementationCache {
     IMP didCancelClientRedirectForFrameFunc;
     IMP willPerformClientRedirectToURLDelayFireDateForFrameFunc;
     IMP didChangeLocationWithinPageForFrameFunc;
+    IMP didPushStateWithinPageForFrameFunc;
+    IMP didReplaceStateWithinPageForFrameFunc;
+    IMP didPopStateWithinPageForFrameFunc;
     IMP willCloseFrameFunc;
     IMP didStartProvisionalLoadForFrameFunc;
     IMP didReceiveTitleForFrameFunc;
diff --git a/WebKit/mac/WebView/WebFrameLoadDelegatePrivate.h b/WebKit/mac/WebView/WebFrameLoadDelegatePrivate.h
index 45a4f08..2359cc6 100644
--- a/WebKit/mac/WebView/WebFrameLoadDelegatePrivate.h
+++ b/WebKit/mac/WebView/WebFrameLoadDelegatePrivate.h
@@ -39,4 +39,8 @@
 
 - (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
diff --git a/WebKit/mac/WebView/WebView.mm b/WebKit/mac/WebView/WebView.mm
index 3238a47..bd8a4ab 100644
--- a/WebKit/mac/WebView/WebView.mm
+++ b/WebKit/mac/WebView/WebView.mm
@@ -1353,6 +1353,9 @@ static inline IMP getMethod(id o, SEL s)
 
     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:));
diff --git a/WebKit/qt/ChangeLog b/WebKit/qt/ChangeLog
index 4fef0ac..e40a74b 100644
--- a/WebKit/qt/ChangeLog
+++ b/WebKit/qt/ChangeLog
@@ -1,3 +1,15 @@
+2009-12-03  Brady Eidson  <beidson at 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 at dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
diff --git a/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp b/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
index f570b83..4593fc5 100644
--- a/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
+++ b/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
@@ -304,6 +304,29 @@ void FrameLoaderClientQt::dispatchDidChangeLocationWithinPage()
     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()
 {
diff --git a/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.h b/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.h
index cd54983..32b9caa 100644
--- a/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.h
+++ b/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.h
@@ -103,6 +103,9 @@ namespace WebCore {
         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();
diff --git a/WebKit/win/ChangeLog b/WebKit/win/ChangeLog
index 16abcae..f457034 100644
--- a/WebKit/win/ChangeLog
+++ b/WebKit/win/ChangeLog
@@ -1,3 +1,16 @@
+2009-12-03  Brady Eidson  <beidson at 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 at dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
diff --git a/WebKit/win/Interfaces/IWebFrameLoadDelegatePrivate2.idl b/WebKit/win/Interfaces/IWebFrameLoadDelegatePrivate2.idl
index a38223c..7e07c55 100644
--- a/WebKit/win/Interfaces/IWebFrameLoadDelegatePrivate2.idl
+++ b/WebKit/win/Interfaces/IWebFrameLoadDelegatePrivate2.idl
@@ -48,4 +48,8 @@ interface IWebFrameLoadDelegatePrivate2 : IWebFrameLoadDelegatePrivate
     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);
 }
diff --git a/WebKit/win/WebCoreSupport/WebFrameLoaderClient.cpp b/WebKit/win/WebCoreSupport/WebFrameLoaderClient.cpp
index 8df0138..b927c72 100644
--- a/WebKit/win/WebCoreSupport/WebFrameLoaderClient.cpp
+++ b/WebKit/win/WebCoreSupport/WebFrameLoaderClient.cpp
@@ -306,6 +306,47 @@ void WebFrameLoaderClient::dispatchDidChangeLocationWithinPage()
         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();
diff --git a/WebKit/win/WebCoreSupport/WebFrameLoaderClient.h b/WebKit/win/WebCoreSupport/WebFrameLoaderClient.h
index 21599bc..f1fb5f7 100644
--- a/WebKit/win/WebCoreSupport/WebFrameLoaderClient.h
+++ b/WebKit/win/WebCoreSupport/WebFrameLoaderClient.h
@@ -65,6 +65,9 @@ public:
     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();
diff --git a/WebKit/wx/ChangeLog b/WebKit/wx/ChangeLog
index 5d0ca0e..06a5043 100644
--- a/WebKit/wx/ChangeLog
+++ b/WebKit/wx/ChangeLog
@@ -1,3 +1,15 @@
+2009-12-03  Brady Eidson  <beidson at 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 at dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
diff --git a/WebKit/wx/WebKitSupport/FrameLoaderClientWx.cpp b/WebKit/wx/WebKitSupport/FrameLoaderClientWx.cpp
index 1ffb23d..c09f8de 100644
--- a/WebKit/wx/WebKitSupport/FrameLoaderClientWx.cpp
+++ b/WebKit/wx/WebKitSupport/FrameLoaderClientWx.cpp
@@ -262,6 +262,20 @@ void FrameLoaderClientWx::dispatchDidChangeLocationWithinPage()
     notImplemented();
 }
 
+void FrameLoaderClientWx::dispatchDidPushStateWithinPage()
+{
+    notImplemented();
+}
+
+void FrameLoaderClientWx::dispatchDidReplaceStateWithinPage()
+{
+    notImplemented();
+}
+
+void FrameLoaderClientWx::dispatchDidPopStateWithinPage()
+{
+    notImplemented();
+}
 
 void FrameLoaderClientWx::dispatchWillClose()
 {
diff --git a/WebKit/wx/WebKitSupport/FrameLoaderClientWx.h b/WebKit/wx/WebKitSupport/FrameLoaderClientWx.h
index ffabc63..0c29941 100644
--- a/WebKit/wx/WebKitSupport/FrameLoaderClientWx.h
+++ b/WebKit/wx/WebKitSupport/FrameLoaderClientWx.h
@@ -96,6 +96,9 @@ namespace WebCore {
         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();
diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog
index c7d8ca5..ad865ff 100644
--- a/WebKitTools/ChangeLog
+++ b/WebKitTools/ChangeLog
@@ -1,3 +1,16 @@
+2009-12-03  Brady Eidson  <beidson at 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 at inf.u-szeged.hu>
 
         Unreviewed build fix.
diff --git a/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h b/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h
index 0deeeca..cc6653b 100644
--- a/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h
+++ b/WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h
@@ -143,6 +143,18 @@ public:
 
     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*);

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list