<rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object...
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Dec 2009 19:04:40 +0000 (19:04 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Dec 2009 19:04:40 +0000 (19:04 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@51644 268f45cc-cd09-0410-ab3c-d52691b4dbfc

94 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/Window/window-appendages-cleared-expected.txt
LayoutTests/fast/dom/Window/window-properties-expected.txt
LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/pushstate-object-types-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/pushstate-object-types.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate-expected.txt [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate.html [new file with mode: 0644]
LayoutTests/fast/loader/stateobjects/resources/navigate-back.html [new file with mode: 0644]
LayoutTests/http/tests/loading/state-object-security-exception-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/loading/state-object-security-exception.html [new file with mode: 0644]
LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
WebCore/ChangeLog
WebCore/DerivedSources.cpp
WebCore/DerivedSources.make
WebCore/GNUmakefile.am
WebCore/WebCore.pro
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/bindings/js/JSEventCustom.cpp
WebCore/bindings/js/JSHistoryCustom.cpp
WebCore/bindings/js/JSPopStateEventCustom.cpp [new file with mode: 0644]
WebCore/dom/Document.cpp
WebCore/dom/Document.h
WebCore/dom/Event.cpp
WebCore/dom/Event.h
WebCore/dom/EventNames.h
WebCore/dom/PopStateEvent.cpp [new file with mode: 0644]
WebCore/dom/PopStateEvent.h [new file with mode: 0644]
WebCore/dom/PopStateEvent.idl [new file with mode: 0644]
WebCore/history/BackForwardList.cpp
WebCore/history/BackForwardList.h
WebCore/history/HistoryItem.cpp
WebCore/history/HistoryItem.h
WebCore/html/HTMLAttributeNames.in
WebCore/html/HTMLBodyElement.cpp
WebCore/html/HTMLBodyElement.h
WebCore/html/HTMLBodyElement.idl
WebCore/html/HTMLFrameSetElement.cpp
WebCore/html/HTMLFrameSetElement.h
WebCore/html/HTMLFrameSetElement.idl
WebCore/loader/DocumentLoader.cpp
WebCore/loader/DocumentLoader.h
WebCore/loader/EmptyClients.h
WebCore/loader/FrameLoader.cpp
WebCore/loader/FrameLoader.h
WebCore/loader/FrameLoaderClient.h
WebCore/loader/HistoryController.cpp
WebCore/loader/HistoryController.h
WebCore/page/DOMWindow.h
WebCore/page/DOMWindow.idl
WebCore/page/History.cpp
WebCore/page/History.h
WebCore/page/History.idl
WebCore/page/Page.cpp
WebKit/chromium/ChangeLog
WebKit/chromium/src/FrameLoaderClientImpl.cpp
WebKit/chromium/src/FrameLoaderClientImpl.h
WebKit/gtk/ChangeLog
WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.cpp
WebKit/gtk/WebCoreSupport/FrameLoaderClientGtk.h
WebKit/mac/ChangeLog
WebKit/mac/WebCoreSupport/WebFrameLoaderClient.h
WebKit/mac/WebCoreSupport/WebFrameLoaderClient.mm
WebKit/mac/WebView/WebDelegateImplementationCaching.h
WebKit/mac/WebView/WebFrameLoadDelegatePrivate.h
WebKit/mac/WebView/WebView.mm
WebKit/qt/ChangeLog
WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
WebKit/qt/WebCoreSupport/FrameLoaderClientQt.h
WebKit/win/ChangeLog
WebKit/win/Interfaces/IWebFrameLoadDelegatePrivate2.idl
WebKit/win/WebCoreSupport/WebFrameLoaderClient.cpp
WebKit/win/WebCoreSupport/WebFrameLoaderClient.h
WebKit/wx/ChangeLog
WebKit/wx/WebKitSupport/FrameLoaderClientWx.cpp
WebKit/wx/WebKitSupport/FrameLoaderClientWx.h
WebKitTools/ChangeLog
WebKitTools/DumpRenderTree/win/FrameLoadDelegate.h

index 4bef668bc6eaad9d24427044d9874298b91a51a5..965fa11330202ab38200c25a6189664c185c8ecb 100644 (file)
@@ -1,3 +1,41 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        Update expected results of old tests:
+        * fast/dom/Window/window-appendages-cleared-expected.txt:
+        * fast/dom/Window/window-properties-expected.txt:
+        * http/tests/security/cross-frame-access-enumeration-expected.txt:
+
+        New tests:
+        * fast/loader/stateobjects: Added.
+        * fast/loader/stateobjects/document-destroyed-navigate-back-expected.txt: Added.
+        * fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll-expected.txt: Added.
+        * fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html: Added.
+        * fast/loader/stateobjects/document-destroyed-navigate-back.html: Added.
+        * fast/loader/stateobjects/popstate-after-load-complete-addeventlistener-expected.txt: Added.
+        * fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html: Added.
+        * fast/loader/stateobjects/popstate-after-load-complete-body-attribute-expected.txt: Added.
+        * fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html: Added.
+        * fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute-expected.txt: Added.
+        * fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html: Added.
+        * fast/loader/stateobjects/popstate-after-load-complete-window-attribute-expected.txt: Added.
+        * fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html: Added.
+        * fast/loader/stateobjects/pushstate-object-types-expected.txt: Added.
+        * fast/loader/stateobjects/pushstate-object-types.html: Added.
+        * fast/loader/stateobjects/pushstate-then-replacestate-expected.txt: Added.
+        * fast/loader/stateobjects/pushstate-then-replacestate.html: Added.
+        * fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange-expected.txt: Added.
+        * fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html: Added.
+        * fast/loader/stateobjects/replacestate-then-pushstate-expected.txt: Added.
+        * fast/loader/stateobjects/replacestate-then-pushstate.html: Added.
+        * fast/loader/stateobjects/resources: Added.
+        * fast/loader/stateobjects/resources/navigate-back.html: Added.
+        * http/tests/loading/state-object-security-exception-expected.txt: Added.
+        * http/tests/loading/state-object-security-exception.html: Added.
+
 2009-12-03  Gustavo Noronha Silva  <gustavo.noronha@collabora.co.uk>
 
         Reviewed by Xan Lopez.
index 63ef8fd79988e77d08070ab16e0deaf15adae0a5..272aa7ff4d0d8604f522e2fd9e0bcf41a0eb5b2b 100644 (file)
@@ -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
index 420c518f841e29095c47c54e0c1278d4a6716437..c0f28316e56349afd383f94ce389ef80f2c56eb1 100644 (file)
@@ -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 (file)
index 0000000..23fc936
--- /dev/null
@@ -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 (file)
index 0000000..9a76bb2
--- /dev/null
@@ -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 (file)
index 0000000..4444358
--- /dev/null
@@ -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 (file)
index 0000000..d910249
--- /dev/null
@@ -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 (file)
index 0000000..061ea73
--- /dev/null
@@ -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 (file)
index 0000000..75b969f
--- /dev/null
@@ -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 (file)
index 0000000..43ea542
--- /dev/null
@@ -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 (file)
index 0000000..9505736
--- /dev/null
@@ -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 (file)
index 0000000..43ea542
--- /dev/null
@@ -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 (file)
index 0000000..26fca1c
--- /dev/null
@@ -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 (file)
index 0000000..c9d4b29
--- /dev/null
@@ -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 (file)
index 0000000..62569a5
--- /dev/null
@@ -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 (file)
index 0000000..5952194
--- /dev/null
@@ -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 (file)
index 0000000..8f31981
--- /dev/null
@@ -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 (file)
index 0000000..d7fafd9
--- /dev/null
@@ -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 (file)
index 0000000..976013e
--- /dev/null
@@ -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 (file)
index 0000000..a4cb868
--- /dev/null
@@ -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 (file)
index 0000000..a148687
--- /dev/null
@@ -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 (file)
index 0000000..5870bd1
--- /dev/null
@@ -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 (file)
index 0000000..826264a
--- /dev/null
@@ -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 (file)
index 0000000..eda9cc5
--- /dev/null
@@ -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 (file)
index 0000000..ad3b829
--- /dev/null
@@ -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 (file)
index 0000000..8a027b2
--- /dev/null
@@ -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>
index 25a71dee8957ad67531b7c213705cfb993236c33..26b4365097fefc6a56281609591bef2cb30c800b 100644 (file)
@@ -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)
 
 
index 1a7d5b0d7f3970f8f1410a5d199965b59b1b8eea..f0b344576e7025ce797cc862a6d32a8ad61ce89f 100644 (file)
@@ -1,3 +1,127 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        Tests: fast/loader/stateobjects/document-destroyed-navigate-back.html
+               fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html
+               fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html
+               fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html
+               fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html
+               fast/loader/stateobjects/pushstate-object-types.html
+               fast/loader/stateobjects/pushstate-then-replacestate.html
+               fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html
+               fast/loader/stateobjects/replacestate-then-pushstate.html
+               http/tests/loading/state-object-security-exception.html
+
+        Derived sources and project file changes:
+        * DerivedSources.cpp:
+        * DerivedSources.make:
+        * GNUmakefile.am
+        * WebCore.pro
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+
+        Add the new PopStateEvent:
+        * dom/PopStateEvent.cpp: Added.
+        (WebCore::PopStateEvent::PopStateEvent):
+        (WebCore::PopStateEvent::initPopStateEvent):
+        * dom/PopStateEvent.h: Added.
+        (WebCore::PopStateEvent::create):
+        (WebCore::PopStateEvent::isPopStateEvent):
+        (WebCore::PopStateEvent::state):
+        * dom/PopStateEvent.idl: Added.
+        * bindings/js/JSPopStateEventCustom.cpp: Added.
+        (WebCore::JSPopStateEvent::initPopStateEvent):
+        (WebCore::JSPopStateEvent::state):
+        * bindings/js/JSEventCustom.cpp:
+        (WebCore::toJS):
+        * dom/Event.cpp:
+        (WebCore::Event::isPopStateEvent):
+        * dom/Event.h:
+        * dom/EventNames.h:
+
+        Add the "onpopstate" attribute:
+        * html/HTMLAttributeNames.in:
+        * html/HTMLBodyElement.cpp:
+        (WebCore::HTMLBodyElement::parseMappedAttribute):
+        * html/HTMLBodyElement.idl:
+        * html/HTMLFrameSetElement.cpp:
+        (WebCore::HTMLFrameSetElement::parseMappedAttribute):
+        * html/HTMLFrameSetElement.h:
+        * html/HTMLFrameSetElement.idl:
+        * page/DOMWindow.h:
+        * page/DOMWindow.idl:
+
+        Add pushState and replaceState management to the loader and history machinery:
+        * bindings/js/JSHistoryCustom.cpp:
+        (WebCore::JSHistory::pushState):
+        (WebCore::JSHistory::replaceState):
+        * loader/HistoryController.cpp:
+        (WebCore::HistoryController::updateForSameDocumentNavigation): Augmented from "scrollToAnchor()", combining
+          both the same-document fragment scroll case with the new same-document state object activation case.
+        (WebCore::HistoryController::pushState):
+        (WebCore::HistoryController::replaceState):
+        * loader/HistoryController.h:
+        * history/BackForwardList.cpp:
+        (WebCore::BackForwardList::addItem): Use insertItemAfterCurrent.
+        (WebCore::BackForwardList::insertItemAfterCurrent): Optionally insert the item without clearing the forward
+          list, as pushStateItem might've selectively cleared only certain items, with the bulk of the forward list
+          meant to remain.
+        (WebCore::BackForwardList::pushStateItem): Clear the forward list *only* for the state item's document, then 
+          insert the new item.
+        (WebCore::BackForwardList::removeItem):
+        * history/BackForwardList.h:
+        * page/History.cpp:
+        (WebCore::History::urlForState):
+        (WebCore::History::stateObjectAdded):
+        * page/History.h:
+        * page/History.idl:
+
+        Let HistoryItems and Documents associate with each other, as well as letting HistoryItems contain state objects:
+        * history/HistoryItem.cpp:
+        (WebCore::HistoryItem::HistoryItem):
+        (WebCore::HistoryItem::~HistoryItem):
+        (WebCore::HistoryItem::setStateObject):
+        (WebCore::HistoryItem::setDocument):
+        (WebCore::HistoryItem::documentDetached):
+        * history/HistoryItem.h:
+        (WebCore::HistoryItem::stateObject):
+        (WebCore::HistoryItem::document):
+        * dom/Document.cpp:
+        (WebCore::Document::detach): Notify all back/forward history items owned by this Document that it
+          is going away.
+        (WebCore::Document::registerHistoryItem): Manage the list of back/forward history items this document owns.
+        (WebCore::Document::unregisterHistoryItem): Ditto.
+        * dom/Document.h:
+
+        Add the ability for Documents, DocumentLoaders, and FrameLoaderClients to be notified when a Documents
+        URL changes as the result of pushState(), replaceState(), or a popstate navigation:
+        * dom/Document.cpp:
+        (WebCore::Document::implicitClose): If there's a pending state object, dispatch the popstate event.
+        (WebCore::Document::updateURLForPushOrReplaceState):
+        (WebCore::Document::statePopped): If loading is complete, dispatch the popstate event. Otherwise, set 
+          the pending state object.
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::replaceRequestURLForSameDocumentNavigation):
+        * loader/DocumentLoader.h:
+        * loader/FrameLoaderClient.h:
+        * loader/EmptyClients.h:
+        (WebCore::EmptyFrameLoaderClient::dispatchDidChangeStateObjectForPageForFrame):
+
+        Change handling of "loading a HistoryItem" to distinguish between new-Document navigations and same-Document
+        navigations, combining the old concept of anchor scrolls with the new concept of state object navigations:
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::loadInSameDocument):
+        (WebCore::FrameLoader::continueFragmentScrollAfterNavigationPolicy):
+        (WebCore::FrameLoader::navigateWithinDocument):
+        (WebCore::FrameLoader::navigateToDifferentDocument):
+        (WebCore::FrameLoader::loadItem):
+        * loader/FrameLoader.h:
+        * page/Page.cpp:
+        (WebCore::Page::goToItem): Changed to allow state object activations to pass through without the load stopping.
+
 2009-12-03  Pavel Feldman  <pfeldman@chromium.org>
 
         Not reviewed: chromium build fix.
