diff options
Diffstat (limited to 'src/script/bridge/qscriptclassobject.cpp')
-rw-r--r-- | src/script/bridge/qscriptclassobject.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/script/bridge/qscriptclassobject.cpp b/src/script/bridge/qscriptclassobject.cpp new file mode 100644 index 0000000..62364f3 --- /dev/null +++ b/src/script/bridge/qscriptclassobject.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qscriptclassobject_p.h" + +#ifndef QT_NO_SCRIPT + +#include "../api/qscriptengine.h" +#include "../api/qscriptengine_p.h" +#include "../api/qscriptclass.h" + +#include "Error.h" + +Q_DECLARE_METATYPE(QScriptContext*) +Q_DECLARE_METATYPE(QScriptValue) +Q_DECLARE_METATYPE(QScriptValueList) + +QT_BEGIN_NAMESPACE + +namespace QScript +{ + +QString qtStringFromJSCUString(const JSC::UString &str); + +ClassObjectDelegate::ClassObjectDelegate(QScriptClass *scriptClass) + : m_scriptClass(scriptClass) +{ +} + +ClassObjectDelegate::~ClassObjectDelegate() +{ +} + +QScriptClass *ClassObjectDelegate::scriptClass() const +{ + return m_scriptClass; +} + +void ClassObjectDelegate::setScriptClass(QScriptClass *scriptClass) +{ + m_scriptClass = scriptClass; +} + +QScriptObjectDelegate::Type ClassObjectDelegate::type() const +{ + return ClassObject; +} + +bool ClassObjectDelegate::getOwnPropertySlot(QScriptObject* object, + JSC::ExecState *exec, + const JSC::Identifier &propertyName, + JSC::PropertySlot &slot) +{ + QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->lexicalGlobalObject())->engine; + QScriptValue scriptObject = engine->scriptValueFromJSCValue(object); + QString name = qtStringFromJSCUString(propertyName.ustring()); + QScriptString scriptName = QScriptEnginePrivate::get(engine)->toStringHandle(name); + uint id = 0; + QScriptClass::QueryFlags flags = m_scriptClass->queryProperty( + scriptObject, scriptName, QScriptClass::HandlesReadAccess, &id); + if (flags & QScriptClass::HandlesReadAccess) { + QScriptValue value = m_scriptClass->property(scriptObject, scriptName, id); + slot.setValue(engine->scriptValueToJSCValue(value)); + return true; + } + return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot); +} + +void ClassObjectDelegate::put(QScriptObject* object, JSC::ExecState *exec, + const JSC::Identifier &propertyName, + JSC::JSValue value, JSC::PutPropertySlot &slot) +{ + QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->lexicalGlobalObject())->engine; + QScriptValue scriptObject = engine->scriptValueFromJSCValue(object); + QString name = qtStringFromJSCUString(propertyName.ustring()); + QScriptString scriptName = QScriptEnginePrivate::get(engine)->toStringHandle(name); + uint id = 0; + QScriptClass::QueryFlags flags = m_scriptClass->queryProperty( + scriptObject, scriptName, QScriptClass::HandlesWriteAccess, &id); + if (flags & QScriptClass::HandlesWriteAccess) { + m_scriptClass->setProperty(scriptObject, scriptName, id, engine->scriptValueFromJSCValue(value)); + return; + } + QScriptObjectDelegate::put(object, exec, propertyName, value, slot); +} + +bool ClassObjectDelegate::deleteProperty(QScriptObject* object, JSC::ExecState *exec, + const JSC::Identifier &propertyName) +{ + // ### avoid duplication of put() + QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->lexicalGlobalObject())->engine; + QScriptValue scriptObject = engine->scriptValueFromJSCValue(object); + QString name = qtStringFromJSCUString(propertyName.ustring()); + QScriptString scriptName = QScriptEnginePrivate::get(engine)->toStringHandle(name); + uint id = 0; + QScriptClass::QueryFlags flags = m_scriptClass->queryProperty( + scriptObject, scriptName, QScriptClass::HandlesWriteAccess, &id); + if (flags & QScriptClass::HandlesWriteAccess) { + if (m_scriptClass->propertyFlags(scriptObject, scriptName, id) & QScriptValue::Undeletable) + return false; + m_scriptClass->setProperty(scriptObject, scriptName, id, QScriptValue()); + return true; + } + return QScriptObjectDelegate::deleteProperty(object, exec, propertyName); +} + +bool ClassObjectDelegate::getPropertyAttributes(const QScriptObject* object, JSC::ExecState *exec, + const JSC::Identifier &propertyName, + unsigned &attribs) const +{ + QScriptEnginePrivate *engine = static_cast<QScript::GlobalObject*>(exec->lexicalGlobalObject())->engine; + QScriptValue scriptObject = engine->scriptValueFromJSCValue(object); + QString name = qtStringFromJSCUString(propertyName.ustring()); + QScriptString scriptName = QScriptEnginePrivate::get(engine)->toStringHandle(name); + uint id = 0; + QScriptClass::QueryFlags flags = m_scriptClass->queryProperty( + scriptObject, scriptName, QScriptClass::HandlesReadAccess, &id); + if (flags & QScriptClass::HandlesReadAccess) { + QScriptValue::PropertyFlags flags = m_scriptClass->propertyFlags(scriptObject, scriptName, id); + attribs = 0; + if (flags & QScriptValue::ReadOnly) + attribs |= JSC::ReadOnly; + if (flags & QScriptValue::SkipInEnumeration) + attribs |= JSC::DontEnum; + if (flags & QScriptValue::Undeletable) + attribs |= JSC::DontDelete; + if (flags & QScriptValue::PropertyGetter) + attribs |= JSC::Getter; + if (flags & QScriptValue::PropertySetter) + attribs |= JSC::Setter; + attribs |= flags & QScriptValue::UserRange; + return true; + } + return QScriptObjectDelegate::getPropertyAttributes(object, exec, propertyName, attribs); +} + +void ClassObjectDelegate::getPropertyNames(QScriptObject* object, JSC::ExecState *exec, + JSC::PropertyNameArray &propertyNames) +{ + qWarning("Enumeration of custom script objects not implemented"); + QScriptObjectDelegate::getPropertyNames(object, exec, propertyNames); +} + +JSC::CallType ClassObjectDelegate::getCallData(QScriptObject*, JSC::CallData &callData) +{ + if (!m_scriptClass->supportsExtension(QScriptClass::Callable)) + return JSC::CallTypeNone; + callData.native.function = call; + return JSC::CallTypeHost; +} + +JSC::JSValue JSC_HOST_CALL ClassObjectDelegate::call(JSC::ExecState *exec, JSC::JSObject *callee, + JSC::JSValue thisValue, const JSC::ArgList &args) +{ + if (!callee->isObject(&QScriptObject::info)) + return JSC::throwError(exec, JSC::TypeError, "callee is not a ClassObject object"); + QScriptObject *obj = static_cast<QScriptObject*>(callee); + QScriptObjectDelegate *delegate = obj->delegate(); + if (!delegate || (delegate->type() != QScriptObjectDelegate::ClassObject)) + return JSC::throwError(exec, JSC::TypeError, "callee is not a ClassObject object"); + QScriptClass *scriptClass = static_cast<ClassObjectDelegate*>(delegate)->scriptClass(); + QScriptEnginePrivate *eng_p = static_cast<QScript::GlobalObject*>(exec->lexicalGlobalObject())->engine; + JSC::ExecState *previousFrame = eng_p->currentFrame; + QScriptContext *ctx = eng_p->contextForFrame(exec); + eng_p->currentFrame = exec; + QScriptValue scriptObject = eng_p->scriptValueFromJSCValue(obj); + QVariant result = scriptClass->extension(QScriptClass::Callable, qVariantFromValue(ctx)); + eng_p->currentFrame = previousFrame; + eng_p->releaseContextForFrame(exec); + return eng_p->jscValueFromVariant(result); +} + +JSC::ConstructType ClassObjectDelegate::getConstructData(QScriptObject*, JSC::ConstructData &constructData) +{ + if (!m_scriptClass->supportsExtension(QScriptClass::Callable)) + return JSC::ConstructTypeNone; + constructData.native.function = construct; + return JSC::ConstructTypeHost; +} + +JSC::JSObject* ClassObjectDelegate::construct(JSC::ExecState *exec, JSC::JSObject *callee, + const JSC::ArgList &args) +{ + Q_ASSERT(callee->isObject(&QScriptObject::info)); + QScriptObject *obj = static_cast<QScriptObject*>(callee); + QScriptObjectDelegate *delegate = obj->delegate(); + QScriptClass *scriptClass = static_cast<ClassObjectDelegate*>(delegate)->scriptClass(); + QScriptEnginePrivate *eng_p = static_cast<QScript::GlobalObject*>(exec->lexicalGlobalObject())->engine; + JSC::ExecState *previousFrame = eng_p->currentFrame; + QScriptContext *ctx = eng_p->contextForFrame(exec); + eng_p->currentFrame = exec; + QScriptValue defaultObject = ctx->thisObject(); + QScriptValue result = qvariant_cast<QScriptValue>(scriptClass->extension(QScriptClass::Callable, qVariantFromValue(ctx))); + if (!result.isObject()) + result = defaultObject; + eng_p->currentFrame = previousFrame; + eng_p->releaseContextForFrame(exec); + return JSC::asObject(eng_p->scriptValueToJSCValue(result)); +} + +bool ClassObjectDelegate::hasInstance(QScriptObject* object, JSC::ExecState *exec, + JSC::JSValue value, JSC::JSValue proto) +{ + if (!scriptClass()->supportsExtension(QScriptClass::HasInstance)) + return QScriptObjectDelegate::hasInstance(object, exec, value, proto); + QScriptValueList args; + QScriptEnginePrivate *eng_p = static_cast<QScript::GlobalObject*>(exec->lexicalGlobalObject())->engine; + args << eng_p->scriptValueFromJSCValue(object) << eng_p->scriptValueFromJSCValue(value); + QVariant result = scriptClass()->extension(QScriptClass::HasInstance, qVariantFromValue(args)); + return result.toBool(); +} + +} // namespace QScript + +QT_END_NAMESPACE + +#endif // QT_NO_SCRIPT |