Refactor static getter function prototype to include thisValue in addition to the...
[WebKit-https.git] / Source / WebCore / bindings / js / JSHistoryCustom.cpp
index d0eae28..09b12a2 100644 (file)
  */
 
 #include "config.h"
-#include "JSHistoryCustom.h"
+#include "JSHistory.h"
 
 #include "Frame.h"
 #include "History.h"
+#include "SerializedScriptValue.h"
 #include <runtime/JSFunction.h>
 
 using namespace JSC;
 
 namespace WebCore {
 
-static JSValue nonCachingStaticBackFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName)
+static EncodedJSValue nonCachingStaticBackFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName)
 {
-    return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 0, propertyName, jsHistoryPrototypeFunctionBack);
+    return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 0, propertyName.publicName(), jsHistoryPrototypeFunctionBack));
 }
 
-static JSValue nonCachingStaticForwardFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName)
+static EncodedJSValue nonCachingStaticForwardFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName)
 {
-    return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 0, propertyName, jsHistoryPrototypeFunctionForward);
+    return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 0, propertyName.publicName(), jsHistoryPrototypeFunctionForward));
 }
 
-static JSValue nonCachingStaticGoFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName)
+static EncodedJSValue nonCachingStaticGoFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName)
 {
-    return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 1, propertyName, jsHistoryPrototypeFunctionGo);
+    return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 1, propertyName.publicName(), jsHistoryPrototypeFunctionGo));
 }
 
-bool JSHistory::getOwnPropertySlotDelegate(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+bool JSHistory::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
 {
     // When accessing History cross-domain, functions are always the native built-in ones.
     // See JSDOMWindow::getOwnPropertySlotDelegate for additional details.
@@ -60,110 +61,91 @@ bool JSHistory::getOwnPropertySlotDelegate(ExecState* exec, const Identifier& pr
     // Our custom code is only needed to implement the Window cross-domain scheme, so if access is
     // allowed, return false so the normal lookup will take place.
     String message;
-    if (allowsAccessFromFrame(exec, impl()->frame(), message))
+    if (shouldAllowAccessToFrame(exec, impl().frame(), message))
         return false;
 
     // Check for the few functions that we allow, even when called cross-domain.
-    const HashEntry* entry = JSHistoryPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
+    // Make these read-only / non-configurable to prevent writes via defineProperty.
+    const HashEntry* entry = JSHistoryPrototype::info()->propHashTable(exec)->entry(exec, propertyName);
     if (entry) {
         // Allow access to back(), forward() and go() from any frame.
-        if (entry->attributes() & Function) {
+        if (entry->attributes() & JSC::Function) {
             if (entry->function() == jsHistoryPrototypeFunctionBack) {
-                slot.setCustom(this, nonCachingStaticBackFunctionGetter);
+                slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticBackFunctionGetter);
                 return true;
             } else if (entry->function() == jsHistoryPrototypeFunctionForward) {
-                slot.setCustom(this, nonCachingStaticForwardFunctionGetter);
+                slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticForwardFunctionGetter);
                 return true;
             } else if (entry->function() == jsHistoryPrototypeFunctionGo) {
-                slot.setCustom(this, nonCachingStaticGoFunctionGetter);
+                slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticGoFunctionGetter);
                 return true;
             }
         }
     } else {
         // Allow access to toString() cross-domain, but always Object.toString.
         if (propertyName == exec->propertyNames().toString) {
-            slot.setCustom(this, objectToStringFunctionGetter);
+            slot.setCustom(this, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter);
             return true;
         }
     }
 
-    printErrorMessageForFrame(impl()->frame(), message);
+    printErrorMessageForFrame(impl().frame(), message);
     slot.setUndefined();
     return true;
 }
 
