diff options
Diffstat (limited to 'JavaScriptCore/qt/api/qscriptvalue_p.h')
-rw-r--r-- | JavaScriptCore/qt/api/qscriptvalue_p.h | 282 |
1 files changed, 270 insertions, 12 deletions
diff --git a/JavaScriptCore/qt/api/qscriptvalue_p.h b/JavaScriptCore/qt/api/qscriptvalue_p.h index 49bec97..1d319ba 100644 --- a/JavaScriptCore/qt/api/qscriptvalue_p.h +++ b/JavaScriptCore/qt/api/qscriptvalue_p.h @@ -101,6 +101,7 @@ public: inline bool isError(); inline bool isObject(); inline bool isFunction(); + inline bool isArray(); inline QString toString() const; inline qsreal toNumber() const; @@ -121,7 +122,28 @@ public: inline bool assignEngine(QScriptEnginePrivate* engine); inline QScriptValuePrivate* property(const QString& name, const QScriptValue::ResolveFlags& mode); + inline QScriptValuePrivate* property(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode); inline QScriptValuePrivate* property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode); + inline JSValueRef property(quint32 property, JSValueRef* exception); + inline JSValueRef property(JSStringRef property, JSValueRef* exception); + inline bool hasOwnProperty(quint32 property); + inline bool hasOwnProperty(JSStringRef property); + template<typename T> + inline QScriptValuePrivate* property(T name, const QScriptValue::ResolveFlags& mode); + + inline void setProperty(const QString& name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags); + inline void setProperty(const QScriptStringPrivate* name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags); + inline void setProperty(const quint32 indexArray, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags); + inline void setProperty(quint32 property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception); + inline void setProperty(JSStringRef property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception); + inline void deleteProperty(quint32 property, JSValueRef* exception); + inline void deleteProperty(JSStringRef property, JSValueRef* exception); + template<typename T> + inline void setProperty(T name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags); + + QScriptValue::PropertyFlags propertyFlags(const QString& name, const QScriptValue::ResolveFlags& mode); + QScriptValue::PropertyFlags propertyFlags(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode); + QScriptValue::PropertyFlags propertyFlags(const JSStringRef name, const QScriptValue::ResolveFlags& mode); inline QScriptValuePrivate* call(const QScriptValuePrivate* , const QScriptValueList& args); @@ -427,6 +449,20 @@ bool QScriptValuePrivate::isFunction() } } +bool QScriptValuePrivate::isArray() +{ + switch (m_state) { + case JSValue: + if (refinedJSValue() != JSObject) + return false; + // Fall-through. + case JSObject: + return m_engine->isArray(*this); + default: + return false; + } +} + QString QScriptValuePrivate::toString() const { switch (m_state) { @@ -744,6 +780,7 @@ inline bool QScriptValuePrivate::instanceOf(QScriptValuePrivate* other) */ bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine) { + Q_ASSERT(engine); JSValueRef value; switch (m_state) { case CBool: @@ -778,31 +815,252 @@ bool QScriptValuePrivate::assignEngine(QScriptEnginePrivate* engine) inline QScriptValuePrivate* QScriptValuePrivate::property(const QString& name, const QScriptValue::ResolveFlags& mode) { + JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(name)); + return property<JSStringRef>(propertyName.get(), mode); +} + +inline QScriptValuePrivate* QScriptValuePrivate::property(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode) +{ + return property<JSStringRef>(*name, mode); +} + +inline QScriptValuePrivate* QScriptValuePrivate::property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode) +{ + return property<quint32>(arrayIndex, mode); +} + +/*! + \internal + This method was created to unify access to the JSObjectGetPropertyAtIndex and the JSObjectGetProperty. +*/ +inline JSValueRef QScriptValuePrivate::property(quint32 property, JSValueRef* exception) +{ + return JSObjectGetPropertyAtIndex(*m_engine, *this, property, exception); +} + +/*! + \internal + This method was created to unify access to the JSObjectGetPropertyAtIndex and the JSObjectGetProperty. +*/ +inline JSValueRef QScriptValuePrivate::property(JSStringRef property, JSValueRef* exception) +{ + return JSObjectGetProperty(*m_engine, *this, property, exception); +} + +/*! + \internal + This method was created to unify acccess to hasOwnProperty, same function for an array index + and a property name access. +*/ +inline bool QScriptValuePrivate::hasOwnProperty(quint32 property) +{ + Q_ASSERT(isObject()); + // FIXME it could be faster, but JSC C API doesn't expose needed functionality. + JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(QString::number(property))); + return hasOwnProperty(propertyName.get()); +} + +/*! + \internal + This method was created to unify acccess to hasOwnProperty, same function for an array index + and a property name access. +*/ +inline bool QScriptValuePrivate::hasOwnProperty(JSStringRef property) +{ + Q_ASSERT(isObject()); + // FIXME it could be faster, but JSC C API doesn't expose needed functionality. + JSRetainPtr<JSStringRef> hasOwnPropertyName(Adopt, JSStringCreateWithUTF8CString("hasOwnProperty")); + JSValueRef exception = 0; + JSValueRef hasOwnProperty = JSObjectGetProperty(*m_engine, *this, hasOwnPropertyName.get(), &exception); + JSValueRef propertyName[] = { JSValueMakeString(*m_engine, property) }; + JSValueRef result = JSObjectCallAsFunction(*m_engine, const_cast<JSObjectRef>(hasOwnProperty), *this, 1, propertyName, &exception); + return exception ? false : JSValueToBoolean(*m_engine, result); +} + +/*! + \internal + This function gets property of an object. + \arg propertyName could be type of quint32 (an array index) or JSStringRef (a property name). +*/ +template<typename T> +inline QScriptValuePrivate* QScriptValuePrivate::property(T propertyName, const QScriptValue::ResolveFlags& mode) +{ if (!isObject()) - return new QScriptValuePrivate; + return new QScriptValuePrivate(); - if (mode & QScriptValue::ResolveLocal) { - qWarning("QScriptValue::property(): ResolveLocal not supported yet."); + if ((mode == QScriptValue::ResolveLocal) && (!hasOwnProperty(propertyName))) + return new QScriptValuePrivate(); + + JSValueRef exception = 0; + JSValueRef value = property(propertyName, &exception); + + if (exception) { + m_engine->setException(exception, QScriptEnginePrivate::NotNullException); + return new QScriptValuePrivate(engine(), exception); + } + if (JSValueIsUndefined(*m_engine, value)) return new QScriptValuePrivate; + return new QScriptValuePrivate(engine(), value); +} + +inline void QScriptValuePrivate::setProperty(const QString& name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags) +{ + JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(name)); + setProperty<JSStringRef>(propertyName.get(), value, flags); +} + +inline void QScriptValuePrivate::setProperty(quint32 arrayIndex, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags) +{ + setProperty<quint32>(arrayIndex, value, flags); +} + +inline void QScriptValuePrivate::setProperty(const QScriptStringPrivate* name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags) +{ + setProperty<JSStringRef>(*name, value, flags); +} + +/*! + \internal + This method was created to unify access to the JSObjectSetPropertyAtIndex and the JSObjectSetProperty. +*/ +inline void QScriptValuePrivate::setProperty(quint32 property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception) +{ + Q_ASSERT(isObject()); + if (flags) { + // FIXME This could be better, but JSC C API doesn't expose needed functionality. It is + // not possible to create / modify a property attribute via an array index. + JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(QString::number(property))); + JSObjectSetProperty(*m_engine, *this, propertyName.get(), value, flags, exception); + return; } + JSObjectSetPropertyAtIndex(*m_engine, *this, property, value, exception); +} - JSRetainPtr<JSStringRef> nameRef(Adopt, QScriptConverter::toString(name)); - QScriptValuePrivate* result = new QScriptValuePrivate(m_engine.constData(), JSObjectGetProperty(*m_engine, *this, nameRef.get(), /* exception */ 0)); +/*! + \internal + This method was created to unify access to the JSObjectSetPropertyAtIndex and the JSObjectSetProperty. +*/ +inline void QScriptValuePrivate::setProperty(JSStringRef property, JSValueRef value, JSPropertyAttributes flags, JSValueRef* exception) +{ + Q_ASSERT(isObject()); + JSObjectSetProperty(*m_engine, *this, property, value, flags, exception); +} - return result; +/*! + \internal + This method was created to unify access to the JSObjectDeleteProperty and a teoretical JSObjectDeletePropertyAtIndex + which doesn't exist now. +*/ +inline void QScriptValuePrivate::deleteProperty(quint32 property, JSValueRef* exception) +{ + // FIXME It could be faster, we need a JSC C API for deleting array index properties. + JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(QString::number(property))); + JSObjectDeleteProperty(*m_engine, *this, propertyName.get(), exception); } -inline QScriptValuePrivate* QScriptValuePrivate::property(quint32 arrayIndex, const QScriptValue::ResolveFlags& mode) +/*! + \internal + This method was created to unify access to the JSObjectDeleteProperty and a teoretical JSObjectDeletePropertyAtIndex. +*/ +inline void QScriptValuePrivate::deleteProperty(JSStringRef property, JSValueRef* exception) +{ + Q_ASSERT(isObject()); + JSObjectDeleteProperty(*m_engine, *this, property, exception); +} + +template<typename T> +inline void QScriptValuePrivate::setProperty(T name, QScriptValuePrivate* value, const QScriptValue::PropertyFlags& flags) { if (!isObject()) - return new QScriptValuePrivate; + return; - if (mode & QScriptValue::ResolveLocal) { - qWarning("QScriptValue::property(): ResolveLocal not supported yet."); - return new QScriptValuePrivate; + if (!value->isJSBased()) + value->assignEngine(engine()); + + JSValueRef exception = 0; + if (!value->isValid()) { + // Remove the property. + deleteProperty(name, &exception); + m_engine->setException(exception); + return; + } + if (m_engine != value->m_engine) { + qWarning("QScriptValue::setProperty() failed: cannot set value created in a different engine"); + return; + } + + setProperty(name, *value, QScriptConverter::toPropertyFlags(flags), &exception); + m_engine->setException(exception); +} + +inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(const QString& name, const QScriptValue::ResolveFlags& mode) +{ + JSRetainPtr<JSStringRef> propertyName(Adopt, QScriptConverter::toString(name)); + return propertyFlags(propertyName.get(), mode); +} + +inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(const QScriptStringPrivate* name, const QScriptValue::ResolveFlags& mode) +{ + return propertyFlags(*name, mode); +} + +inline QScriptValue::PropertyFlags QScriptValuePrivate::propertyFlags(JSStringRef name, const QScriptValue::ResolveFlags& mode) +{ + unsigned flags = 0; + if (!isObject()) + return QScriptValue::PropertyFlags(flags); + + // FIXME It could be faster and nicer, but new JSC C API should be created. + static JSStringRef objectName = QScriptConverter::toString("Object"); + static JSStringRef propertyDescriptorName = QScriptConverter::toString("getOwnPropertyDescriptor"); + + // FIXME This is dangerous if global object was modified (bug 41839). + JSValueRef exception = 0; + JSObjectRef globalObject = JSContextGetGlobalObject(*m_engine); + JSValueRef objectConstructor = JSObjectGetProperty(*m_engine, globalObject, objectName, &exception); + Q_ASSERT(JSValueIsObject(*m_engine, objectConstructor)); + JSValueRef propertyDescriptorGetter = JSObjectGetProperty(*m_engine, const_cast<JSObjectRef>(objectConstructor), propertyDescriptorName, &exception); + Q_ASSERT(JSValueIsObject(*m_engine, propertyDescriptorGetter)); + + JSValueRef arguments[] = { *this, JSValueMakeString(*m_engine, name) }; + JSObjectRef propertyDescriptor + = const_cast<JSObjectRef>(JSObjectCallAsFunction(*m_engine, + const_cast<JSObjectRef>(propertyDescriptorGetter), + /* thisObject */ 0, + /* argumentCount */ 2, + arguments, + &exception)); + if (exception) { + // Invalid property. + return QScriptValue::PropertyFlags(flags); + } + + if (!JSValueIsObject(*m_engine, propertyDescriptor)) { + // Property isn't owned by this object. + JSObjectRef proto; + if (mode == QScriptValue::ResolveLocal + || ((proto = const_cast<JSObjectRef>(JSObjectGetPrototype(*m_engine, *this))) && JSValueIsNull(*m_engine, proto))) { + return QScriptValue::PropertyFlags(flags); + } + QScriptValuePrivate p(engine(), proto); + return p.propertyFlags(name, QScriptValue::ResolvePrototype); } - return new QScriptValuePrivate(m_engine.constData(), JSObjectGetPropertyAtIndex(*m_engine, *this, arrayIndex, /* exception */ 0)); + static JSStringRef writableName = QScriptConverter::toString("writable"); + static JSStringRef configurableName = QScriptConverter::toString("configurable"); + static JSStringRef enumerableName = QScriptConverter::toString("enumerable"); + + bool readOnly = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, writableName, &exception)); + if (!exception && readOnly) + flags |= QScriptValue::ReadOnly; + bool undeletable = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, configurableName, &exception)); + if (!exception && undeletable) + flags |= QScriptValue::Undeletable; + bool skipInEnum = !JSValueToBoolean(*m_engine, JSObjectGetProperty(*m_engine, propertyDescriptor, enumerableName, &exception)); + if (!exception && skipInEnum) + flags |= QScriptValue::SkipInEnumeration; + + return QScriptValue::PropertyFlags(flags); } QScriptValuePrivate* QScriptValuePrivate::call(const QScriptValuePrivate*, const QScriptValueList& args) |