Changeset 66628 in webkit


Ignore:
Timestamp:
Sep 1, 2010 6:00:51 PM (14 years ago)
Author:
commit-queue@webkit.org
Message:

2010-09-01 Mihai Parparita <mihaip@chromium.org>

Reviewed by Brady Eidson.

popstate event is not fired until document opts in by calling pushstate.
https://bugs.webkit.org/show_bug.cgi?id=41372

Add two tests to check how often popstate is being fired (for both
fragment changes and page changes, especially with the page cache
enabled).

Update existing state object tests to handle popstate being fired for
the page being navigated to (right after onload).

  • fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html:
  • fast/loader/stateobjects/document-destroyed-navigate-back.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-body-inline-attribute.html:
  • fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html:
  • fast/loader/stateobjects/popstate-fires-on-history-traversal-expected.txt: Added.
  • fast/loader/stateobjects/popstate-fires-on-history-traversal.html: Added.
  • fast/loader/stateobjects/popstate-fires-with-page-cache-expected.txt: Added.
  • fast/loader/stateobjects/popstate-fires-with-page-cache.html: Added.
  • 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-in-iframe.html:
  • fast/loader/stateobjects/replacestate-then-pushstate.html:
  • fast/loader/stateobjects/resources/popstate-fires-with-page-cache-1.html: Added.
  • fast/loader/stateobjects/resources/popstate-fires-with-page-cache-2.html: Added.
  • fast/loader/stateobjects/resources/replacestate-in-iframe-window-child.html:

2010-09-01 Mihai Parparita <mihaip@chromium.org>

Reviewed by Brady Eidson.

popstate event is not fired until document opts in by calling pushstate.
https://bugs.webkit.org/show_bug.cgi?id=41372

Fire popstate even when we don't have a state object when a page is
loaded (for both regular loads and those from the page cache). Also
fire popstate when doing in-document navigation via fragment changes.
This is consistent with both Gecko and recent the HTML5 spec change:
http://html5.org/tools/web-apps-tracker?from=5376&to=5377

Tests: fast/loader/stateobjects/popstate-fires-on-history-traversal.html

fast/loader/stateobjects/popstate-fires-with-page-cache.html

  • bindings/js/SerializedScriptValue.cpp:
  • bindings/js/SerializedScriptValue.h: (WebCore::SerializedScriptValue::create):
  • bindings/v8/SerializedScriptValue.cpp:
  • bindings/v8/SerializedScriptValue.h:
  • dom/Document.cpp: (WebCore::Document::implicitClose):
  • dom/Document.h:
  • history/CachedFrame.cpp: (WebCore::CachedFrameBase::restore):
  • loader/FrameLoader.cpp: (WebCore::FrameLoader::loadInSameDocument): (WebCore::FrameLoader::transitionToCommitted):
  • loader/HistoryController.cpp: (WebCore::HistoryController::pushState): (WebCore::HistoryController::replaceState):