index bce87d23862a4f1e07c16430619d5e810d08a0c1..e96b606cf8f6efbcdc141eaca14caa1de48da6dc 100644 (file)
 #include "JSPageTransitionEvent.cpp"
 #include "JSPlugin.cpp"
 #include "JSPluginArray.cpp"
+#include "JSPopStateEvent.cpp"
 #include "JSProcessingInstruction.cpp"
 #include "JSProgressEvent.cpp"
 #include "JSRange.cpp"
index 9e03f13bfba4663e4a4d5e8b38e645823962bee9..3f192fc5bac4f03ec6a50223c9330eb4153ecb1b 100644 (file)
@@ -228,6 +228,7 @@ DOM_CLASSES = \
     PageTransitionEvent \
     Plugin \
     PluginArray \
+    PopStateEvent \
     PositionError \
     ProcessingInstruction \
     ProgressEvent \
index 834029b576da45f6e3c5a90e67cb40e9ff858db3..2d8eb2f8c28713afe84b3e60132e378ed38415b2 100644 (file)
@@ -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 \
index 79f03bb1401c4adf2b24c4e87167364b3634bd36..a8106c15b6fa9fed229f958b0bcd5b17ab1bea0e 100644 (file)
@@ -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 \
index aa53a85b093f6709c84148685d3f2580a19bc382..d2e4e6b279c6864bd175f1d926d5c087d7943c7c 100644 (file)
                                RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPluginArray.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPopStateEvent.cpp"\r
