Title: [107058] trunk
Revision
107058
Author
commit-qu...@webkit.org
Date
2012-02-08 02:39:13 -0800 (Wed, 08 Feb 2012)

Log Message

Add state attribute to history's dom interface.
https://bugs.webkit.org/show_bug.cgi?id=76035

Patch by Pablo Flouret <pab...@motorola.com> on 2012-02-08
Reviewed by Kentaro Hara.

Source/WebCore:

Tests: fast/loader/stateobjects/state-attribute-object-types.html
       fast/loader/stateobjects/state-attribute-only-one-deserialization.html

* bindings/js/JSHistoryCustom.cpp:
(WebCore::JSHistory::state):
(WebCore):
(WebCore::JSHistory::pushState):
(WebCore::JSHistory::replaceState):
* bindings/v8/custom/V8HistoryCustom.cpp:
(WebCore::V8History::stateAccessorGetter):
(WebCore):
(WebCore::V8History::pushStateCallback):
(WebCore::V8History::replaceStateCallback):
* page/History.cpp:
(WebCore::History::History):
(WebCore::History::state):
(WebCore):
(WebCore::History::stateInternal):
(WebCore::History::stateChanged):
* page/History.h:
(History):
* page/History.idl:

LayoutTests:

* fast/dom/Window/window-appendages-cleared-expected.txt:
* fast/loader/stateobjects/state-attribute-object-types-expected.txt: Added.
* fast/loader/stateobjects/state-attribute-object-types.html: Added.
* fast/loader/stateobjects/state-attribute-only-one-deserialization-expected.txt: Added.
* fast/loader/stateobjects/state-attribute-only-one-deserialization.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (107057 => 107058)


--- trunk/LayoutTests/ChangeLog	2012-02-08 10:21:49 UTC (rev 107057)
+++ trunk/LayoutTests/ChangeLog	2012-02-08 10:39:13 UTC (rev 107058)
@@ -1,3 +1,16 @@
+2012-02-08  Pablo Flouret  <pab...@motorola.com>
+
+        Add state attribute to history's dom interface.
+        https://bugs.webkit.org/show_bug.cgi?id=76035
+
+        Reviewed by Kentaro Hara.
+
+        * fast/dom/Window/window-appendages-cleared-expected.txt:
+        * fast/loader/stateobjects/state-attribute-object-types-expected.txt: Added.
+        * fast/loader/stateobjects/state-attribute-object-types.html: Added.
+        * fast/loader/stateobjects/state-attribute-only-one-deserialization-expected.txt: Added.
+        * fast/loader/stateobjects/state-attribute-only-one-deserialization.html: Added.
+
 2012-02-08  Nikolas Zimmermann  <nzimmerm...@rim.com>
 
         SVGLoad event fires too early

Modified: trunk/LayoutTests/fast/dom/Window/window-appendages-cleared-expected.txt (107057 => 107058)


--- trunk/LayoutTests/fast/dom/Window/window-appendages-cleared-expected.txt	2012-02-08 10:21:49 UTC (rev 107057)
+++ trunk/LayoutTests/fast/dom/Window/window-appendages-cleared-expected.txt	2012-02-08 10:39:13 UTC (rev 107058)
@@ -4,6 +4,7 @@
 PASS history.length == "LEFTOVER" is false
 PASS history.pushState == "LEFTOVER" is false
 PASS history.replaceState == "LEFTOVER" is false
+PASS history.state == "LEFTOVER" is false
 PASS location.assign == "LEFTOVER" is false
 PASS location.hash == "LEFTOVER" is false
 PASS location.host == "LEFTOVER" is false

Added: trunk/LayoutTests/fast/loader/stateobjects/state-attribute-object-types-expected.txt (0 => 107058)


--- trunk/LayoutTests/fast/loader/stateobjects/state-attribute-object-types-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/loader/stateobjects/state-attribute-object-types-expected.txt	2012-02-08 10:39:13 UTC (rev 107058)
@@ -0,0 +1,25 @@
+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 state attribute returns the expected objects.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS history.state is defined.
+
+history.state should initially be null.
+PASS history.state is null
+
+PASS history.state is undefined.
+PASS history.state is null
+PASS history.state is false
+PASS history.state is true
+PASS history.state is 42
+PASS history.state is "String"
+PASS +history.state is +(new Date(0))
+PASS history.state == '/foo/gi' is true
+PASS history.state == '' is true
+PASS history.state == '[object Object]' is true
+PASS history.state == '[object ImageData]' is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/loader/stateobjects/state-attribute-object-types.html (0 => 107058)