Location:
trunk
Files:
6 added
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r66625 r66628  
     12010-09-01  Mihai Parparita  <mihaip@chromium.org>
     2
     3        Reviewed by Brady Eidson.
     4
     5        popstate event is not fired until document opts in by calling pushstate.
     6        https://bugs.webkit.org/show_bug.cgi?id=41372
     7
     8        Add two tests to check how often popstate is being fired (for both
     9        fragment changes and page changes, especially with the page cache
     10        enabled).
     11
     12        Update existing state object tests to handle popstate being fired for
     13        the page being navigated to (right after onload).
     14
     15        * fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html:
     16        * fast/loader/stateobjects/document-destroyed-navigate-back.html:
     17        * fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html:
     18        * fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html:
     19        * fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html:
     20        * fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html:
     21        * fast/loader/stateobjects/popstate-fires-on-history-traversal-expected.txt: Added.
     22        * fast/loader/stateobjects/popstate-fires-on-history-traversal.html: Added.
     23        * fast/loader/stateobjects/popstate-fires-with-page-cache-expected.txt: Added.
     24        * fast/loader/stateobjects/popstate-fires-with-page-cache.html: Added.
     25        * fast/loader/stateobjects/pushstate-object-types.html:
     26        * fast/loader/stateobjects/pushstate-then-replacestate.html:
     27        * fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html:
     28        * fast/loader/stateobjects/replacestate-in-iframe.html:
     29        * fast/loader/stateobjects/replacestate-then-pushstate.html:
     30        * fast/loader/stateobjects/resources/popstate-fires-with-page-cache-1.html: Added.
     31        * fast/loader/stateobjects/resources/popstate-fires-with-page-cache-2.html: Added.
     32        * fast/loader/stateobjects/resources/replacestate-in-iframe-window-child.html:
     33
    1342010-09-01  Matthew Willis  <lilmatt@flock.com>
    235
  • trunk/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back-with-fragment-scroll.html

    r60608 r66628  
    3333}
    3434
    35 function loaded()
     35function runTest()
    3636{
    3737    alert("LOADED");
     
    4444}
    4545
     46var beganTest = false;
     47
    4648function statePopped()
    4749{
     50    // The first time popstate fires, it's because the page has finished loading.
     51    // Only then can we begin the test.
     52    if (!beganTest) {
     53        beganTest = true;
     54        runTest();
     55        // Continue with the handler if we've already began the test.
     56        if (!sessionStorage.stage)
     57            return;
     58    }
     59   
    4860    alert("State popped - " + event.state + " (type " + typeof event.state + ")");
    4961
     
    8092
    8193</script>
    82 <body onload="loaded();" onpopstate="statePopped();" onhashchange="hashChanged();" onunload="/* disable page cache */">
     94<body onpopstate="statePopped();" onhashchange="hashChanged();" onunload="/* disable page cache */">
    8395<pre>
    8496This test:
  • trunk/LayoutTests/fast/loader/stateobjects/document-destroyed-navigate-back.html

    r65340 r66628  
    3232}
    3333
    34 function loaded()
     34function runTest()
    3535{
    3636    if (!sessionStorage.stage) {
     
    4343}
    4444
     45var beganTest = false;
     46
    4547function statePopped()
    4648{
     49    // The first time popstate fires, it's because the page has finished loading.
     50    // Only then can we begin the test.
     51    if (!beganTest) {
     52        beganTest = true;
     53        runTest();
     54        // Continue with the handler if we've already began the test.
     55        if (!sessionStorage.stage)
     56            return;
     57    }
     58   
    4759    alert("State popped - " + event.state + " (type " + typeof event.state + ")");
    4860    if (event.state == "FirstEntry") {
     
    6375
    6476</script>
    65 <body onload="loaded();" onpopstate="statePopped();" onunload="/* disable page cache */">
     77<body onpopstate="statePopped();" onunload="/* disable page cache */">
    6678<pre>
    6779This test:
  • trunk/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-addeventlistener.html

    r51644 r66628  
    2121}
    2222
     23var beganTest = false;
     24
    2325function statePopped()
    2426{
     27    // The first time popstate fires, it's because the page has finished loading.
     28    // Only then can we begin the test.
     29    if (!beganTest) {
     30        beganTest = true;
     31        runTest();
     32        return;
     33    }
     34   
    2535    log("State popped - " + event.state + " (type " + typeof event.state + ")");
    2636    if (event.state == null)
     
    3343
    3444</script>
    35 <body onload="runTest();">
     45<body>
    3646<pre>
    3747This test does the following:
  • trunk/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-attribute.html

    r51644 r66628  
    2121}
    2222
     23var beganTest = false;
     24
    2325function statePopped()
    2426{
     27    // The first time popstate fires, it's because the page has finished loading.
     28    // Only then can we begin the test.
     29    if (!beganTest) {
     30        beganTest = true;
     31        runTest();
     32        return;
     33    }
     34   
    2535    log("State popped - " + event.state + " (type " + typeof event.state + ")");
    2636    if (event.state == null) {
     
    3242
    3343</script>
    34 <body onload="runTest();">
     44<body>
    3545<pre>
    3646This test does the following:
  • trunk/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-body-inline-attribute.html

    r51644 r66628  
    2121}
    2222
     23var beganTest = false;
     24
    2325function statePopped()
    2426{
     27    // The first time popstate fires, it's because the page has finished loading.
     28    // Only then can we begin the test.
     29    if (!beganTest) {
     30        beganTest = true;
     31        runTest();
     32        return;
     33    }
     34   
    2535    log("State popped - " + event.state + " (type " + typeof event.state + ")");
    2636    if (event.state == null) {
     
    3242
    3343</script>
    34 <body onload="runTest();" onpopstate="statePopped();">
     44<body onpopstate="statePopped();">
    3545<pre>
    3646This test does the following:
  • trunk/LayoutTests/fast/loader/stateobjects/popstate-after-load-complete-window-attribute.html

    r51644 r66628  
    2121}
    2222
     23var beganTest = false;
     24
    2325function statePopped()
    2426{
     27    // The first time popstate fires, it's because the page has finished loading.
     28    // Only then can we begin the test.
     29    if (!beganTest) {
     30        beganTest = true;
     31        runTest();
     32        return;
     33    }
     34
    2535    log("State popped - " + event.state + " (type " + typeof event.state + ")");
    2636    if (event.state == null)
     
    3343
    3444</script>
    35 <body onload="runTest();">
     45<body>
    3646<pre>
    3747This test does the following:
  • trunk/LayoutTests/fast/loader/stateobjects/pushstate-object-types.html

    r51655 r66628  
    1111function log(txt)
    1212{
    13     document.getElementById("logger").innerText += txt + "\n";
     13    document.getElementById("logger").appendChild(document.createTextNode(txt + "\n"));
    1414}
    15    
     15
    1616function runTest()
    1717{
     18    beganTest = true;
    1819    history.replaceState("FirstEntry", "Initial entry");
    1920    history.pushState(undefined, "undefined entry");
     
    4041}
    4142
    42 function statePopped()
     43var beganTest = false;
     44
     45onpopstate = function(event)
    4346{
     47    // The first time popstate fires, it's because the page has finished loading.
     48    // Only then can we begin the test.
     49    if (!beganTest) {
     50        beganTest = true;
     51        runTest();
     52        return;
     53    }
     54   
    4455    if (event.state instanceof Date)
    45         log("State popped - " + event.state * 1 + " (type " + typeof event.state + ")");
     56        log("State popped - " + event.state.getTime() + " (type " + typeof event.state + ")");
    4657    else
    4758        log("State popped - " + event.state + " (type " + typeof event.state + ")");
     
    5566
    5667</script>
    57 <body onload="runTest();" onpopstate="statePopped();">
    58 <pre id="someelement">
     68<body>
     69<p>
    5970This 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.
    60 </pre><br>
     71</p>
    6172<pre id="logger"></pre>
    6273</body>
  • trunk/LayoutTests/fast/loader/stateobjects/pushstate-then-replacestate.html

    r51644 r66628  
    2323}
    2424
    25 function statePopped()
     25var beganTest = false;
     26
     27onpopstate = function(event)
    2628{
     29    // The first time popstate fires, it's because the page has finished loading.
     30    // Only then can we begin the test.
     31    if (!beganTest) {
     32        beganTest = true;
     33        runTest();
     34        return;
     35    }
     36
    2737    log("State popped - " + event.state + " (type " + typeof event.state + ")");
    2838    if (event.state == null)
     
    3343
    3444</script>
    35 <body onload="runTest();" onpopstate="statePopped();">
     45<body>
    3646<pre>
    3747This test does the following:
  • trunk/LayoutTests/fast/loader/stateobjects/pushstate-with-fragment-urls-and-hashchange.html

    r53672 r66628  
    4545}
    4646
    47 function statePopped()
     47var beganTest = false;
     48
     49onpopstate = function(event)
    4850{
     51    // The first time popstate fires, it's because the page has finished loading.
     52    // Only then can we begin the test.
     53    if (!beganTest) {
     54        beganTest = true;
     55        runTest();
     56        return;
     57    }
     58
    4959    log("State popped with event " + event.state + " (type " + typeof event.state + ") and last path component " + lastPathComponent());
    5060    if (event.state != "OriginalEntry")
     
    5464}
    5565
    56 function hashChanged()
     66onhashchange = function()
    5767{
    5868    log("Hash change fired and last path component is " + lastPathComponent());
     
    6070
    6171</script>
    62 <body onload="runTest();" onpopstate="statePopped();" onhashchange="hashChanged();">
     72<body>
    6373<pre>
    6474This test pushes a series of state objects with different URLs and fragment identifiers meant to test the hashChange event as states are popped.
  • trunk/LayoutTests/fast/loader/stateobjects/replacestate-in-iframe.html

    r57042 r66628  
    3434onload = function() {
    3535  testWin = open("resources/replacestate-in-iframe-window.html");
    36   testWin.onload = windowLoaded;
    3736}
    3837</script>
  • trunk/LayoutTests/fast/loader/stateobjects/replacestate-then-pushstate.html

    r51644 r66628  
    2323}
    2424
    25 function statePopped()
     25var beganTest = false;
     26
     27onpopstate = function(event)
    2628{
     29    // The first time popstate fires, it's because the page has finished loading.
     30    // Only then can we begin the test.
     31    if (!beganTest) {
     32        beganTest = true;
     33        runTest();
     34        return;
     35    }
     36
    2737    log("State popped - " + event.state + " (type " + typeof event.state + ")");
    2838    if (event.state == "OriginalHistoryItem")
     
    3343
    3444</script>
    35 <body onload="runTest();" onpopstate="statePopped();">
     45<body>
    3646<pre>
    3747This test does the following:
  • trunk/LayoutTests/fast/loader/stateobjects/resources/replacestate-in-iframe-window-child.html

    r57042 r66628  
    55
    66onpopstate = function(e) {
     7  if (!sessionStorage.beganTest) {
     8      sessionStorage.beganTest = true;
     9      top.opener.windowLoaded();
     10      return;
     11  }
     12 
    713  alert("onpopstate");
    814  top.opener.notifyDone(window == parent ? "FAIL" : "PASS");
  • trunk/WebCore/ChangeLog

    r66624 r66628  
     12010-09-01  Mihai Parparita  <mihaip@chromium.org>
     2
     3        Reviewed by Brady Eidson.
     4
     5        popstate event is not fired until document opts in by calling pushstate.
     6        https://bugs.webkit.org/show_bug.cgi?id=41372
     7
     8        Fire popstate even when we don't have a state object when a page is
     9        loaded (for both regular loads and those from the page cache). Also
     10        fire popstate when doing in-document navigation via fragment changes.
     11        This is consistent with both Gecko and recent the HTML5 spec change:
     12        http://html5.org/tools/web-apps-tracker?from=5376&to=5377
     13
     14        Tests: fast/loader/stateobjects/popstate-fires-on-history-traversal.html
     15               fast/loader/stateobjects/popstate-fires-with-page-cache.html
     16
     17        * bindings/js/SerializedScriptValue.cpp:
     18        * bindings/js/SerializedScriptValue.h:
     19        (WebCore::SerializedScriptValue::create):
     20        * bindings/v8/SerializedScriptValue.cpp:
     21        * bindings/v8/SerializedScriptValue.h:
     22        * dom/Document.cpp:
     23        (WebCore::Document::implicitClose):
     24        * dom/Document.h:
     25        * history/CachedFrame.cpp:
     26        (WebCore::CachedFrameBase::restore):
     27        * loader/FrameLoader.cpp:
     28        (WebCore::FrameLoader::loadInSameDocument):
     29        (WebCore::FrameLoader::transitionToCommitted):
     30        * loader/HistoryController.cpp:
     31        (WebCore::HistoryController::pushState):
     32        (WebCore::HistoryController::replaceState):
     33
    1342010-09-01  Ryosuke Niwa  <rniwa@webkit.org>
    235
  • trunk/WebCore/bindings/js/SerializedScriptValue.cpp

    r65102 r66628  
    10811081}
    10821082
     1083SerializedScriptValue* SerializedScriptValue::nullValue()
     1084{
     1085    DEFINE_STATIC_LOCAL(RefPtr<SerializedScriptValue>, nullValue, (SerializedScriptValue::create()));
     1086    return nullValue.get();
     1087}
     1088
    10831089JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception)
    10841090{
  • trunk/WebCore/bindings/js/SerializedScriptValue.h

    r65104 r66628  
    214214            return adoptRef(new SerializedScriptValue(SerializedScriptValueData()));
    215215        }
     216       
     217        static SerializedScriptValue* nullValue();
    216218
    217219        PassRefPtr<SerializedScriptValue> release()
  • trunk/WebCore/bindings/v8/SerializedScriptValue.cpp

    r65105 r66628  
    10971097}
    10981098
     1099SerializedScriptValue* SerializedScriptValue::nullValue()
     1100{
     1101    DEFINE_STATIC_LOCAL(RefPtr<SerializedScriptValue>, nullValue, (SerializedScriptValue::create()));
     1102    return nullValue.get();
     1103}
     1104
    10991105PassRefPtr<SerializedScriptValue> SerializedScriptValue::release()
    11001106{
  • trunk/WebCore/bindings/v8/SerializedScriptValue.h

    r61114 r66628  
    5353    static PassRefPtr<SerializedScriptValue> create(String data);
    5454    static PassRefPtr<SerializedScriptValue> create();
     55   
     56    static SerializedScriptValue* nullValue();   
    5557
    5658    PassRefPtr<SerializedScriptValue> release();
  • trunk/WebCore/dom/Document.cpp

    r66498 r66628  
    8383#include "HTMLTitleElement.h"
    8484#include "HTTPParsers.h"
    85 #include "HistoryItem.h"
    8685#include "HitTestRequest.h"
    8786#include "HitTestResult.h"
     
    20222021    dispatchWindowLoadEvent();
    20232022    enqueuePageshowEvent(PageshowEventNotPersisted);
    2024     if (m_pendingStateObject)
    2025         enqueuePopstateEvent(m_pendingStateObject.release());
     2023    enqueuePopstateEvent(m_pendingStateObject ? m_pendingStateObject.release() : SerializedScriptValue::nullValue());
    20262024   
    20272025    if (f)
  • trunk/WebCore/dom/Document.h

    r66498 r66628  
    8686class HTMLInputElement;
    8787class HTMLMapElement;
    88 class HistoryItem;
    8988class HitTestRequest;
    9089class HitTestResult;
     
    991990    void enqueuePageshowEvent(PageshowEventPersistence);
    992991    void enqueueHashchangeEvent(const String& oldURL, const String& newURL);
     992    void enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject);
    993993
    994994    void addMediaCanStartListener(MediaCanStartListener*);
     
    10591059    void createStyleSelector();
    10601060
    1061     void enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject);
    10621061    void pendingEventTimerFired(Timer<Document>*);
    10631062
  • trunk/WebCore/history/CachedFrame.cpp

    r62677 r66628  
    3434#include "FrameLoaderClient.h"
    3535#include "FrameView.h"
     36#include "HistoryItem.h"
    3637#include "Logging.h"
    3738#include "PageTransitionEvent.h"
     
    107108
    108109    m_document->enqueuePageshowEvent(PageshowEventPersisted);
     110   
     111    HistoryItem* historyItem = frame->loader()->history()->currentItem();
     112    m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue());
     113   
    109114#if ENABLE(TOUCH_EVENTS)
    110115    if (m_document->hasListenerType(Document::TOUCH_LISTENER))
  • trunk/WebCore/loader/FrameLoader.cpp

    r66549 r66628  
    11691169    m_client->dispatchDidNavigateWithinPage();
    11701170
    1171     if (stateObject) {
    1172         m_frame->document()->statePopped(stateObject);
    1173         m_client->dispatchDidPopStateWithinPage();
    1174     }
     1171    m_frame->document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
     1172    m_client->dispatchDidPopStateWithinPage();
    11751173   
    11761174    if (hashChange) {
     
    19481946                    history()->updateForBackForwardNavigation();
    19491947
    1950                     if (history()->currentItem())
     1948                    // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
     1949                    if (history()->currentItem() && !cachedPage)
    19511950                        m_pendingStateObject = history()->currentItem()->stateObject();
    19521951
  • trunk/WebCore/loader/HistoryController.cpp

    r66238 r66628  
    658658    m_currentItem->setURLString(urlString);
    659659
    660     // Create a null state object for the previous HistoryItem so that we will
    661     // generate a popstate event when navigating back to it.
    662     // FIXME: http://webkit.org/b/41372 implies that we shouldn't need this.
    663     if (!m_previousItem->stateObject())
    664         m_previousItem->setStateObject(SerializedScriptValue::create());
    665 
    666660    page->backForwardList()->addItem(topItem.release());
    667661}
Note: See TracChangeset for help on using the changeset viewer.