+                               >\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32"\r
+                                       ExcludedFromBuild="true"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32"\r
+                                       ExcludedFromBuild="true"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Debug_Internal|Win32"\r
+                                       ExcludedFromBuild="true"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Debug_Cairo|Win32"\r
+                                       ExcludedFromBuild="true"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release_Cairo|Win32"\r
+                                       ExcludedFromBuild="true"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Debug_All|Win32"\r
+                                       ExcludedFromBuild="true"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                       />\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
+                               RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPopStateEvent.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSPositionError.cpp"\r
                                >\r
                                RelativePath="..\dom\default\PlatformMessagePortChannel.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\dom\PopStateEvent.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\dom\PopStateEvent.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\dom\Position.cpp"\r
                                >\r
                                        RelativePath="..\bindings\js\JSPluginElementFunctions.h"\r
                                        >\r
                                </File>\r
+                               <File\r
+                                       RelativePath="..\bindings\js\JSPopStateEventCustom.cpp"\r
+                                       >\r
+                               </File>\r
                                <File\r
                                        RelativePath="..\bindings\js\JSQuarantinedObjectWrapper.cpp"\r
                                        >\r
                                        RelativePath="..\inspector\front-end\Color.js"\r
                                        >\r
                                </File>\r
-                <File\r
-                    RelativePath="..\inspector\front-end\ConsolePanel.js"\r
-                    >\r
-                </File>\r
+                               <File\r
+                                       RelativePath="..\inspector\front-end\ConsolePanel.js"\r
+                                       >\r
+                               </File>\r
                                <File\r
                                        RelativePath="..\inspector\front-end\ConsoleView.js"\r
                                        >\r
                                        >\r
                                </File>\r
                                <File\r