--- trunk/LayoutTests/fast/loader/stateobjects/state-attribute-object-types.html	                        (rev 0)
+++ trunk/LayoutTests/fast/loader/stateobjects/state-attribute-object-types.html	2012-02-08 10:39:13 UTC (rev 107058)
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+</head/>
+<body>
+<script>
+    description('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 state attribute returns the expected objects.');
+
+    if (window.layoutTestController)
+        layoutTestController.clearBackForwardList();
+
+    shouldBeDefined("history.state");
+    debug("\nhistory.state should initially be null.");
+    shouldBeNull("history.state");
+    debug("");
+
+    history.pushState(undefined, "undefined entry");
+    shouldBeUndefined("history.state");
+    history.pushState(null, "null entry");
+    shouldBeNull("history.state");
+    history.pushState(false, "false entry");
+    shouldBeFalse("history.state");
+    history.pushState(true, "true entry");
+    shouldBeTrue("history.state");
+    history.pushState(42, "Number entry");
+    shouldBe("history.state", "42");
+    history.pushState("String", "String entry");
+    shouldBeEqualToString("history.state", "String");
+    history.pushState(new Date(0), "Date entry");
+    shouldBe("+history.state", "+(new Date(0))");
+    history.pushState(new RegExp("foo", "gi"), "RegExp entry");
+    shouldEvaluateTo("history.state", new RegExp("foo", "gi"));
+    history.pushState(new Array, "Array entry");
+    shouldEvaluateTo("history.state", new Array);
+    history.pushState(new Object, "Object entry");
+    shouldEvaluateTo("history.state", new Object);
+    history.pushState(document.createElement("canvas").getContext("2d").createImageData(10,10), "ImageData entry");
+    shouldEvaluateTo("history.state", document.createElement("canvas").getContext("2d").createImageData(10,10));
+</script>
+<script src=""
+</body>
+</html>
+

Added: trunk/LayoutTests/fast/loader/stateobjects/state-attribute-only-one-deserialization-expected.txt (0 => 107058)


--- trunk/LayoutTests/fast/loader/stateobjects/state-attribute-only-one-deserialization-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/loader/stateobjects/state-attribute-only-one-deserialization-expected.txt	2012-02-08 10:39:13 UTC (rev 107058)
@@ -0,0 +1,19 @@
+Make sure the same deserialization of the state object is used every time (both in the history object and popstate events).
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS history.state is defined.
+PASS history.state === history.state is true
+PASS history.state !== stateObject is true
+PASS history.state === stateObject is true
+
+Inside popstate event
+
+PASS history.state !== stateObject is true
+PASS popStateEvent.state !== stateObject is true
+FAIL popStateEvent.state === history.state should be true. Was false.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/loader/stateobjects/state-attribute-only-one-deserialization.html (0 => 107058)


--- trunk/LayoutTests/fast/loader/stateobjects/state-attribute-only-one-deserialization.html	                        (rev 0)
+++ trunk/LayoutTests/fast/loader/stateobjects/state-attribute-only-one-deserialization.html	2012-02-08 10:39:13 UTC (rev 107058)
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src=""
+</head/>
+<body>
+<script>
+    description("Make sure the same deserialization of the state object is used every time (both in the history object and popstate events).");
+
+    window.jsTestIsAsync = true;
+    if (window.layoutTestController) {
+        layoutTestController.clearBackForwardList();
+        layoutTestController.waitUntilDone();
+    }
+
+    shouldBeDefined("history.state");
+
+    // Create a new object.
+    var stateObject = ["a"];
+
+    // Use it as the state object in a replaceState.  This clones the object.
+    history.replaceState(stateObject, null, null);
+
+    shouldBeTrue("history.state === history.state");
+
+    // Since the actual history.state is a structured clone, it should not match our original object.
+    shouldBeTrue("history.state !== stateObject");
+
+    // Now let's refetch a copy of history.state to store;
+    stateObject = history.state;
+
+    // Our reference and the history.state itself should be the same.  This is now Adam's original assertion.
+    shouldBeTrue("history.state === stateObject");
+
+    // Now let's do a pushstate to add a history entry.
+    history.pushState(null, null, null);
+
+    // Now add a handler for the popstate event.
+    var popStateEvent;
+    window._onpopstate_ = function(e) {
+        debug("\nInside popstate event\n");
+        popStateEvent = e;
+        // Our stored reference to stateObject will not match the current state object, as it is a structured clone of the history item's state object.
+        shouldBeTrue("history.state !== stateObject");
+        // Our stored reference to stateObject will not match the state object in this pop state event, as it is the same as history.state which is a structured clone of the history item's state object.
+        shouldBeTrue("popStateEvent.state !== stateObject");
+        // The event's state object and the current state object should match.
+        shouldBeTrue("popStateEvent.state === history.state"); // This fails for now, needs to be fixed.
+
+        var s = document.createElement("script");
+        s.src = ""
+        document.body.appendChild(s);
+        setTimeout(finishJSTest, 0);
+    }
+
+    // Now let's go back to our original history entry which has a state object that we've stored a reference to already.
+    // This will fire our popstate event handler above.
+    history.back();
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (107057 => 107058)


