diff options
Diffstat (limited to 'JavaScriptCore/qt/api')
-rw-r--r-- | JavaScriptCore/qt/api/qscriptconverter_p.h | 14 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptengine_p.cpp | 21 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptengine_p.h | 12 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptstring_p.h | 12 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptvalue.cpp | 112 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptvalue.h | 30 | ||||
-rw-r--r-- | JavaScriptCore/qt/api/qscriptvalue_p.h | 282 |
7 files changed, 467 insertions, 16 deletions
diff --git a/JavaScriptCore/qt/api/qscriptconverter_p.h b/JavaScriptCore/qt/api/qscriptconverter_p.h index cd86e20..0c57d95 100644 --- a/JavaScriptCore/qt/api/qscriptconverter_p.h +++ b/JavaScriptCore/qt/api/qscriptconverter_p.h @@ -20,7 +20,9 @@ #ifndef qscriptconverter_p_h #define qscriptconverter_p_h +#include "qscriptvalue.h" #include <JavaScriptCore/JavaScript.h> +#include <QtCore/qglobal.h> #include <QtCore/qnumeric.h> #include <QtCore/qstring.h> #include <QtCore/qvarlengtharray.h> @@ -127,6 +129,18 @@ public: buf.append(0); return QString::fromLatin1(buf.constData()); } + + static JSPropertyAttributes toPropertyFlags(const QFlags<QScriptValue::PropertyFlag>& flags) + { + JSPropertyAttributes attr = 0; + if (flags.testFlag(QScriptValue::ReadOnly)) + attr |= kJSPropertyAttributeReadOnly; + if (flags.testFlag(QScriptValue::Undeletable)) + attr |= kJSPropertyAttributeDontDelete; + if (flags.testFlag(QScriptValue::SkipInEnumeration)) + attr |= kJSPropertyAttributeDontEnum; + return attr; + } }; #endif // qscriptconverter_p_h diff --git a/JavaScriptCore/qt/api/qscriptengine_p.cpp b/JavaScriptCore/qt/api/qscriptengine_p.cpp index 23e41c4..360de29 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.cpp +++ b/JavaScriptCore/qt/api/qscriptengine_p.cpp @@ -32,11 +32,32 @@ QScriptEnginePrivate::QScriptEnginePrivate(const QScriptEngine* engine) : q_ptr(const_cast<QScriptEngine*>(engine)) , m_context(JSGlobalContextCreate(0)) , m_exception(0) + , m_arrayConstructor(0) + , m_arrayPrototype(0) { + JSObjectRef globalObject = JSContextGetGlobalObject(m_context); + + // Save references to the Array constructor and prototype. + JSRetainPtr<JSStringRef> arrayName(Adopt, JSStringCreateWithUTF8CString("Array")); + JSValueRef arrayConstructor = JSObjectGetProperty(m_context, globalObject, arrayName.get(), /* exception */ 0); + Q_ASSERT(JSValueIsObject(m_context, arrayConstructor)); + m_arrayConstructor = JSValueToObject(m_context, arrayConstructor, /* exception */ 0); + JSValueProtect(m_context, m_arrayConstructor); + + // Note that this is not the [[Prototype]] internal property (which we could + // get via JSObjectGetPrototype), but the Array.prototype, that will be set + // as [[Prototype]] of Array instances. + JSRetainPtr<JSStringRef> prototypeName(Adopt, JSStringCreateWithUTF8CString("prototype")); + JSValueRef arrayPrototype = JSObjectGetProperty(m_context, m_arrayConstructor, prototypeName.get(), /* exception */ 0); + Q_ASSERT(JSValueIsObject(m_context, arrayPrototype)); + m_arrayPrototype = arrayPrototype; + JSValueProtect(m_context, m_arrayPrototype); } QScriptEnginePrivate::~QScriptEnginePrivate() { + JSValueUnprotect(m_context, m_arrayConstructor); + JSValueUnprotect(m_context, m_arrayPrototype); if (m_exception) JSValueUnprotect(m_context, m_exception); JSGlobalContextRelease(m_context); diff --git a/JavaScriptCore/qt/api/qscriptengine_p.h b/JavaScriptCore/qt/api/qscriptengine_p.h index 30ee039..401c051 100644 --- a/JavaScriptCore/qt/api/qscriptengine_p.h +++ b/JavaScriptCore/qt/api/qscriptengine_p.h @@ -77,10 +77,15 @@ public: inline QScriptStringPrivate* toStringHandle(const QString& str) const; inline operator JSGlobalContextRef() const; + + inline bool isArray(JSValueRef value) const; private: QScriptEngine* q_ptr; JSGlobalContextRef m_context; JSValueRef m_exception; + + JSObjectRef m_arrayConstructor; + JSValueRef m_arrayPrototype; }; @@ -211,4 +216,11 @@ QScriptEnginePrivate::operator JSGlobalContextRef() const return m_context; } +bool QScriptEnginePrivate::isArray(JSValueRef value) const +{ + // JSC API doesn't export the [[Class]] information for the builtins. But we know that a value + // is an array if it was created with the Array constructor or if it is the Array.prototype. + return JSValueIsInstanceOfConstructor(m_context, value, m_arrayConstructor, /* exception */ 0) || JSValueIsStrictEqual(m_context, value, m_arrayPrototype); +} + #endif diff --git a/JavaScriptCore/qt/api/qscriptstring_p.h b/JavaScriptCore/qt/api/qscriptstring_p.h index d4fc88e..fe84f4d 100644 --- a/JavaScriptCore/qt/api/qscriptstring_p.h +++ b/JavaScriptCore/qt/api/qscriptstring_p.h @@ -46,6 +46,8 @@ public: inline quint64 id() const; + inline operator JSStringRef() const; + private: JSStringRef m_string; }; @@ -109,4 +111,14 @@ quint64 QScriptStringPrivate::id() const return reinterpret_cast<quint32>(m_string); } +/*! + \internal + This method should be used for invoking JSC functions. + \note This method keeps ownership of an internal JSStringRef. +*/ +QScriptStringPrivate::operator JSStringRef() const +{ + return m_string; +} + #endif // qscriptstring_p_h diff --git a/JavaScriptCore/qt/api/qscriptvalue.cpp b/JavaScriptCore/qt/api/qscriptvalue.cpp index e309fb7..a7d0b7b 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.cpp +++ b/JavaScriptCore/qt/api/qscriptvalue.cpp @@ -313,6 +313,17 @@ bool QScriptValue::isError() const } /*! + Returns true if this QScriptValue is an object of the Array class; + otherwise returns false. + + \sa QScriptEngine::newArray() +*/ +bool QScriptValue::isArray() const +{ + return d_ptr->isArray(); +} + +/*! Returns true if this QScriptValue is of the Object type; otherwise returns false. @@ -651,6 +662,23 @@ QScriptValue QScriptValue::property(const QString& name, const ResolveFlags& mod /*! \overload + Returns the value of this QScriptValue's property with the given \a name, + using the given \a mode to resolve the property. + + This overload of property() is useful when you need to look up the + same property repeatedly, since the lookup can be performed faster + when the name is represented as an interned string. + + \sa QScriptEngine::toStringHandle(), setProperty() +*/ +QScriptValue QScriptValue::property(const QScriptString& name, const ResolveFlags& mode) const +{ + return QScriptValuePrivate::get(d_ptr->property(QScriptStringPrivate::get(name).constData(), mode)); +} + +/*! + \overload + Returns the property at the given \a arrayIndex, using the given \a mode to resolve the property. @@ -665,3 +693,87 @@ QScriptValue QScriptValue::property(quint32 arrayIndex, const ResolveFlags& mode { return QScriptValuePrivate::get(d_ptr->property(arrayIndex, mode)); } + +/*! + Sets the value of this QScriptValue's property with the given \a name to + the given \a value. + + If this QScriptValue is not an object, this function does nothing. + + If this QScriptValue does not already have a property with name \a name, + a new property is created; the given \a flags then specify how this + property may be accessed by script code. + + If \a value is invalid, the property is removed. + + If the property is implemented using a setter function (i.e. has the + PropertySetter flag set), calling setProperty() has side-effects on + the script engine, since the setter function will be called with the + given \a value as argument (possibly resulting in an uncaught script + exception). + + Note that you cannot specify custom getter or setter functions for + built-in properties, such as the \c{length} property of Array objects + or meta properties of QObject objects. + + \sa property() +*/ +void QScriptValue::setProperty(const QString& name, const QScriptValue& value, const PropertyFlags& flags) +{ + d_ptr->setProperty(name, QScriptValuePrivate::get(value), flags); +} + +/*! + \overload + + Sets the property at the given \a arrayIndex to the given \a value. + + This function is provided for convenience and performance when + working with array objects. + + If this QScriptValue is not an Array object, this function behaves + as if setProperty() was called with the string representation of \a + arrayIndex. +*/ +void QScriptValue::setProperty(quint32 arrayIndex, const QScriptValue& value, const PropertyFlags& flags) +{ + d_ptr->setProperty(arrayIndex, QScriptValuePrivate::get(value), flags); +} + +/*! + Sets the value of this QScriptValue's property with the given \a + name to the given \a value. The given \a flags specify how this + property may be accessed by script code. + + This overload of setProperty() is useful when you need to set the + same property repeatedly, since the operation can be performed + faster when the name is represented as an interned string. + + \sa QScriptEngine::toStringHandle() +*/ +void QScriptValue::setProperty(const QScriptString& name, const QScriptValue& value, const PropertyFlags& flags) +{ + d_ptr->setProperty(QScriptStringPrivate::get(name).constData(), QScriptValuePrivate::get(value), flags); +} + +/*! + Returns the flags of the property with the given \a name, using the + given \a mode to resolve the property. + + \sa property() +*/ +QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QString& name, const ResolveFlags& mode) const +{ + return d_ptr->propertyFlags(name, mode); +} + +/*! + Returns the flags of the property with the given \a name, using the + given \a mode to resolve the property. + + \sa property() +*/ +QScriptValue::PropertyFlags QScriptValue::propertyFlags(const QScriptString& name, const ResolveFlags& mode) const +{ + return d_ptr->propertyFlags(QScriptStringPrivate::get(name).constData(), mode); +} diff --git a/JavaScriptCore/qt/api/qscriptvalue.h b/JavaScriptCore/qt/api/qscriptvalue.h index c55d461..991a6a0 100644 --- a/JavaScriptCore/qt/api/qscriptvalue.h +++ b/JavaScriptCore/qt/api/qscriptvalue.h @@ -20,6 +20,7 @@ #ifndef qscriptvalue_h #define qscriptvalue_h +#include "qscriptstring.h" #include <QtCore/qlist.h> #include <QtCore/qshareddata.h> @@ -34,12 +35,25 @@ typedef double qsreal; class QScriptValue { public: enum ResolveFlag { - ResolveLocal = 0x00, - ResolvePrototype = 0x01 + ResolveLocal = 0x00, + ResolvePrototype = 0x01, + ResolveScope = 0x02, + ResolveFull = ResolvePrototype | ResolveScope }; - Q_DECLARE_FLAGS(ResolveFlags, ResolveFlag) + enum PropertyFlag { + ReadOnly = 0x00000001, + Undeletable = 0x00000002, + SkipInEnumeration = 0x00000004, + PropertyGetter = 0x00000008, + PropertySetter = 0x00000010, + QObjectMember = 0x00000020, + KeepExistingFlags = 0x00000800, + UserRange = 0xff000000 // Users may use these as they see fit. + }; + Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag) + enum SpecialValue { NullValue, UndefinedValue @@ -75,8 +89,16 @@ public: bool instanceOf(const QScriptValue& other) const; QScriptValue property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const; + QScriptValue property(const QScriptString& name, const ResolveFlags& mode = ResolvePrototype) const; QScriptValue property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const; + void setProperty(const QString& name, const QScriptValue& value, const PropertyFlags& flags = KeepExistingFlags); + void setProperty(quint32 arrayIndex, const QScriptValue& value, const PropertyFlags& flags = KeepExistingFlags); + void setProperty(const QScriptString& name, const QScriptValue& value, const PropertyFlags& flags = KeepExistingFlags); + + PropertyFlags propertyFlags(const QString& name, const ResolveFlags& mode = ResolvePrototype) const; + PropertyFlags propertyFlags(const QScriptString& name, const ResolveFlags& mode = ResolvePrototype) const; + QScriptEngine* engine() const; bool isValid() const; @@ -89,6 +111,7 @@ public: bool isUndefined() const; bool isObject() const; bool isError() const; + bool isArray() const; QString toString() const; qsreal toNumber() const; @@ -102,7 +125,6 @@ public: QScriptValue call(const QScriptValue& thisObject = QScriptValue(), const QScriptValueList& args = QScriptValueList()); - private: QScriptValue(void*); QScriptValue(QScriptValuePrivate*); 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) |