-                                       RelativePath="..\inspector\front-end\TimelineOverviewPane.js"\r
+                                       RelativePath="..\inspector\front-end\TimelineGrid.js"\r
                                        >\r
                                </File>\r
                                <File\r
-                                       RelativePath="..\inspector\front-end\TimelineGrid.js"\r
+                                       RelativePath="..\inspector\front-end\TimelineOverviewPane.js"\r
                                        >\r
                                </File>\r
                                <File\r
index 2bfbdb503b9cde2a892e4f7981f7c5eff0600265..4b7d4d082fb3f98cb85f47b6d7a51c1035d59589 100644 (file)
                51741D100B07259A00ED442C /* BackForwardList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51741D0C0B07259A00ED442C /* BackForwardList.cpp */; };
                51741D110B07259A00ED442C /* HistoryItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 51741D0D0B07259A00ED442C /* HistoryItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
                51741D120B07259A00ED442C /* HistoryItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51741D0E0B07259A00ED442C /* HistoryItem.cpp */; };
+               5174E20A10A1F44F00F95E6F /* PopStateEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5174E20810A1F44F00F95E6F /* PopStateEvent.h */; };
+               5174E20C10A1F49A00F95E6F /* PopStateEvent.idl in Resources */ = {isa = PBXBuildFile; fileRef = 5174E20B10A1F49A00F95E6F /* PopStateEvent.idl */; };
+               5189F01810B3781300F3C739 /* JSPopStateEventCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5189F01710B3781300F3C739 /* JSPopStateEventCustom.cpp */; };
+               5189F01D10B37BD900F3C739 /* JSPopStateEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5189F01B10B37BD900F3C739 /* JSPopStateEvent.cpp */; };
+               5189F01E10B37BD900F3C739 /* JSPopStateEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 5189F01C10B37BD900F3C739 /* JSPopStateEvent.h */; };
+               5189F0DE10B46B0E00F3C739 /* PopStateEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5189F0DD10B46B0E00F3C739 /* PopStateEvent.cpp */; };
                518A34C11026C831001B6896 /* WebSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 518A34BE1026C831001B6896 /* WebSocket.cpp */; };
                518A34C21026C831001B6896 /* WebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 518A34BF1026C831001B6896 /* WebSocket.h */; };
                518A34C71026C8C9001B6896 /* JSWebSocketConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 518A34C41026C8C9001B6896 /* JSWebSocketConstructor.cpp */; };
                51741D0C0B07259A00ED442C /* BackForwardList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BackForwardList.cpp; sourceTree = "<group>"; };
                51741D0D0B07259A00ED442C /* HistoryItem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HistoryItem.h; sourceTree = "<group>"; };
                51741D0E0B07259A00ED442C /* HistoryItem.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HistoryItem.cpp; sourceTree = "<group>"; };
+               5174E20810A1F44F00F95E6F /* PopStateEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopStateEvent.h; sourceTree = "<group>"; };
+               5174E20B10A1F49A00F95E6F /* PopStateEvent.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PopStateEvent.idl; sourceTree = "<group>"; };
+               5189F01710B3781300F3C739 /* JSPopStateEventCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPopStateEventCustom.cpp; sourceTree = "<group>"; };
+               5189F01B10B37BD900F3C739 /* JSPopStateEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPopStateEvent.cpp; sourceTree = "<group>"; };
+               5189F01C10B37BD900F3C739 /* JSPopStateEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPopStateEvent.h; sourceTree = "<group>"; };
+               5189F0DD10B46B0E00F3C739 /* PopStateEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PopStateEvent.cpp; sourceTree = "<group>"; };
                518A34BE1026C831001B6896 /* WebSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocket.cpp; sourceTree = "<group>"; };
                518A34BF1026C831001B6896 /* WebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocket.h; sourceTree = "<group>"; };
                518A34C01026C831001B6896 /* WebSocket.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebSocket.idl; sourceTree = "<group>"; };
                                1A0D573F0A5C7867007EDD4C /* JSOverflowEvent.h */,
                                E1284BB010449FFA00EAEB52 /* JSPageTransitionEvent.cpp */,
                                E1284BAF10449FFA00EAEB52 /* JSPageTransitionEvent.h */,