--- trunk/Source/WebCore/ChangeLog	2012-02-08 10:21:49 UTC (rev 107057)
+++ trunk/Source/WebCore/ChangeLog	2012-02-08 10:39:13 UTC (rev 107058)
@@ -1,3 +1,33 @@
+2012-02-08  Pablo Flouret  <pab...@motorola.com>
+
+        Add state attribute to history's dom interface.
+        https://bugs.webkit.org/show_bug.cgi?id=76035
+
+        Reviewed by Kentaro Hara.
+
+        Tests: fast/loader/stateobjects/state-attribute-object-types.html
+               fast/loader/stateobjects/state-attribute-only-one-deserialization.html
+
+        * bindings/js/JSHistoryCustom.cpp:
+        (WebCore::JSHistory::state):
+        (WebCore):
+        (WebCore::JSHistory::pushState):
+        (WebCore::JSHistory::replaceState):
+        * bindings/v8/custom/V8HistoryCustom.cpp:
+        (WebCore::V8History::stateAccessorGetter):
+        (WebCore):
+        (WebCore::V8History::pushStateCallback):
+        (WebCore::V8History::replaceStateCallback):
+        * page/History.cpp:
+        (WebCore::History::History):
+        (WebCore::History::state):
+        (WebCore):
+        (WebCore::History::stateInternal):
+        (WebCore::History::stateChanged):
+        * page/History.h:
+        (History):
+        * page/History.idl:
+
 2012-02-08  Nikolas Zimmermann  <nzimmerm...@rim.com>
 
         SVGLoad event fires too early

Modified: trunk/Source/WebCore/bindings/js/JSHistoryCustom.cpp (107057 => 107058)


--- trunk/Source/WebCore/bindings/js/JSHistoryCustom.cpp	2012-02-08 10:21:49 UTC (rev 107057)
+++ trunk/Source/WebCore/bindings/js/JSHistoryCustom.cpp	2012-02-08 10:39:13 UTC (rev 107058)
@@ -164,6 +164,20 @@
     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
 }
 
+JSValue JSHistory::state(ExecState *exec) const
+{
+    History* history = static_cast<History*>(impl());
+
+    JSValue cachedValue = m_state.get();
+    if (!cachedValue.isEmpty() && !history->stateChanged())
+        return cachedValue;
+
+    SerializedScriptValue* serialized = history->state();
+    JSValue result = serialized ? serialized->deserialize(exec, globalObject(), 0) : jsNull();
+    const_cast<JSHistory*>(this)->m_state.set(exec->globalData(), this, result);
+    return result;
+}
+
 JSValue JSHistory::pushState(ExecState* exec)
 {
     RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0);
@@ -185,6 +199,8 @@
     impl()->stateObjectAdded(historyState.release(), title, url, History::StateObjectPush, ec);
     setDOMException(exec, ec);
 
+    m_state.clear();
+
     return jsUndefined();
 }
 
@@ -209,6 +225,8 @@
     impl()->stateObjectAdded(historyState.release(), title, url, History::StateObjectReplace, ec);
     setDOMException(exec, ec);
 
+    m_state.clear();
+
     return jsUndefined();
 }
 

Modified: trunk/Source/WebCore/bindings/v8/custom/V8HistoryCustom.cpp (107057 => 107058)