-bool JSHistory::getOwnPropertyDescriptorDelegate(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+bool JSHistory::putDelegate(ExecState* exec, PropertyName, JSValue, PutPropertySlot&)
 {
-    if (!impl()->frame()) {
-        descriptor.setUndefined();
-        return true;
-    }
-
-    // Throw out all cross domain access
-    if (!allowsAccessFromFrame(exec, impl()->frame()))
+    // Only allow putting by frames in the same origin.
+    if (!shouldAllowAccessToFrame(exec, impl().frame()))
         return true;
-
-    // Check for the few functions that we allow, even when called cross-domain.
-    const HashEntry* entry = JSHistoryPrototype::s_info.propHashTable(exec)->entry(exec, propertyName);
-    if (entry) {
-        PropertySlot slot;
-        // Allow access to back(), forward() and go() from any frame.
-        if (entry->attributes() & Function) {
-            if (entry->function() == jsHistoryPrototypeFunctionBack) {
-                slot.setCustom(this, nonCachingStaticBackFunctionGetter);
-                descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
-                return true;
-            } else if (entry->function() == jsHistoryPrototypeFunctionForward) {
-                slot.setCustom(this, nonCachingStaticForwardFunctionGetter);
-                descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
-                return true;
-            } else if (entry->function() == jsHistoryPrototypeFunctionGo) {
-                slot.setCustom(this, nonCachingStaticGoFunctionGetter);
-                descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
-                return true;
-            }
-        }
-    } else {
-        // Allow access to toString() cross-domain, but always Object.toString.
-        if (propertyName == exec->propertyNames().toString) {
-            PropertySlot slot;
-            slot.setCustom(this, objectToStringFunctionGetter);
-            descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
-            return true;
-        }
-    }
-
-    descriptor.setUndefined();
-    return true;
+    return false;
 }
 
-bool JSHistory::putDelegate(ExecState* exec, const Identifier&, JSValue, PutPropertySlot&)
+bool JSHistory::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
 {
-    // Only allow putting by frames in the same origin.
-    if (!allowsAccessFromFrame(exec, impl()->frame()))
-        return true;
-    return false;
+    JSHistory* thisObject = jsCast<JSHistory*>(cell);
+    // Only allow deleting by frames in the same origin.
+    if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame()))
+        return false;
+    return Base::deleteProperty(thisObject, exec, propertyName);
 }
 
-bool JSHistory::deleteProperty(ExecState* exec, const Identifier& propertyName)
+bool JSHistory::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
 {
+    JSHistory* thisObject = jsCast<JSHistory*>(cell);
     // Only allow deleting by frames in the same origin.
-    if (!allowsAccessFromFrame(exec, impl()->frame()))
+    if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame()))
         return false;
-    return Base::deleteProperty(exec, propertyName);
+    return Base::deletePropertyByIndex(thisObject, exec, propertyName);
 }
 
-void JSHistory::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+void JSHistory::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
 {
+    JSHistory* thisObject = jsCast<JSHistory*>(object);
     // Only allow the history object to enumerated by frames in the same origin.
-    if (!allowsAccessFromFrame(exec, impl()->frame()))
+    if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame()))
         return;
-    Base::getOwnPropertyNames(exec, propertyNames, mode);
+    Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+JSValue JSHistory::state(ExecState *exec) const
+{
+    History& history = impl();
+
+    JSValue cachedValue = m_state.get();
+    if (!cachedValue.isEmpty() && !history.stateChanged())
+        return cachedValue;
+
+    RefPtr<SerializedScriptValue> serialized = history.state();
+    JSValue result = serialized ? serialized->deserialize(exec, globalObject(), 0) : jsNull();
+    const_cast<JSHistory*>(this)->m_state.set(exec->vm(), this, result);
+    return result;
 }
 
 JSValue JSHistory::pushState(ExecState* exec)
 {
-    RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0));
+    RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0, 0);
     if (exec->hadException())
         return jsUndefined();
 
@@ -179,15 +161,17 @@ JSValue JSHistory::pushState(ExecState* exec)
     }
 
     ExceptionCode ec = 0;
-    impl()->stateObjectAdded(historyState.release(), title, url, History::StateObjectPush, ec);
+    impl().stateObjectAdded(historyState.release(), title, url, History::StateObjectPush, ec);
     setDOMException(exec, ec);
 
+    m_state.clear();
+
     return jsUndefined();
 }
 
 JSValue JSHistory::replaceState(ExecState* exec)
 {
-    RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0));
+    RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0, 0);
     if (exec->hadException())
         return jsUndefined();
 
@@ -203,9 +187,11 @@ JSValue JSHistory::replaceState(ExecState* exec)
     }
 
     ExceptionCode ec = 0;
-    impl()->stateObjectAdded(historyState.release(), title, url, History::StateObjectReplace, ec);
+    impl().stateObjectAdded(historyState.release(), title, url, History::StateObjectReplace, ec);
     setDOMException(exec, ec);
 
+    m_state.clear();
+
     return jsUndefined();
 }