+                               5189F01B10B37BD900F3C739 /* JSPopStateEvent.cpp */,
+                               5189F01C10B37BD900F3C739 /* JSPopStateEvent.h */,
                                933A14B60B7D1D5200A53FFD /* JSTextEvent.cpp */,
                                933A14B70B7D1D5200A53FFD /* JSTextEvent.h */,
                                A86629CA09DA2B47009633A5 /* JSUIEvent.cpp */,
                                BCD9C2610C17AA67005C90A2 /* JSNodeListCustom.cpp */,
                                A9C6E64A0D7465E7006442E9 /* JSPluginArrayCustom.cpp */,
                                A9C6E64B0D7465E7006442E9 /* JSPluginCustom.cpp */,
+                               5189F01710B3781300F3C739 /* JSPopStateEventCustom.cpp */,
                                51DCE8010CAC9F1C00488358 /* JSSQLResultSetRowListCustom.cpp */,
                                1AD2316D0CD269E700C1F194 /* JSSQLTransactionCustom.cpp */,
                                51D0C5150DAA90B7003B3831 /* JSStorageCustom.cpp */,
                                E1284AD910447AEB00EAEB52 /* PageTransitionEvent.idl */,
                                41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */,
                                41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */,
+                               5189F0DD10B46B0E00F3C739 /* PopStateEvent.cpp */,
+                               5174E20810A1F44F00F95E6F /* PopStateEvent.h */,
+                               5174E20B10A1F49A00F95E6F /* PopStateEvent.idl */,
                                BE91FC8C06133666005E3790 /* Position.cpp */,
                                BE91FC8B06133666005E3790 /* Position.h */,
                                37919C210B7D188600A56998 /* PositionIterator.cpp */,
                                1479FAF0109AE37500DED655 /* RenderRubyBase.h in Headers */,
                                1479FAF2109AE37500DED655 /* RenderRubyRun.h in Headers */,
                                1479FAF4109AE37500DED655 /* RenderRubyText.h in Headers */,
+                               5174E20A10A1F44F00F95E6F /* PopStateEvent.h in Headers */,
                                18C5FCA610A3991F0048438D /* WebKitSharedScript.h in Headers */,
                                18C5FCA910A3991F0048438D /* WebKitSharedScriptRepository.h in Headers */,
                                18C5FCB810A3C6F20048438D /* SharedScriptContext.h in Headers */,
                                E124748410AA161D00B79493 /* AuthenticationClient.h in Headers */,
                                9382DF5810A8D5C900925652 /* ColorSpace.h in Headers */,
                                AB31C91E10AE1B8E000C7B92 /* LineClampValue.h in Headers */,
+                               5189F01E10B37BD900F3C739 /* JSPopStateEvent.h in Headers */,
                                6E47E66110B7944B00B186C8 /* WebGLGetInfo.h in Headers */,
                                7A0E76DB10BF059800A0276E /* JSInjectedScriptHost.h in Headers */,
                                7A0E76FA10BF08ED00A0276E /* InjectedScriptHost.h in Headers */,
                                85136CA80AED665900F90A3D /* westResizeCursor.png in Resources */,
                                1AB1AE7A0C051FDE00139F4F /* zoomInCursor.png in Resources */,
                                1AB1AE7B0C051FDE00139F4F /* zoomOutCursor.png in Resources */,
+                               5174E20C10A1F49A00F95E6F /* PopStateEvent.idl in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                1479FAEF109AE37500DED655 /* RenderRubyBase.cpp in Sources */,
                                1479FAF1109AE37500DED655 /* RenderRubyRun.cpp in Sources */,
                                1479FAF3109AE37500DED655 /* RenderRubyText.cpp in Sources */,
+                               5189F01810B3781300F3C739 /* JSPopStateEventCustom.cpp in Sources */,
+                               5189F01D10B37BD900F3C739 /* JSPopStateEvent.cpp in Sources */,
+                               5189F0DE10B46B0E00F3C739 /* PopStateEvent.cpp in Sources */,
                                18C5FCA510A3991F0048438D /* WebKitSharedScript.cpp in Sources */,
                                18C5FCA810A3991F0048438D /* WebKitSharedScriptRepository.cpp in Sources */,
                                18C5FCB710A3C6F20048438D /* SharedScriptContext.cpp in Sources */,
index 2c6e130b2d7d5fcd78360f21f5db64733feeb1e6..85a7a95cfc7f68cdbabfa1cc1deb0012b95b8ab7 100644 (file)
@@ -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);
 