--- trunk/Source/WebCore/bindings/v8/custom/V8HistoryCustom.cpp	2012-02-08 10:21:49 UTC (rev 107057)
+++ trunk/Source/WebCore/bindings/v8/custom/V8HistoryCustom.cpp	2012-02-08 10:39:13 UTC (rev 107058)
@@ -41,6 +41,24 @@
 
 namespace WebCore {
 
+v8::Handle<v8::Value> V8History::stateAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
+{
+    INC_STATS("DOM.History.state");
+    History* history = V8History::toNative(info.Holder());
+
+    v8::Handle<v8::String> propertyName = v8::String::NewSymbol("state");
+    v8::Handle<v8::Value> value = info.Holder()->GetHiddenValue(propertyName);
+
+    if (!value.IsEmpty() && !history->stateChanged())
+        return value;
+
+    SerializedScriptValue* serialized = history->state();
+    value = serialized ? serialized->deserialize() : v8::Handle<v8::Value>(v8::Null());
+    info.Holder()->SetHiddenValue(propertyName, value);
+
+    return value;
+}
+
 v8::Handle<v8::Value> V8History::pushStateCallback(const v8::Arguments& args)
 {
     bool didThrow = false;
@@ -62,6 +80,7 @@
     ExceptionCode ec = 0;
     History* history = V8History::toNative(args.Holder());
     history->stateObjectAdded(historyState.release(), title, url, History::StateObjectPush, ec);
+    args.Holder()->DeleteHiddenValue(v8::String::NewSymbol("state"));
     return throwError(ec);
 }
 
@@ -86,6 +105,7 @@
     ExceptionCode ec = 0;
     History* history = V8History::toNative(args.Holder());
     history->stateObjectAdded(historyState.release(), title, url, History::StateObjectReplace, ec);
+    args.Holder()->DeleteHiddenValue(v8::String::NewSymbol("state"));
     return throwError(ec);
 }
 

Modified: trunk/Source/WebCore/page/History.cpp (107057 => 107058)


--- trunk/Source/WebCore/page/History.cpp	2012-02-08 10:21:49 UTC (rev 107057)
+++ trunk/Source/WebCore/page/History.cpp	2012-02-08 10:39:13 UTC (rev 107058)
@@ -42,6 +42,7 @@
 
 History::History(Frame* frame)
     : DOMWindowProperty(frame)
+    , m_lastStateObjectRequested(0)
 {
 }
 
@@ -54,6 +55,28 @@
     return m_frame->page()->backForward()->count();
 }
 
+SerializedScriptValue* History::state()
+{
+    m_lastStateObjectRequested = stateInternal();
+    return m_lastStateObjectRequested;
+}
+
+SerializedScriptValue* History::stateInternal() const
+{
+    if (!m_frame)
+        return 0;
+
+    if (HistoryItem* historyItem = m_frame->loader()->history()->currentItem())
+        return historyItem->stateObject();
+
+    return 0;
+}
+
+bool History::stateChanged() const
+{
+    return m_lastStateObjectRequested != stateInternal();
+}
+
 void History::back()
 {
     go(-1);

Modified: trunk/Source/WebCore/page/History.h (107057 => 107058)


--- trunk/Source/WebCore/page/History.h	2012-02-08 10:21:49 UTC (rev 107057)
+++ trunk/Source/WebCore/page/History.h	2012-02-08 10:39:13 UTC (rev 107058)
@@ -44,6 +44,8 @@
     static PassRefPtr<History> create(Frame* frame) { return adoptRef(new History(frame)); }
 
     unsigned length() const;
+    SerializedScriptValue* state();
+    bool stateChanged() const;
     void back();
     void forward();
     void go(int distance);
@@ -62,6 +64,10 @@
     explicit History(Frame*);
 
     KURL urlForState(const String& url);
+
+    SerializedScriptValue* stateInternal() const;
+
+    SerializedScriptValue* m_lastStateObjectRequested;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/History.idl (107057 => 107058)


--- trunk/Source/WebCore/page/History.idl	2012-02-08 10:21:49 UTC (rev 107057)
+++ trunk/Source/WebCore/page/History.idl	2012-02-08 10:39:13 UTC (rev 107058)
@@ -37,6 +37,7 @@
         OmitConstructor
     ] History {
         readonly attribute unsigned long length;
+        readonly attribute [CachedAttribute, Custom] SerializedScriptValue state;
 
         [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void back();
         [DoNotCheckDomainSecurity, CallWith=ScriptExecutionContext] void forward();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to