index b24b1ffedbd6494372ebb9e74c33f431732c2aa3..db2ebde95d2175d4669ea6aafeb64ab46ebe4b04 100644 (file)
@@ -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 (file)
index 0000000..ee86a09
--- /dev/null
@@ -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
index 723c6dc63284d5bc7447c54c1064b55bdeb2c493..923efa2247c9b3034f6c4347a208b8a57a22e8ba 100644 (file)
@@ -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())
index 3aee2d69d7250fa5b7ab27edc169e984dc810f3f..54c563b7ba3c3ed63b586d9042814241af3f8a45 100644 (file)
@@ -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;
 
index 65906a1898eb07fcf8eee26dfe34e9bbc8c0d77a..ed1140a37b8faad201362bfa7c9f5ed2272dc9df 100644 (file)
@@ -136,6 +136,11 @@ bool Event::isPageTransitionEvent() const
     return false;
 }
 
+bool Event::isPopStateEvent() const
+{
+    return false;
+}
+
 bool Event::isProgressEvent() const
 {
     return false;
index 3b36e026b89efc126abb28dc3eb0d803e4919168..ec768e9d0f0bf882b57a6227461400002378891f 100644 (file)
@@ -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;
index ffa5a2ea34163e69750599b25e01b8d1866f58b6..8c3e3e43dd00b313002594efd500bdce8e8a37a8 100644 (file)
@@ -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 (file)
index 0000000..b9ad862
--- /dev/null
@@ -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 (file)
index 0000000..2fb8d06
--- /dev/null
@@ -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 (file)
index 0000000..c6775ec
--- /dev/null
@@ -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;
+    };
+
+}
index 0aad98b802ff8041651d0e3979e6514bdafd3559..3550e375d763b61e4682f91ec1fddf17ff2d6fd7 100644 (file)
@@ -34,6 +34,7 @@
 #include "Logging.h"
 #include "Page.h"
 #include "PageCache.h"
+#include "SerializedScriptValue.h"
 
 using namespace std;
 
@@ -57,13 +58,18 @@ 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;
         }
index fdc3360f2b5e099dd67ed560b5b5767e884c0513..88398a557a677c7e473786913b7774b119ddbeb1 100644 (file)
 
 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) 
index 2ca29e3c1c11cc2efd3780902a56264bd1f2be6f..e604ac5959cb7a98438dd76b2d0a320a5d6056e8 100644 (file)
@@ -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()));
index d991470df17efa372bb2195dc9389ed2d0785176..4c91e76520aa10bfd979542f0e011fd1cefe4c2e 100644 (file)
@@ -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;
index 596c4587ad81d87f8300b88c03cb50fd332d0af2..0e91c884696e708a6d62c823c7aec3d7fae1173a 100644 (file)
@@ -182,6 +182,7 @@ onpaste
 onpause
 onplay
 onplaying
+onpopstate
 onprogress
 onratechange
 onreset
index a356bf347f3f4dda0afc2e216d0931744e56f895..35133c08e319ec4bb42fb0507e547dfe6014d9b3 100644 (file)
@@ -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)
index e898c88495de9052055a4a95a3a16906755c5820..76b49a1846d23f3ea4b500c48b93aa7380e07e1a 100644 (file)
@@ -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
index 2e93e2e1b988dedf7a6b1e0fc50ad7bae3cf38b4..b2f0c6506898b22d2d6465e41de60c8a5ea13254 100644 (file)
@@ -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;
index cbeba87566fd777abd60e2ff0a3ec997b75523ad..6c1630bf2f3a582da1b270850b1db8c1453d050d 100644 (file)
@@ -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);
 }
index 2b2d7eacd2c2ceeee172bb81e9dae2e08973fcb3..0c75efe1a219d179080e489f82b802f55b477830 100644 (file)
@@ -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);
index b44a071e07b8b5e56e5d52f03e5a60f4d8e7ffa4..6ab1a8bce190891bcc14a530bc19b8193102385b 100644 (file)
@@ -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;
index 820cb36fc01d3ddea5d91f8a74eebb916cd624a8..1507fe921caabc6fa42303cbf8012cf314874902 100644 (file)
@@ -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);
index 70d5afdc43f432a54bff4c22754698ea076afee7..76a5aee394905dae69ef85bf761ed9b5f4b5c699 100644 (file)
@@ -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; }
index bf34a1bb85e2db6e1b3752a8dd8f23b88b377e10..8f7a572f90b34cdb67357cdab8f00f3468eb2873 100644 (file)
@@ -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() { }
index 52453c678dcb77ebc9c5eceeb215c8c2f0dd356b..2047c8d2ffc1da74807fc3f4ed10e224ba8f6714 100644 (file)
@@ -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)
index 6c676b96fde4696fed70d72a243b6a6b60ef6daf..7304bfd942f94e785ea2b5f18bc5aebdc1e2a664 100644 (file)
@@ -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();
 
index bccbb8aa19b116a5f6bed8ce3ccb9a5840f58e2c..99505b803289caaec1af6b432c4317f5e88eb7b0 100644 (file)
@@ -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;
index 501640a7b925698b419d554fe2b04013f10070a8..f7d1f98b913e08ac4f60ff68576388d8a6171b21 100644 (file)
@@ -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
index 4ecae69f9e10c8fd20bcb74ba66df3c429af9e98..7c4a1ac483a0f7f08b93bf3123dabd8713d35949 100644 (file)
@@ -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);
index fefb7b97bc522211c676ac2c185c26e1a4eee477..146f390c7202fce24a8cd569100c5a87119b9c37 100644 (file)
@@ -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
index e83399893424d22ce9388da6681fc9594fac96a4..f92016ace005a2399b209ddbc518a501df7fbeb9 100644 (file)
@@ -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;
index bf7a313642a815516a48c27c5dcde92532ac3958..ea9819e41ca7a6574f597045e22789c21fc1243d 100644 (file)
 #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
index f0df2de3856367d5159b200335df0b4f86243541..66a6a03b92c3904ec6f409651bb56dd14378d6d8 100644 (file)
 #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
 
index 914d441713c77addf5f80122ea45b7513e92dfc6..379055205daf591c31d4365d2a8e95b5ea460a8e 100644 (file)
@@ -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);
     };
 
 }
index 4321e0843ed2e9c0c5c4a1f638352cfb252b404d..c4f33d6e195b5b8eabbb018d43764e888da71314 100644 (file)
@@ -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);
 }
 
index 88e7d97fe708176e4dea9388c62fbfe609b0947c..9c48a1523c8bb60a7e0c6a388929dba4a3e02990 100644 (file)
@@ -1,3 +1,15 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        * src/FrameLoaderClientImpl.cpp:
+        (WebKit::FrameLoaderClientImpl::dispatchDidPushStateWithinPage):
+        (WebKit::FrameLoaderClientImpl::dispatchDidReplaceStateWithinPage):
+        (WebKit::FrameLoaderClientImpl::dispatchDidPopStateWithinPage):
+        * src/FrameLoaderClientImpl.h:
+
 2009-12-03  Pavel Feldman  <pfeldman@chromium.org>
 
         Reviewed by Timothy Hatcher.
index 7f3dddcb980649de6d3664b137fcf9b1718d88ab..74189b852fe3a1c9c0615aad5bbe14d4acb8754d 100644 (file)
@@ -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())
index 7d7c68586d17bb3041ab273d5352ccc32ac765e3..4ddfe5f3efbeef671717a7712c47982fb44dc8fa 100644 (file)
@@ -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();
index 4142116820037cd0edbf3a7ddc992f6ea20aae88..c0c42d44b3c87f873248cfaf2b6fce9b4157d265 100644 (file)
@@ -1,3 +1,15 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        * WebCoreSupport/FrameLoaderClientGtk.cpp:
+        (WebKit::FrameLoaderClient::dispatchDidPushStateWithinPage):
+        (WebKit::FrameLoaderClient::dispatchDidReplaceStateWithinPage):
+        (WebKit::FrameLoaderClient::dispatchDidPopStateWithinPage):
+        * WebCoreSupport/FrameLoaderClientGtk.h:
+
 2009-12-03  Pavel Feldman  <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
index 1b1c9c8bb2e75422c9b5fd120016a789c0371669..1b6bfa7ed1499b4397d9966e6b2f5e28cd80b0a0 100644 (file)
@@ -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();
index c62a1fe5bee6713cbcd93eb7dcd4d9b26f4e2690..cace770e4bafcf0c0f45dcb396bad4fd0997fc76 100644 (file)
@@ -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();
index af84eaac753c06dcf9eb5b30d9d552021e376a27..576fd2209e73cab6e6ed9c6fcd056e9b2cdec38d 100644 (file)
@@ -1,3 +1,19 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        * WebCoreSupport/WebFrameLoaderClient.h:
+        * WebCoreSupport/WebFrameLoaderClient.mm:
+        (WebFrameLoaderClient::dispatchDidPushStateWithinPage):
+        (WebFrameLoaderClient::dispatchDidReplaceStateWithinPage):
+        (WebFrameLoaderClient::dispatchDidPopStateWithinPage):
+        * WebView/WebDelegateImplementationCaching.h:
+        * WebView/WebFrameLoadDelegatePrivate.h:
+        * WebView/WebView.mm:
+        (-[WebView _cacheFrameLoadDelegateImplementations]):
+
 2009-12-03  Pavel Feldman  <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
index fb3c232c841f3afee7e814e0c493a6d8261f7c60..277478372ac8f7104aad5841be812e6c843588c4 100644 (file)
@@ -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();
index 2297e238bacb1c1c7152de1567bb3a98f408722a..9816e017e8a84f79dbd6bb1ca4b9822822e10d18 100644 (file)
@@ -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());   
index 8f0d1455fe07a723f34a5c8bf1e154b96ad40a8f..684934adffab7f2afed32e6e96ad0d30eaa8f9a2 100644 (file)
@@ -57,6 +57,9 @@ struct WebFrameLoadDelegateImplementationCache {
     IMP didCancelClientRedirectForFrameFunc;
     IMP willPerformClientRedirectToURLDelayFireDateForFrameFunc;
     IMP didChangeLocationWithinPageForFrameFunc;
+    IMP didPushStateWithinPageForFrameFunc;
+    IMP didReplaceStateWithinPageForFrameFunc;
+    IMP didPopStateWithinPageForFrameFunc;
     IMP willCloseFrameFunc;
     IMP didStartProvisionalLoadForFrameFunc;
     IMP didReceiveTitleForFrameFunc;
index 45a4f08dbd5a2a94e3065e4cc914122d1c115f3c..2359cc61a0e9ee4f54b72ce47321d540beb55b61 100644 (file)
@@ -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
index 3238a47cb95778a8ebb1e1c011a75f6dc8b6377d..bd8a4aba3fe8c42f49183ed8b7fa4d5d58aa936d 100644 (file)
@@ -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:));
index 4fef0ac0414e1c640f9cef83f2b6cca731175a84..e40a74b49f461159abddf5d0e8e085fbcc70fa1f 100644 (file)
@@ -1,3 +1,15 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        * WebCoreSupport/FrameLoaderClientQt.cpp:
+        (WebCore::FrameLoaderClientQt::dispatchDidPushStateWithinPage):
+        (WebCore::FrameLoaderClientQt::dispatchDidReplaceStateWithinPage):
+        (WebCore::FrameLoaderClientQt::dispatchDidPopStateWithinPage):
+        * WebCoreSupport/FrameLoaderClientQt.h:
+
 2009-12-03  Pavel Feldman  <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
index f570b83e7560d30c8e5f51b8c735aa47f2c9f9dc..4593fc5a1eaf5933320482d1757823077ccd78e6 100644 (file)
@@ -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()
 {
index cd54983bc1c007458c3a114a503b2a638c367051..32b9caaf5eaa0112015a67c78f96414f1bb5092b 100644 (file)
@@ -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();
index 16abcae862649dcccaeb2e712c88f79cf7ecb7d4..f4570343e10c1c821f7e42e94de5744dbb04569e 100644 (file)
@@ -1,3 +1,16 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        * Interfaces/IWebFrameLoadDelegatePrivate2.idl:
+        * WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebFrameLoaderClient::dispatchDidPushStateWithinPage):
+        (WebFrameLoaderClient::dispatchDidReplaceStateWithinPage):
+        (WebFrameLoaderClient::dispatchDidPopStateWithinPage):
+        * WebCoreSupport/WebFrameLoaderClient.h:
+
 2009-12-03  Pavel Feldman  <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
index a38223cb82793f390ce572a2b482a5f0509a85ad..7e07c55fb2f8504fe06997f671b58d84a2191950 100644 (file)
@@ -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);
 }
index 8df01382a69aa5191773f364c09348bfd483506d..b927c72c803a3439dda895ae6560f352f20d750f 100644 (file)
@@ -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();
index 21599bc1660bc08ed2a3bdfcc7839ae9d793329f..f1fb5f7c3903729c81f245359ed4957572fa7c99 100644 (file)
@@ -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();
index 5d0ca0e203563131ab9c61282230821f66e07126..06a504327c577c1249d7d3a3dba4fcd150571a3a 100644 (file)
@@ -1,3 +1,15 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        * WebKitSupport/FrameLoaderClientWx.cpp:
+        (WebCore::FrameLoaderClientWx::dispatchDidPushStateWithinPage):
+        (WebCore::FrameLoaderClientWx::dispatchDidReplaceStateWithinPage):
+        (WebCore::FrameLoaderClientWx::dispatchDidPopStateWithinPage):
+        * WebKitSupport/FrameLoaderClientWx.h:
+
 2009-12-03  Pavel Feldman  <pfeldman@dhcp-172-28-174-220.spb.corp.google.com>
 
         Reviewed by Timothy Hatcher.
index 1ffb23d2b084e7834a27dadae9a0a3bc4029bd93..c09f8defa638c8231bd2dfed0e980989c59f74e1 100644 (file)
@@ -262,6 +262,20 @@ void FrameLoaderClientWx::dispatchDidChangeLocationWithinPage()
     notImplemented();
 }
 
+void FrameLoaderClientWx::dispatchDidPushStateWithinPage()
+{
+    notImplemented();
+}
+
+void FrameLoaderClientWx::dispatchDidReplaceStateWithinPage()
+{
+    notImplemented();
+}
+
+void FrameLoaderClientWx::dispatchDidPopStateWithinPage()
+{
+    notImplemented();
+}
 
 void FrameLoaderClientWx::dispatchWillClose()
 {
index ffabc63e0256c5be63407184e2e5d30ea9bf3f14..0c29941f712a1714bbb1776c71f69d59fbf3923a 100644 (file)
@@ -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();
index c7d8ca5f17f02e3b9a458137f73784c75494dceb..ad865ff4dd1c899e4d2ff892148753f31ac89fdd 100644 (file)
@@ -1,3 +1,16 @@
+2009-12-03  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+        Keep DRT-win building...
+
+        * DumpRenderTree/win/FrameLoadDelegate.h:
+        (FrameLoadDelegate::didPushStateWithinPageForFrame):
+        (FrameLoadDelegate::didReplaceStateWithinPageForFrame):
+        (FrameLoadDelegate::didPopStateWithinPageForFrame):
+
 2009-12-03  Andras Becsi  <abecsi@inf.u-szeged.hu>
 
         Unreviewed build fix.
index 0deeecaaaed7a8bea859e3704b23a34001ea0745..cc6653beb8c7a1ae980934832c77e365ed4d8667 100644 (file)
@@ -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*);