summaryrefslogtreecommitdiffstats
path: root/Python/sysmodule.c
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2014-10-30 21:50:46 (GMT)
committerGeorg Brandl <georg@python.org>2014-10-30 21:50:46 (GMT)
commit884217cb60111cb9fadaed5acb3781690a4637ad (patch)
treeb3f58e46d6888dca9f7e6cfaf4e50955f58b50d1 /Python/sysmodule.c
parent3b4cf554e58d219958fadbf6555d94b1805173f5 (diff)
downloadcpython-884217cb60111cb9fadaed5acb3781690a4637ad.zip
cpython-884217cb60111cb9fadaed5acb3781690a4637ad.tar.gz
cpython-884217cb60111cb9fadaed5acb3781690a4637ad.tar.bz2
distutils example: fix invalid rst in description string
Diffstat (limited to 'Python/sysmodule.c')
0 files changed, 0 insertions, 0 deletions
0; + return static_cast(delegate)->object(); +} + +QScriptDeclarativeClass::~QScriptDeclarativeClass() +{ +} + +QScriptEngine *QScriptDeclarativeClass::engine() const +{ + return d_ptr->engine; +} + +/* +QScriptDeclarativeClass::PersistentIdentifier * +QScriptDeclarativeClass::createPersistentIdentifier(const QString &str) +{ + QScriptEnginePrivate *p = + static_cast(QObjectPrivate::get(d_ptr->engine)); + JSC::ExecState* exec = p->currentFrame; + + PersistentIdentifierPrivate *rv = new PersistentIdentifierPrivate; + rv->identifierValue = JSC::Identifier(exec, (UChar *)str.constData(), str.size()); + rv->identifier = (void *)rv->identifierValue.ustring().rep(); + return rv; +} + +QScriptDeclarativeClass::PersistentIdentifier * +QScriptDeclarativeClass::createPersistentIdentifier(const Identifier &id) +{ + QScriptEnginePrivate *p = + static_cast(QObjectPrivate::get(d_ptr->engine)); + JSC::ExecState* exec = p->currentFrame; + + PersistentIdentifierPrivate *rv = new PersistentIdentifierPrivate; + rv->identifierValue = JSC::Identifier(exec, (JSC::UString::Rep *)id); + rv->identifier = (void *)rv->identifierValue.ustring().rep(); + return rv; +} +*/ + + +QString QScriptDeclarativeClass::toString(const Identifier &identifier) +{ + JSC::UString::Rep *r = (JSC::UString::Rep *)identifier; + return QString((QChar *)r->data(), r->size()); +} + +QScriptClass::QueryFlags +QScriptDeclarativeClass::queryProperty(const Object &object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(flags); + return 0; +} + +QScriptValue QScriptDeclarativeClass::property(const Object &object, const Identifier &name) +{ + Q_UNUSED(object); + Q_UNUSED(name); + return QScriptValue(); +} + +void QScriptDeclarativeClass::setProperty(const Object &object, const Identifier &name, + const QScriptValue &value) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(value); +} + +QScriptValue::PropertyFlags +QScriptDeclarativeClass::propertyFlags(const Object &object, const Identifier &name) +{ + Q_UNUSED(object); + Q_UNUSED(name); + return 0; +} + +QStringList QScriptDeclarativeClass::propertyNames(const Object &object) +{ + Q_UNUSED(object); + return QStringList(); +} + +void QScriptDeclarativeClass::destroyed(const Object &object) +{ + Q_UNUSED(object); +} + diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h new file mode 100644 index 0000000..5705a51 --- /dev/null +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTDECLARATIVECLASS_P_H +#define QSCRIPTDECLARATIVECLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QScriptDeclarativeClassPrivate; +class PersistentIdentifierPrivate; +class Q_SCRIPT_EXPORT QScriptDeclarativeClass +{ +public: + typedef void* Identifier; + typedef void* Object; + + static QScriptValue newObject(QScriptEngine *, QScriptDeclarativeClass *, Object); + static QScriptDeclarativeClass *scriptClass(const QScriptValue &); + static Object object(const QScriptValue &); + + template + class PersistentIdentifier : public T { + public: + Identifier identifier; + + ~PersistentIdentifier() { QScriptDeclarativeClass::destroyPersistentIdentifier(&d); } + private: + friend class QScriptDeclarativeClass; + PersistentIdentifier() : identifier(0), d(0) {} + void *d; + }; + + QScriptDeclarativeClass(QScriptEngine *engine); + virtual ~QScriptDeclarativeClass(); + + QScriptEngine *engine() const; + + template + PersistentIdentifier *createPersistentIdentifier(const QString &str) { + PersistentIdentifier *rv = new PersistentIdentifier; + initPersistentIdentifier(&rv->d, &rv->identifier, str); + return rv; + } + template + PersistentIdentifier *createPersistentIdentifier(const Identifier &id) { + PersistentIdentifier *rv = new PersistentIdentifier; + initPersistentIdentifier(&rv->d, &rv->identifier, id); + return rv; + } + + QString toString(const Identifier &); + + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + virtual QScriptValue::PropertyFlags propertyFlags(const Object &, const Identifier &); + + virtual QStringList propertyNames(const Object &); + + virtual void destroyed(const Object &); + + static void destroyPersistentIdentifier(void **); + void initPersistentIdentifier(void **, Identifier *, const QString &); + void initPersistentIdentifier(void **, Identifier *, const Identifier &); + +protected: + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/script/bridge/qscriptdeclarativeobject.cpp b/src/script/bridge/qscriptdeclarativeobject.cpp new file mode 100644 index 0000000..62c2686 --- /dev/null +++ b/src/script/bridge/qscriptdeclarativeobject.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "config.h" +#include "qscriptdeclarativeobject_p.h" + +#include "../api/qscriptengine.h" +#include "../api/qscriptengine_p.h" +#include "../api/qscriptcontext.h" +#include "../api/qscriptcontext_p.h" +#include "../api/qscriptclass.h" +#include "../api/qscriptclasspropertyiterator.h" + +#include "Error.h" +#include "PropertyNameArray.h" + +#include + +Q_DECLARE_METATYPE(QScriptContext*) +Q_DECLARE_METATYPE(QScriptValue) +Q_DECLARE_METATYPE(QScriptValueList) + +QT_BEGIN_NAMESPACE + +namespace QScript +{ + +DeclarativeObjectDelegate::DeclarativeObjectDelegate(QScriptDeclarativeClass *c, + QScriptDeclarativeClass::Object &o) +: m_class(c), m_object(o) +{ +} + +DeclarativeObjectDelegate::~DeclarativeObjectDelegate() +{ + m_class->destroyed(m_object); +} + +QScriptObjectDelegate::Type DeclarativeObjectDelegate::type() const +{ + return DeclarativeClassObject; +} + +bool DeclarativeObjectDelegate::getOwnPropertySlot(QScriptObject* object, + JSC::ExecState *exec, + const JSC::Identifier &propertyName, + JSC::PropertySlot &slot) +{ + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); + + QScriptClass::QueryFlags flags = + m_class->queryProperty(m_object, identifier, QScriptClass::HandlesReadAccess); + if (flags & QScriptClass::HandlesReadAccess) { + QScriptValue value = m_class->property(m_object, identifier); + slot.setValue(engine->scriptValueToJSCValue(value)); + return true; + } + + return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot); +} + +void DeclarativeObjectDelegate::put(QScriptObject* object, JSC::ExecState *exec, + const JSC::Identifier &propertyName, + JSC::JSValue value, JSC::PutPropertySlot &slot) +{ + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); + + QScriptClass::QueryFlags flags = + m_class->queryProperty(m_object, identifier, QScriptClass::HandlesWriteAccess); + if (flags & QScriptClass::HandlesWriteAccess) { + m_class->setProperty(m_object, identifier, engine->scriptValueFromJSCValue(value)); + return; + } + QScriptObjectDelegate::put(object, exec, propertyName, value, slot); +} + +bool DeclarativeObjectDelegate::deleteProperty(QScriptObject* object, JSC::ExecState *exec, + const JSC::Identifier &propertyName, + bool checkDontDelete) +{ + return QScriptObjectDelegate::deleteProperty(object, exec, propertyName, checkDontDelete); +} + +bool DeclarativeObjectDelegate::getPropertyAttributes(const QScriptObject* object, + JSC::ExecState *exec, + const JSC::Identifier &propertyName, + unsigned &attribs) const +{ + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); + + QScriptClass::QueryFlags flags = + m_class->queryProperty(m_object, identifier, QScriptClass::HandlesReadAccess); + if (flags & QScriptClass::HandlesReadAccess) { + QScriptValue::PropertyFlags flags = m_class->propertyFlags(m_object, identifier); + 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 DeclarativeObjectDelegate::getPropertyNames(QScriptObject* object, JSC::ExecState *exec, + JSC::PropertyNameArray &propertyNames, + unsigned listedAttributes) +{ + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + + QStringList properties = m_class->propertyNames(m_object); + for (int ii = 0; ii < properties.count(); ++ii) { + const QString &name = properties.at(ii); + propertyNames.add(JSC::Identifier(exec, name)); + } + + QScriptObjectDelegate::getPropertyNames(object, exec, propertyNames, listedAttributes); +} + +JSC::CallType DeclarativeObjectDelegate::getCallData(QScriptObject *object, JSC::CallData &callData) +{ + return QScriptObjectDelegate::getCallData(object, callData); +} + +JSC::ConstructType DeclarativeObjectDelegate::getConstructData(QScriptObject* object, JSC::ConstructData &constructData) +{ + return QScriptObjectDelegate::getConstructData(object, constructData); +} + +bool DeclarativeObjectDelegate::hasInstance(QScriptObject* object, JSC::ExecState *exec, + JSC::JSValue value, JSC::JSValue proto) +{ + return QScriptObjectDelegate::hasInstance(object, exec, value, proto); +} + +} // namespace QScript + +QT_END_NAMESPACE diff --git a/src/script/bridge/qscriptdeclarativeobject_p.h b/src/script/bridge/qscriptdeclarativeobject_p.h new file mode 100644 index 0000000..87375d8 --- /dev/null +++ b/src/script/bridge/qscriptdeclarativeobject_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTDECLARATIVEOBJECT_P_H +#define QSCRIPTDECLARATIVEOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include "qscriptobject_p.h" +#include "qscriptdeclarativeclass_p.h" + +QT_BEGIN_NAMESPACE + +class QScriptClass; + +namespace QScript +{ + +class DeclarativeObjectDelegate : public QScriptObjectDelegate +{ +public: + DeclarativeObjectDelegate(QScriptDeclarativeClass *c, QScriptDeclarativeClass::Object &o); + ~DeclarativeObjectDelegate(); + + virtual Type type() const; + + QScriptDeclarativeClass *scriptClass() const { return m_class; } + QScriptDeclarativeClass::Object object() const { return m_object; } + + virtual bool getOwnPropertySlot(QScriptObject*, JSC::ExecState*, + const JSC::Identifier& propertyName, + JSC::PropertySlot&); + virtual void put(QScriptObject*, JSC::ExecState* exec, + const JSC::Identifier& propertyName, + JSC::JSValue, JSC::PutPropertySlot&); + virtual bool deleteProperty(QScriptObject*, JSC::ExecState*, + const JSC::Identifier& propertyName, + bool checkDontDelete = true); + virtual bool getPropertyAttributes(const QScriptObject*, JSC::ExecState*, + const JSC::Identifier&, + unsigned&) const; + virtual void getPropertyNames(QScriptObject*, JSC::ExecState*, + JSC::PropertyNameArray&, + unsigned listedAttributes = JSC::Structure::Prototype); + + virtual JSC::CallType getCallData(QScriptObject*, JSC::CallData&); + virtual JSC::ConstructType getConstructData(QScriptObject*, JSC::ConstructData&); + + virtual bool hasInstance(QScriptObject*, JSC::ExecState*, + JSC::JSValue value, JSC::JSValue proto); + +private: + QScriptDeclarativeClass *m_class; + QScriptDeclarativeClass::Object m_object; +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif diff --git a/src/script/bridge/qscriptobject_p.h b/src/script/bridge/qscriptobject_p.h index c1cee31..a5858ac 100644 --- a/src/script/bridge/qscriptobject_p.h +++ b/src/script/bridge/qscriptobject_p.h @@ -127,7 +127,8 @@ public: enum Type { QtObject, Variant, - ClassObject + ClassObject, + DeclarativeClassObject }; QScriptObjectDelegate(); -- cgit v0.12 From f9f878ca1fff08b6ea24507a84adfeb16d8938b6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 28 Sep 2009 18:51:54 +1000 Subject: Add two step compile/evaluate support to QScript --- src/script/api/qscriptengine.cpp | 173 +++++++++++++++++++++++++++++++++++++++ src/script/api/qscriptengine.h | 26 ++++++ 2 files changed, 199 insertions(+) diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index fb14940..7256f27 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -340,6 +340,24 @@ public: JSC::JSValue prototype; }; +class QScriptProgramPrivate +{ +public: + QScriptProgramPrivate() : refcount(1), hasException(false) { } + + void addref() { ++refcount; } + void release() { if (--refcount) delete this; } + + int refcount; + + bool hasException; + QScriptValue exception; + + JSC::SourceCode source; + WTF::RefPtr evalNode; +}; + + namespace QScript { @@ -2114,7 +2132,112 @@ QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &progra return QScriptSyntaxCheckResult(p); } +QScriptProgram QScriptEngine::compile(const QString &program, const QString &fileName, int lineNumber) +{ + Q_D(QScriptEngine); + + QScriptProgram rv; + rv.d = new QScriptProgramPrivate; + + JSC::JSLock lock(false); // ### hmmm + QBoolBlocker inEval(d->inEval, true); + currentContext()->activationObject(); //force the creation of a context for native function; + + JSC::UString jscProgram = program; + JSC::UString jscFileName = fileName; + JSC::ExecState* exec = d->currentFrame; + + JSC::SourceCode &source = rv.d->source; + source = JSC::makeSource(jscProgram, jscFileName, lineNumber); + + intptr_t sourceId = source.provider()->asID(); + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + if (debugger) + debugger->evaluateStart(sourceId); + + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + int errorLine; + JSC::UString errorMessage; + WTF::RefPtr &evalNode = rv.d->evalNode; + evalNode = exec->globalData().parser->parse(exec, exec->dynamicGlobalObject()->debugger(), source, &errorLine, &errorMessage); + if (!evalNode) { + JSC::JSValue exceptionValue = JSC::Error::create(exec, JSC::SyntaxError, errorMessage, errorLine, source.provider()->asID(), 0); + exec->setException(exceptionValue); + + if (debugger) { + debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, exceptionValue), sourceId, false); + debugger->evaluateStop(exceptionValue, sourceId); + } + + rv.d->hasException = true; + rv.d->exception = d->scriptValueFromJSCValue(exceptionValue); + } else if (debugger) { + debugger->evaluateStop(JSC::JSValue(), sourceId); + } + + return rv; +} + +QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) +{ + Q_D(QScriptEngine); + + if (0 == program.d) + return QScriptValue(); + else if (program.d->hasException) + return program.d->exception; + else if (!program.d->evalNode) + return QScriptValue(); + + JSC::JSLock lock(false); // ### hmmm + QBoolBlocker inEval(d->inEval, true); + currentContext()->activationObject(); //force the creation of a context for native function; + + JSC::ExecState* exec = d->currentFrame; + + intptr_t sourceId = program.d->source.provider()->asID(); + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + if (debugger) + debugger->evaluateStart(sourceId); + + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + WTF::RefPtr &evalNode = program.d->evalNode; + + JSC::JSValue thisValue = d->thisForContext(exec); + JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); + JSC::JSValue exceptionValue; + d->timeoutChecker()->setShouldAbort(false); + JSC::JSValue result = exec->interpreter()->execute(evalNode.get(), exec, thisObject, exec->scopeChain(), &exceptionValue); + + if (d->timeoutChecker()->shouldAbort()) { + if (d->abortResult.isError()) + exec->setException(d->scriptValueToJSCValue(d->abortResult)); + if (debugger) + debugger->evaluateStop(d->scriptValueToJSCValue(d->abortResult), sourceId); + + return d->abortResult; + } + + if (exceptionValue) { + exec->setException(exceptionValue); + + if (debugger) + debugger->evaluateStop(exceptionValue, sourceId); + + return d->scriptValueFromJSCValue(exceptionValue); + } + + if (debugger) + debugger->evaluateStop(result, sourceId); + + Q_ASSERT(!exec->hadException()); + return d->scriptValueFromJSCValue(result); +} /*! Evaluates \a program, using \a lineNumber as the base line number, @@ -3708,6 +3831,9 @@ QScriptValue QScriptEngine::objectById(qint64 id) const return const_cast(d)->scriptValueFromJSCValue((JSC::JSCell*)id); } + + + /*! \since 4.5 \class QScriptSyntaxCheckResult @@ -3836,4 +3962,51 @@ Q_AUTOTEST_EXPORT bool qt_script_isJITEnabled() } #endif +QScriptProgram::QScriptProgram() +: d(0) +{ +} + +QScriptProgram::~QScriptProgram() +{ + if (d) d->release(); +} + +QScriptProgram::QScriptProgram(const QScriptProgram &c) +: d(c.d) +{ + if (d) d->addref(); +} + +QScriptProgram &QScriptProgram::operator=(const QScriptProgram &c) +{ + if (c.d) c.d->addref(); + if (d) d->release(); + d = c.d; + return *this; +} + +bool QScriptProgram::isNull() const +{ + return d == 0; +} + +bool QScriptProgram::hasSyntaxError() const +{ + if (d) return d->hasException; + else return false; +} + +QScriptValue QScriptProgram::syntaxError() const +{ + if (d) return d->exception; + else return QScriptValue(); +} + +QString QScriptProgram::programSource() const +{ + if (d) return d->source.toString(); + else return QString(); +} + QT_END_NAMESPACE diff --git a/src/script/api/qscriptengine.h b/src/script/api/qscriptengine.h index 701f9c6..71266cc 100644 --- a/src/script/api/qscriptengine.h +++ b/src/script/api/qscriptengine.h @@ -120,6 +120,29 @@ private: friend class QScriptEnginePrivate; }; +class QScriptProgramPrivate; +class Q_SCRIPT_EXPORT QScriptProgram +{ +public: + QScriptProgram(); + QScriptProgram(const QScriptProgram &); + ~QScriptProgram(); + + QScriptProgram &operator=(const QScriptProgram &); + + bool isNull() const; + + bool hasSyntaxError() const; + QScriptValue syntaxError() const; + + QString programSource() const; + +private: + friend class QScriptEngine; + QScriptProgramPrivate *d; +}; + +class QScriptCode; class Q_SCRIPT_EXPORT QScriptEngine #ifndef QT_NO_QOBJECT : public QObject @@ -164,6 +187,9 @@ public: bool canEvaluate(const QString &program) const; static QScriptSyntaxCheckResult checkSyntax(const QString &program); + QScriptProgram compile(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + QScriptValue evaluate(const QScriptProgram &); + QScriptValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); bool isEvaluating() const; -- cgit v0.12 From 061c85a17ecb303676b548e6daef6e64967ca1e7 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 28 Sep 2009 21:21:25 +1000 Subject: Use QScriptProgram to speed up binding creation --- src/declarative/qml/qmlcompileddata.cpp | 2 ++ src/declarative/qml/qmlcompiler.cpp | 3 +++ src/declarative/qml/qmlcompiler_p.h | 6 +++--- src/declarative/qml/qmlexpression.cpp | 21 ++++++++++++++++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp index b2e2d40..a46d893 100644 --- a/src/declarative/qml/qmlcompileddata.cpp +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -159,6 +159,8 @@ QmlCompiledData::~QmlCompiledData() if (types.at(ii).ref) types.at(ii).ref->release(); } + + qDeleteAll(programs); } QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt, const QBitField &bindings) const diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 02cd813..e67f79a 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -2296,7 +2296,10 @@ bool QmlCompiler::completeComponentBuild() expression = rewriteBinding(expression); quint32 length = expression.length(); + quint32 pc = output->programs.length(); + output->programs.append(0); binding.compiledData = + QByteArray((const char *)&pc, sizeof(quint32)) + QByteArray((const char *)&length, sizeof(quint32)) + QByteArray((const char *)expression.constData(), expression.length() * sizeof(QChar)); diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 00637e3..447c421 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -69,6 +69,7 @@ class QmlEngine; class QmlComponent; class QmlContext; +class QScriptProgram; class QmlCompiledData : public QmlRefCount { public: @@ -106,6 +107,7 @@ public: QList datas; QList locations; QList bytecode; + QList programs; void dumpInstructions(); private: @@ -253,12 +255,10 @@ private: struct ComponentCompileState { ComponentCompileState() - : parserStatusCount(0), savedObjects(0), - pushedProperties(0), root(0) {} + : parserStatusCount(0), pushedProperties(0), root(0) {} QHash ids; QHash idIndexes; int parserStatusCount; - int savedObjects; int pushedProperties; QHash bindings; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index db9d39f..adf5261 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -45,6 +45,7 @@ #include "qmlcontext_p.h" #include "qmlrewrite_p.h" #include "QtCore/qdebug.h" +#include "qmlcompiler_p.h" Q_DECLARE_METATYPE(QList); @@ -74,8 +75,26 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, if (*data == BasicScriptEngineData) { sse.load((const char *)(data + 1), rc); } else { - expression = QString::fromRawData((QChar *)(data + 2), data[1]); + QmlCompiledData *dd = (QmlCompiledData *)rc; + expressionRewritten = true; + expression = QString::fromRawData((QChar *)(data + 3), data[2]); + + int progIdx = *(data + 1); + QmlEngine *engine = ctxt->engine(); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + if (!dd->programs.at(progIdx)) { + dd->programs[progIdx] = new QScriptProgram(scriptEngine->compile(expression)); + } + + QmlContextPrivate *ctxtPriv = ctxt->d_func(); + QScriptContext *scriptContext = scriptEngine->pushContext(); + for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) + scriptContext->pushScope(ctxtPriv->scopeChain.at(i)); + + expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]); + expressionFunctionValid = true; + scriptEngine->popContext(); } QmlAbstractExpression::setContext(ctxt); -- cgit v0.12 From c4190288ca68eca9b84ccab67d860517a6a8e7c5 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 29 Sep 2009 21:50:31 +1000 Subject: Use placement new correctly --- src/script/bridge/qscriptdeclarativeclass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index 47b693f..c753379 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -70,8 +70,8 @@ void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, static_cast(QObjectPrivate::get(d_ptr->engine)); JSC::ExecState* exec = p->currentFrame; - new (*d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); - *i = (Identifier)((JSC::Identifier *)*d)->ustring().rep(); + new (d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); + *i = (Identifier)((JSC::Identifier *)d)->ustring().rep(); } void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, const Identifier &id) @@ -80,7 +80,7 @@ void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, static_cast(QObjectPrivate::get(d_ptr->engine)); JSC::ExecState* exec = p->currentFrame; - new (*d) JSC::Identifier(exec, (JSC::UString::Rep *)id); + new (d) JSC::Identifier(exec, (JSC::UString::Rep *)id); *i = id; } -- cgit v0.12 From 49527e854a9edb0a92e64264d6efac6be46cf0ed Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 30 Sep 2009 11:07:07 +1000 Subject: Create a property cache for synthesized metaobjects --- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlcompileddata.cpp | 3 + src/declarative/qml/qmlcompiler.cpp | 6 +- src/declarative/qml/qmlcompiler_p.h | 3 + src/declarative/qml/qmldeclarativedata_p.h | 3 + src/declarative/qml/qmlengine.cpp | 14 ++- src/declarative/qml/qmlengine_p.h | 18 +++- src/declarative/qml/qmlinstruction.cpp | 2 +- src/declarative/qml/qmlinstruction_p.h | 2 +- src/declarative/qml/qmlmetaproperty.cpp | 71 +++------------ src/declarative/qml/qmlmetaproperty_p.h | 22 ----- src/declarative/qml/qmlpropertycache.cpp | 137 +++++++++++++++++++++++++++++ src/declarative/qml/qmlpropertycache_p.h | 100 +++++++++++++++++++++ src/declarative/qml/qmlvme.cpp | 9 +- 14 files changed, 303 insertions(+), 93 deletions(-) create mode 100644 src/declarative/qml/qmlpropertycache.cpp create mode 100644 src/declarative/qml/qmlpropertycache_p.h diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 8349e29..216adb1 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -34,7 +34,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlxmlhttprequest.cpp \ qml/qmlsqldatabase.cpp \ qml/qmetaobjectbuilder.cpp \ - qml/qmlwatcher.cpp + qml/qmlwatcher.cpp \ + qml/qmlpropertycache.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -86,7 +87,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlxmlhttprequest_p.h \ qml/qmlsqldatabase_p.h \ qml/qmetaobjectbuilder_p.h \ - qml/qmlwatcher_p.h + qml/qmlwatcher_p.h \ + qml/qmlpropertycache_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp index a46d893..a603d4e 100644 --- a/src/declarative/qml/qmlcompileddata.cpp +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -160,6 +160,9 @@ QmlCompiledData::~QmlCompiledData() types.at(ii).ref->release(); } + for (int ii = 0; ii < propertyCaches.count(); ++ii) + propertyCaches.at(ii)->release(); + qDeleteAll(programs); } diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index e67f79a..0b4ac20 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -647,7 +647,7 @@ void QmlCompiler::compileTree(Object *tree) Q_ASSERT(tree->metatype); static_cast(output->root) = *tree->metaObject(); - if (!tree->metadata.isEmpty()) + if (!tree->metadata.isEmpty()) QmlEnginePrivate::get(engine)->registerCompositeType(output); } @@ -807,7 +807,9 @@ void QmlCompiler::genObject(QmlParser::Object *obj) meta.line = -1; meta.storeMeta.data = output->indexForByteArray(obj->metadata); meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); - meta.storeMeta.slotData = -1; + meta.storeMeta.propertyCache = output->propertyCaches.count(); + // ### Surely the creation of this property cache could be more efficient + output->propertyCaches << QmlPropertyCache::create(engine, obj->metaObject()); output->bytecode << meta; } diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 447c421..677aba7 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -62,6 +62,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -99,6 +100,7 @@ public: int index; int type; }; + QAbstractDynamicMetaObject root; QList primitives; QList floatData; @@ -108,6 +110,7 @@ public: QList locations; QList bytecode; QList programs; + QList propertyCaches; void dumpInstructions(); private: diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h index ade961f..b4c87b8 100644 --- a/src/declarative/qml/qmldeclarativedata_p.h +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE class QmlCompiledData; class QmlAbstractBinding; class QmlContext; +class QmlPropertyCache; class QmlDeclarativeData : public QDeclarativeData { public: @@ -85,6 +86,8 @@ public: QHash *attachedProperties; + QmlPropertyCache *propertyCache; + static QmlDeclarativeData *get(const QObject *object, bool create = false) { QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 72603ed..757670b 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -41,11 +41,12 @@ #undef QT3_SUPPORT // don't want it here - it just causes bugs (which is why we removed it) -#include +#include #include #include #include #include +#include #ifdef QT_SCRIPTTOOLS_LIB #include @@ -192,6 +193,8 @@ QmlEnginePrivate::~QmlEnginePrivate() contextClass = 0; delete objectClass; objectClass = 0; + delete objectClass2; + objectClass2 = 0; delete valueTypeClass; valueTypeClass = 0; delete typeNameClass; @@ -211,6 +214,9 @@ QmlEnginePrivate::~QmlEnginePrivate() clear(parserStatus[ii]); for(QHash::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter) (*iter)->release(); + for(QHash::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) + (*iter)->release(); + } void QmlEnginePrivate::clear(SimpleList &bvs) @@ -236,6 +242,7 @@ void QmlEnginePrivate::init() scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); + objectClass2 = new QScriptDeclarativeClass(&scriptEngine); valueTypeClass = new QmlValueTypeScriptClass(q); typeNameClass = new QmlTypeNameScriptClass(q); rootContext = new QmlContext(q,true); @@ -700,7 +707,7 @@ QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool cre QmlDeclarativeData::QmlDeclarativeData(QmlContext *ctxt) : context(ctxt), bindings(0), bindingBitsSize(0), bindingBits(0), outerContext(0), lineNumber(0), columnNumber(0), deferredComponent(0), - deferredIdx(0), attachedProperties(0) + deferredIdx(0), attachedProperties(0), propertyCache(0) { } @@ -725,6 +732,9 @@ void QmlDeclarativeData::destroyed(QObject *object) if (bindingBits) free(bindingBits); + if (propertyCache) + propertyCache->release(); + delete this; } diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 74e24d4..68019e2 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -72,6 +72,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -88,6 +89,7 @@ class QScriptEngineDebugger; class QNetworkReply; class QNetworkAccessManager; class QmlAbstractBinding; +class QScriptDeclarativeClass; class QmlEnginePrivate : public QObjectPrivate { @@ -149,6 +151,7 @@ public: } resolveData; QmlContextScriptClass *contextClass; QmlObjectScriptClass *objectClass; + QScriptDeclarativeClass *objectClass2; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; // Used by DOM Core 3 API @@ -212,10 +215,17 @@ public: // ### Fixme typedef QHash, bool> FunctionCache; FunctionCache functionCache; - QHash propertyCache; - static QmlMetaObjectCache *cache(QmlEnginePrivate *priv, QObject *obj) { - if (!priv || !obj || QObjectPrivate::get(obj)->metaObject) return 0; - return &priv->propertyCache[obj->metaObject()]; + QHash propertyCache; + QmlPropertyCache *cache(QObject *obj) { + Q_Q(QmlEngine); + if (!obj || QObjectPrivate::get(obj)->metaObject) return 0; + const QMetaObject *mo = obj->metaObject(); + QmlPropertyCache *rv = propertyCache.value(mo); + if (!rv) { + rv = QmlPropertyCache::create(q, mo); + propertyCache.insert(mo, rv); + } + return rv; } struct Imports { diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index b71c6e3..18439f4 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -69,7 +69,7 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx) qWarning() << idx << "\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; break; case QmlInstruction::StoreMetaObject: - qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data << "\t" << instr->storeMeta.slotData; + qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data << "\t"; break; case QmlInstruction::StoreFloat: qWarning() << idx << "\t" << line << "\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 2c9ceac..e62bfdf 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -175,8 +175,8 @@ public: } create; struct { int data; - int slotData; int aliasData; + int propertyCache; } storeMeta; struct { int value; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index efc4a2b..f7882dc 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -58,56 +58,6 @@ Q_DECLARE_METATYPE(QList); QT_BEGIN_NAMESPACE -QmlMetaObjectCache::QmlMetaObjectCache() -: propertyCache(0) -{ -} - -void QmlMetaObjectCache::init(const QMetaObject *metaObject) -{ - if (propertyCache || !metaObject) - return; - - int propCount = metaObject->propertyCount(); - - propertyCache = new Data[propCount]; - for (int ii = 0; ii < propCount; ++ii) { - QMetaProperty p = metaObject->property(ii); - propertyCache[ii].propType = p.userType(); - propertyCache[ii].coreIndex = ii; - propertyCache[ii].name = QLatin1String(p.name()); - - propertyNameCache.insert(propertyCache[ii].name, ii); - } -} - -QmlMetaObjectCache::~QmlMetaObjectCache() -{ - delete [] propertyCache; -} - -QmlMetaObjectCache::Data * -QmlMetaObjectCache::property(int index, const QMetaObject *metaObject) -{ - init(metaObject); - - return propertyCache + index; -} - -QmlMetaObjectCache::Data * -QmlMetaObjectCache::property(const QString &name, const QMetaObject *metaObject) -{ - init(metaObject); - - QHash::ConstIterator iter = propertyNameCache.find(name); - - if (iter != propertyNameCache.end()) { - return propertyCache + *iter; - } else { - return 0; - } -} - /*! \class QmlMetaProperty \brief The QmlMetaProperty class abstracts accessing QML properties. @@ -258,11 +208,17 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) } // Property - QmlMetaObjectCache *cache = QmlEnginePrivate::cache(enginePrivate, obj); + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) + cache = enginePrivate?enginePrivate->cache(obj):0; + if (cache) { - QmlMetaObjectCache::Data *data = - cache->property(name, obj->metaObject()); - if (data) { + QmlPropertyCache::Data *data = cache->property(name); + + if (data && !data->isFunction) { type = QmlMetaProperty::Property; propType = data->propType; coreIdx = data->coreIndex; @@ -272,7 +228,7 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) QMetaProperty p = QmlMetaType::property(obj, name.toUtf8().constData()); propType = p.userType(); coreIdx = p.propertyIndex(); - if (p.name()) + if (p.name()) type = QmlMetaProperty::Property; } } @@ -1186,13 +1142,12 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) } else if (d->type & Property) { - QmlMetaObjectCache *cache = QmlEnginePrivate::cache(enginePrivate, obj); + QmlPropertyCache *cache = enginePrivate?enginePrivate->cache(obj):0; d->coreIdx = id; if (cache) { - QmlMetaObjectCache::Data *data = - cache->property(id, obj->metaObject()); + QmlPropertyCache::Data *data = cache->property(id); d->propType = data->propType; d->name = data->name; } else { diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 1ccf913..0d96174 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -58,28 +58,6 @@ QT_BEGIN_NAMESPACE -class QmlMetaObjectCache -{ -public: - QmlMetaObjectCache(); - ~QmlMetaObjectCache(); - - struct Data { - int propType; - int coreIndex; - QString name; - }; - - Data *property(const QString &, const QMetaObject *); - Data *property(int, const QMetaObject *); - -private: - void init(const QMetaObject *); - - Data *propertyCache; - QHash propertyNameCache; -}; - class QmlContext; class QmlMetaPropertyPrivate { diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp new file mode 100644 index 0000000..f88b3a3 --- /dev/null +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertycache_p.h" +#include "qmlengine_p.h" + +QmlPropertyCache::QmlPropertyCache() +{ +} + +QmlPropertyCache::~QmlPropertyCache() +{ + for (int ii = 0; ii < indexCache.count(); ++ii) + indexCache.at(ii)->release(); + + for (StringCache::ConstIterator iter = stringCache.begin(); + iter != stringCache.end(); ++iter) + (*iter)->release(); + + for (IdentifierCache::ConstIterator iter = identifierCache.begin(); + iter != identifierCache.end(); ++iter) + (*iter)->release(); +} + +// ### Optimize - check engine for the parent meta object etc. +QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject *metaObject) +{ + Q_ASSERT(engine); + Q_ASSERT(metaObject); + + QmlPropertyCache *cache = new QmlPropertyCache; + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + // ### The properties/methods should probably be spliced on a per-metaobject basis + int propCount = metaObject->propertyCount(); + + cache->indexCache.resize(propCount); + for (int ii = propCount - 1; ii >= 0; --ii) { + QMetaProperty p = metaObject->property(ii); + QString propName = QLatin1String(p.name()); + + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass2->createPersistentIdentifier(propName); + data->propType = p.userType(); + data->coreIndex = ii; + data->name = propName; + + cache->indexCache[ii] = data; + + if (cache->stringCache.contains(propName)) + continue; + + cache->stringCache.insert(propName, data); + cache->identifierCache.insert(data->identifier, data); + data->addref(); + data->addref(); + } + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 0; --ii) { + QMetaMethod m = metaObject->method(ii); + QString methodName = QLatin1String(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + if (cache->stringCache.contains(methodName)) + continue; + + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass2->createPersistentIdentifier(methodName); + cache->stringCache.insert(methodName, data); + cache->identifierCache.insert(data->identifier, data); + data->addref(); + data->addref(); + + data->isFunction = true; + } + + return cache; +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(int index) const +{ + if (index < 0 || index >= indexCache.count()) + return 0; + + return indexCache.at(index); +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QString &str) const +{ + return stringCache.value(str); +} + diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h new file mode 100644 index 0000000..c10fafa --- /dev/null +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROPERTYCACHE_P_H +#define QMLPROPERTYCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QMetaProperty; +class QmlPropertyCache : public QmlRefCount +{ +public: + QmlPropertyCache(); + virtual ~QmlPropertyCache(); + + struct Data : public QmlRefCount { + Data() : isFunction(false) {} + + bool isFunction; + int propType; + int coreIndex; + QString name; + }; + + static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); + + Data *property(const QScriptDeclarativeClass::Identifier &id) const { + return identifierCache.value(id); + } + + Data *property(const QString &) const; + Data *property(int) const; + +private: + typedef QVector *> IndexCache; + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; + + IndexCache indexCache; + StringCache stringCache; + IdentifierCache identifierCache; +}; + +QT_END_NAMESPACE + +#endif // QMLPROPERTYCACHE_P_H diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 44b17e6..a5d2732 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -143,6 +143,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, const QList &customTypeData = comp->customTypeData; const QList &intData = comp->intData; const QList &floatData = comp->floatData; + const QList &propertyCaches = comp->propertyCaches; QmlEnginePrivate::SimpleList bindValues; @@ -259,9 +260,15 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, const QByteArray &metadata = datas.at(instr.storeMeta.data); QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); - const QmlVMEMetaData *data = (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); + const QmlVMEMetaData *data = + (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); (void)new QmlVMEMetaObject(target, &mo, data, comp); + + QmlDeclarativeData *ddata = QmlDeclarativeData::get(target, true); + if (ddata->propertyCache) ddata->propertyCache->release(); + ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache); + ddata->propertyCache->addref(); } break; -- cgit v0.12 From dff7f0593d86e90eb14c805a96ebbda778f45a82 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 30 Sep 2009 18:13:04 +1000 Subject: Improve script lookup caching --- demos/declarative/samegame/content/samegame.js | 3 + src/declarative/qml/qml.pri | 10 +- src/declarative/qml/qmlcompiler.cpp | 20 +- src/declarative/qml/qmlcompiler_p.h | 4 +- src/declarative/qml/qmlcontext.cpp | 47 ++-- src/declarative/qml/qmlcontext_p.h | 10 +- src/declarative/qml/qmlcontextscriptclass.cpp | 190 +++++++++++++++++ src/declarative/qml/qmlcontextscriptclass_p.h | 89 ++++++++ src/declarative/qml/qmlengine.cpp | 264 +---------------------- src/declarative/qml/qmlengine_p.h | 62 +----- src/declarative/qml/qmlinstruction_p.h | 2 +- src/declarative/qml/qmlintegercache.cpp | 108 ++++++++++ src/declarative/qml/qmlintegercache_p.h | 103 +++++++++ src/declarative/qml/qmlmetaproperty.cpp | 2 +- src/declarative/qml/qmlobjectscriptclass.cpp | 283 +++++++++++++++++++++++++ src/declarative/qml/qmlobjectscriptclass_p.h | 98 +++++++++ src/declarative/qml/qmlpropertycache.cpp | 20 +- src/declarative/qml/qmlpropertycache_p.h | 37 +++- src/declarative/qml/qmlvme.cpp | 4 +- src/script/api/qscriptvalue.cpp | 5 + src/script/bridge/qscriptdeclarativeclass.cpp | 13 ++ src/script/bridge/qscriptdeclarativeclass_p.h | 2 + 22 files changed, 1021 insertions(+), 355 deletions(-) create mode 100644 src/declarative/qml/qmlcontextscriptclass.cpp create mode 100644 src/declarative/qml/qmlcontextscriptclass_p.h create mode 100644 src/declarative/qml/qmlintegercache.cpp create mode 100644 src/declarative/qml/qmlintegercache_p.h create mode 100644 src/declarative/qml/qmlobjectscriptclass.cpp create mode 100644 src/declarative/qml/qmlobjectscriptclass_p.h diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index e42b7cc..4a9179b 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -38,6 +38,7 @@ function initBoard() scoreName.forceClose(); dialog.forceClose(); + var a = new Date(); //Initialize Board board = new Array(maxIndex); gameCanvas.score = 0; @@ -48,6 +49,8 @@ function initBoard() } } timer = new Date(); + + print(timer.valueOf() - a.valueOf()); } var fillFound;//Set after a floodFill call to the number of tiles found diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 216adb1..1a6dad3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -35,7 +35,10 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlsqldatabase.cpp \ qml/qmetaobjectbuilder.cpp \ qml/qmlwatcher.cpp \ - qml/qmlpropertycache.cpp + qml/qmlpropertycache.cpp \ + qml/qmlintegercache.cpp \ + qml/qmlobjectscriptclass.cpp \ + qml/qmlcontextscriptclass.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -88,7 +91,10 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlsqldatabase_p.h \ qml/qmetaobjectbuilder_p.h \ qml/qmlwatcher_p.h \ - qml/qmlpropertycache_p.h + qml/qmlpropertycache_p.h \ + qml/qmlintegercache_p.h \ + qml/qmlobjectscriptclass_p.h \ + qml/qmlcontextscriptclass_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 0b4ac20..5cb2158 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -633,7 +633,7 @@ void QmlCompiler::compileTree(Object *tree) init.line = 0; init.init.bindingsSize = compileState.bindings.count(); init.init.parserStatusSize = compileState.parserStatusCount; - init.init.idSize = compileState.ids.count(); + init.init.contextCache = genContextCache(); output->bytecode << init; genObject(tree); @@ -964,7 +964,7 @@ void QmlCompiler::genComponent(QmlParser::Object *obj) init.type = QmlInstruction::Init; init.init.bindingsSize = compileState.bindings.count(); init.init.parserStatusSize = compileState.parserStatusCount; - init.init.idSize = compileState.ids.count(); + init.init.contextCache = genContextCache(); init.line = obj->location.start.line; output->bytecode << init; @@ -2263,6 +2263,22 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, output->bytecode << store; } +int QmlCompiler::genContextCache() +{ + if (compileState.ids.count() == 0) + return -1; + + QmlIntegerCache *cache = new QmlIntegerCache(engine); + + for (QHash::ConstIterator iter = compileState.ids.begin(); + iter != compileState.ids.end(); + ++iter) + cache->add(iter.key(), (*iter)->idIndex); + + output->contextCaches.append(cache); + return output->contextCaches.count() - 1; +} + bool QmlCompiler::completeComponentBuild() { for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 677aba7..1cb66c7 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -63,6 +63,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -111,6 +112,7 @@ public: QList bytecode; QList programs; QList propertyCaches; + QList contextCaches; void dumpInstructions(); private: @@ -232,7 +234,7 @@ private: QmlParser::Property *prop, QmlParser::Object *obj, QmlParser::Property *valueTypeProperty = 0); - + int genContextCache(); int componentTypeRef(); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 97ab375..1c9d177 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE QmlContextPrivate::QmlContextPrivate() -: parent(0), engine(0), isInternal(false), notifyIndex(-1), +: parent(0), engine(0), isInternal(false), propertyNames(0), notifyIndex(-1), highPriorityCount(0), expressions(0), idValues(0), idValueCount(0) { } @@ -103,8 +103,8 @@ void QmlContextPrivate::init() //set scope chain QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - QScriptValue scopeObj = - scriptEngine->newObject(QmlEnginePrivate::get(engine)->contextClass, scriptEngine->newVariant(QVariant::fromValue((QObject*)q))); + QScriptValue scopeObj = QmlEnginePrivate::get(engine)->contextClass->newContext(q); + //### no longer need to push global object once we switch to JSC (test with objects added to globalObject) //if (parent) // scopeChain = parent->d_func()->scopeChain; @@ -304,6 +304,9 @@ QmlContext::~QmlContext() d->contextObjects.clear(); delete [] d->idValues; + + if (d->propertyNames) + d->propertyNames->release(); } void QmlContextPrivate::invalidateEngines() @@ -361,13 +364,16 @@ void QmlContext::setContextProperty(const QString &name, const QVariant &value) QObject *o = QmlMetaType::toQObject(value); setContextProperty(name, o); } else { - QHash::ConstIterator iter = d->propertyNames.find(name); - if(iter == d->propertyNames.end()) { - d->propertyNames.insert(name, d->idValueCount + d->propertyValues.count()); + + if (!d->propertyNames) d->propertyNames = new QmlIntegerCache(d->engine); + + int idx = d->propertyNames->value(name); + if (idx == -1) { + d->propertyNames->add(name, d->idValueCount + d->propertyValues.count()); d->propertyValues.append(value); } else { - d->propertyValues[*iter] = value; - QMetaObject::activate(this, *iter + d->notifyIndex, 0); + d->propertyValues[idx] = value; + QMetaObject::activate(this, idx + d->notifyIndex, 0); } } } @@ -380,15 +386,19 @@ void QmlContextPrivate::setIdProperty(const QString &name, int idx, notifyIndex = q->metaObject()->methodCount(); } - propertyNames.insert(name, idx); + propertyNames->add(name, idx); idValues[idx].priv = this; idValues[idx] = obj; } -void QmlContextPrivate::setIdPropertyCount(int count) +void QmlContextPrivate::setIdPropertyData(QmlIntegerCache *data) { - idValues = new ContextGuard[count]; - idValueCount = count; + Q_ASSERT(!propertyNames); + propertyNames = data; + propertyNames->addref(); + + idValueCount = data->count(); + idValues = new ContextGuard[idValueCount]; } /*! @@ -402,14 +412,15 @@ void QmlContext::setContextProperty(const QString &name, QObject *value) if (d->notifyIndex == -1) d->notifyIndex = this->metaObject()->methodCount(); - QHash::ConstIterator iter = d->propertyNames.find(name); - if(iter == d->propertyNames.end()) { - d->propertyNames.insert(name, d->idValueCount + d->propertyValues.count()); + if (!d->propertyNames) d->propertyNames = new QmlIntegerCache(d->engine); + int idx = d->propertyNames->value(name); + + if (idx == -1) { + d->propertyNames->add(name, d->idValueCount + d->propertyValues.count()); d->propertyValues.append(QVariant::fromValue(value)); } else { - int idx = *iter; - d->propertyValues[*iter] = QVariant::fromValue(value); - QMetaObject::activate(this, *iter + d->notifyIndex, 0); + d->propertyValues[idx] = QVariant::fromValue(value); + QMetaObject::activate(this, idx + d->notifyIndex, 0); } } diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index b305408..64faa6d 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -61,6 +61,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -82,7 +83,8 @@ public: QmlEngine *engine; bool isInternal; - QHash propertyNames; + QmlIntegerCache *propertyNames; +// QHash propertyNames; QList propertyValues; int notifyIndex; @@ -125,9 +127,13 @@ public: ContextGuard *idValues; int idValueCount; void setIdProperty(const QString &, int, QObject *); - void setIdPropertyCount(int); + void setIdPropertyData(QmlIntegerCache *); void destroyed(ContextGuard *); + static QmlContextPrivate *get(QmlContext *context) { + return static_cast(QObjectPrivate::get(context)); + } + // Only used for debugging QList > instances; }; diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp new file mode 100644 index 0000000..baea60a --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcontextscriptclass_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +struct ContextData { + ContextData(QmlContext *c) : context(c) {} + QGuard context; +}; + +/* + The QmlContextScriptClass handles property access for a QmlContext + via QtScript. + */ +QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine), + lastPropertyIndex(-1), lastDefaultObject(-1) +{ +} + +QmlContextScriptClass::~QmlContextScriptClass() +{ +} + +QScriptValue QmlContextScriptClass::newContext(QmlContext *context) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, (Object)new ContextData(context)); +} + +QScriptClass::QueryFlags +QmlContextScriptClass::queryProperty(const Object &object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + QmlContext *bindContext = ((ContextData *)object)->context.data(); + if (!bindContext) + return 0; + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + lastPropertyIndex = -1; + lastDefaultObject = -1; + + lastPropertyIndex = cp->propertyNames?cp->propertyNames->value(name):-1; + if (lastPropertyIndex != -1) + return QScriptClass::HandlesReadAccess; + + // ### Check for attached properties +#if 0 + QmlType *type = 0; ImportedNamespace *ns = 0; + if (currentExpression && bindContext == currentExpression->context() && + propName.at(0).isUpper() && resolveType(bindContext->d_func()->imports, propName.toUtf8(), &type, 0, 0, 0, &ns)) { + + if (type || ns) { + // Must be either an attached property, or an enum + resolveData.object = bindContext->d_func()->defaultObjects.first(); + resolveData.type = type; + resolveData.ns = ns; + return QScriptClass::HandlesReadAccess; + } + + } +#endif + + for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags); + + if (rv) { + lastDefaultObject = ii; + return rv; + } + } + + return 0; +} + +QScriptValue QmlContextScriptClass::property(const Object &object, const Identifier &name) +{ + Q_UNUSED(object); + + Q_ASSERT(lastPropertyIndex != -1 || lastDefaultObject != -1); + + QmlContext *bindContext = ((ContextData *)object)->context.data(); + Q_ASSERT(bindContext); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + + // ### Check for attached properties +#if 0 + if (resolveData.type || resolveData.ns) { + QmlTypeNameBridge tnb = { + resolveData.object, + resolveData.type, + resolveData.ns + }; + return scriptEngine.newObject(typeNameClass, scriptEngine.newVariant(qVariantFromValue(tnb))); + } +#endif + + if (lastPropertyIndex != -1) { + + QScriptValue rv; + if (lastPropertyIndex < cp->idValueCount) { + rv = ep->objectClass->newQObject(cp->idValues[lastPropertyIndex].data()); + } else { + QVariant value = cp->propertyValues.at(lastPropertyIndex); + if (QmlMetaType::isObject(value.userType())) { + rv = ep->objectClass->newQObject(QmlMetaType::toQObject(value)); + } else { + // ### Shouldn't this be qScriptValueFromValue() + rv = ep->scriptEngine.newVariant(value); + } + } + + ep->capturedProperties << + QmlEnginePrivate::CapturedProperty(bindContext, -1, + lastPropertyIndex + cp->notifyIndex); + + return rv; + } else { + + // Default object property + return ep->objectClass->property(cp->defaultObjects.at(lastDefaultObject), name); + + } +} + +void QmlContextScriptClass::setProperty(const Object &object, const Identifier &name, + const QScriptValue &value) +{ + Q_ASSERT(lastDefaultObject != -1); + + QmlContext *bindContext = ((ContextData *)object)->context.data(); + Q_ASSERT(bindContext); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + ep->objectClass->setProperty(cp->defaultObjects.at(lastDefaultObject), name, value); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h new file mode 100644 index 0000000..9ef090d --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCONTEXTSCRIPTCLASS_P_H +#define QMLCONTEXTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlContext; +class QmlContextScriptClass : public QScriptDeclarativeClass +{ +public: + QmlContextScriptClass(QmlEngine *); + ~QmlContextScriptClass(); + + QScriptValue newContext(QmlContext *); + +protected: + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + +private: + QmlEngine *engine; + + int lastPropertyIndex; + int lastDefaultObject; + + uint m_id; +}; + +QT_END_NAMESPACE + +#endif // QMLCONTEXTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 757670b..d680fa1 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -193,8 +193,6 @@ QmlEnginePrivate::~QmlEnginePrivate() contextClass = 0; delete objectClass; objectClass = 0; - delete objectClass2; - objectClass2 = 0; delete valueTypeClass; valueTypeClass = 0; delete typeNameClass; @@ -242,7 +240,6 @@ void QmlEnginePrivate::init() scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); - objectClass2 = new QScriptDeclarativeClass(&scriptEngine); valueTypeClass = new QmlValueTypeScriptClass(q); typeNameClass = new QmlTypeNameScriptClass(q); rootContext = new QmlContext(q,true); @@ -288,95 +285,6 @@ struct QmlValueTypeReference { }; Q_DECLARE_METATYPE(QmlValueTypeReference); -//////////////////////////////////////////////////////////////////// -QScriptClass::QueryFlags -QmlEnginePrivate::queryContext(const QString &propName, uint *id, - QmlContext *bindContext) -{ - resolveData.safetyCheckId++; - *id = resolveData.safetyCheckId; - resolveData.clear(); - - QHash::Iterator contextProperty = - bindContext->d_func()->propertyNames.find(propName); - - if (contextProperty != bindContext->d_func()->propertyNames.end()) { - - resolveData.context = bindContext; - resolveData.contextIndex = *contextProperty; - - return QScriptClass::HandlesReadAccess; - } - - QmlType *type = 0; ImportedNamespace *ns = 0; - if (currentExpression && bindContext == currentExpression->context() && - propName.at(0).isUpper() && resolveType(bindContext->d_func()->imports, propName.toUtf8(), &type, 0, 0, 0, &ns)) { - - if (type || ns) { - // Must be either an attached property, or an enum - resolveData.object = bindContext->d_func()->defaultObjects.first(); - resolveData.type = type; - resolveData.ns = ns; - return QScriptClass::HandlesReadAccess; - } - - } - - QScriptClass::QueryFlags rv = 0; - for (int ii = 0; !rv && ii < bindContext->d_func()->defaultObjects.count(); ++ii) { - rv = queryObject(propName, id, - bindContext->d_func()->defaultObjects.at(ii)); - } - - return rv; -} - -QScriptValue QmlEnginePrivate::propertyContext(const QScriptString &name, uint id) -{ - Q_ASSERT(id == resolveData.safetyCheckId); - - if (resolveData.type || resolveData.ns) { - QmlTypeNameBridge tnb = { - resolveData.object, - resolveData.type, - resolveData.ns - }; - return scriptEngine.newObject(typeNameClass, scriptEngine.newVariant(qVariantFromValue(tnb))); - } else if (resolveData.context) { - QmlContext *bindContext = resolveData.context; - QmlContextPrivate *contextPrivate = bindContext->d_func(); - int index = resolveData.contextIndex; - - QScriptValue rv; - if (index < contextPrivate->idValueCount) { - rv = scriptEngine.newObject(objectClass, scriptEngine.newVariant(QVariant::fromValue(contextPrivate->idValues[index].data()))); - } else { - QVariant value = contextPrivate->propertyValues.at(index); - if (QmlMetaType::isObject(value.userType())) { - rv = scriptEngine.newObject(objectClass, scriptEngine.newVariant(value)); - } else { - rv = scriptEngine.newVariant(value); - } - } - capturedProperties << QmlEnginePrivate::CapturedProperty(bindContext, -1, index + contextPrivate->notifyIndex); - return rv; - - } else { - - return propertyObject(name, resolveData.object, id); - - } - - return QScriptValue(); -} - -void QmlEnginePrivate::setPropertyContext(const QScriptValue &value, uint id) -{ - // As context properties cannot be written, we can assume that the - // write is a object property write - setPropertyObject(value, id); -} - void QmlEnginePrivate::setPropertyObject(const QScriptValue &value, uint id) { Q_ASSERT(id == resolveData.safetyCheckId); @@ -430,7 +338,7 @@ QmlEnginePrivate::queryObject(const QString &propName, return rv; } -QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, +QScriptValue QmlEnginePrivate::propertyObject(const QString &propName, QObject *obj, uint id) { Q_ASSERT(id == resolveData.safetyCheckId); @@ -461,7 +369,7 @@ QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, if (!varobj) varobj = qvariant_cast(var); if (varobj) { - return scriptEngine.newObject(objectClass, scriptEngine.newVariant(QVariant::fromValue(varobj))); + return objectClass->newQObject(varobj); } else { return qScriptValueFromValue(&scriptEngine, var); } @@ -784,8 +692,8 @@ void QmlDeclarativeData::setBindingBit(QObject *obj, int bit) QScriptValue QmlEnginePrivate::qmlScriptObject(QObject* object, QmlEngine* engine) { - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return scriptEngine->newObject(engine->d_func()->objectClass, scriptEngine->newQObject(object, QScriptEngine::AutoOwnership)); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + return enginePriv->objectClass->newQObject(object); } /*! @@ -901,7 +809,7 @@ QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngi QUrl url; if(ctxt->argumentCount() > 2) url = QUrl(ctxt->argument(2).toString()); - QObject *parentArg = ctxt->argument(1).data().toQObject(); + QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); QmlContext *qmlCtxt = qmlContext(parentArg); url = qmlCtxt->resolvedUrl(url); QmlComponent component(activeEngine, qml.toUtf8(), url); @@ -1138,13 +1046,15 @@ QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) QmlEnginePrivate *ep = static_cast(QObjectPrivate::get(engine)); + QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val); + if (dc == ep->objectClass) + return QVariant::fromValue(ep->objectClass->toQObject(val)); + else if (dc == ep->contextClass) + return QVariant(); + QScriptClass *sc = val.scriptClass(); if (!sc) { return val.toVariant(); - } else if (sc == ep->contextClass) { - return QVariant(); - } else if (sc == ep->objectClass) { - return QVariant::fromValue(val.data().toQObject()); } else if (sc == ep->valueTypeClass) { QmlValueTypeReference ref = qvariant_cast(val.data().toVariant()); @@ -1160,56 +1070,6 @@ QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) } ///////////////////////////////////////////////////////////// -/* - The QmlContextScriptClass handles property access for a QmlContext - via QtScript. - */ -QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) - : QmlScriptClass(bindEngine) -{ -} - -QmlContextScriptClass::~QmlContextScriptClass() -{ -} - -QScriptClass::QueryFlags -QmlContextScriptClass::queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id) -{ - Q_UNUSED(flags); - QmlContext *bindContext = - static_cast(object.data().toQObject()); - - QString propName = name.toString(); - - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - return ep->queryContext(propName, id, bindContext); -} - -QScriptValue QmlContextScriptClass::property(const QScriptValue &object, - const QScriptString &name, - uint id) -{ - Q_UNUSED(object); - - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - return ep->propertyContext(name, id); -} - -void QmlContextScriptClass::setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value) -{ - Q_UNUSED(object); - Q_UNUSED(name); - - QmlEnginePrivate::get(engine)->setPropertyContext(value, id); -} - -///////////////////////////////////////////////////////////// QmlTypeNameScriptClass::QmlTypeNameScriptClass(QmlEngine *engine) : QmlScriptClass(engine), object(0), type(0) { @@ -1365,108 +1225,6 @@ void QmlValueTypeScriptClass::setProperty(QScriptValue &object, ref.type->write(ref.object, ref.property); } -///////////////////////////////////////////////////////////// -/* - The QmlObjectScriptClass handles property access for QObjects - via QtScript. It is also used to provide a more useful API in - QtScript for QML. - */ - -QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - QString ret = QLatin1String("Qml Object, "); - if(obj){ - //###Should this be designer or developer details? Dev for now. - //TODO: Can we print the id too? - ret += QLatin1String("\""); - ret += obj->objectName(); - ret += QLatin1String("\" "); - ret += QLatin1String(obj->metaObject()->className()); - ret += QLatin1String("(0x"); - ret += QString::number((quintptr)obj,16); - ret += QLatin1String(")"); - }else{ - ret += QLatin1String("null"); - } - return engine->newVariant(ret); -} - -QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - if(obj){ - int delay = 0; - if(context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - QTimer::singleShot(delay, obj, SLOT(deleteLater())); - //### Should this be delayed as well? - context->thisObject().setData(QScriptValue(engine, 0)); - } - return engine->nullValue(); -} - -QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) - : QmlScriptClass(bindEngine) -{ - engine = bindEngine; - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); - prototypeObject = scriptEngine->newObject(); - prototypeObject.setProperty(QLatin1String("toStr"),//TODO: Why won't toString work? - scriptEngine->newFunction(QmlObjectToString)); - prototypeObject.setProperty(QLatin1String("destroy"), - scriptEngine->newFunction(QmlObjectDestroy)); -} - -QmlObjectScriptClass::~QmlObjectScriptClass() -{ -} - -QScriptValue QmlObjectScriptClass::prototype() const -{ - return prototypeObject; -} - -QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id) -{ - Q_UNUSED(flags); - QObject *obj = object.data().toQObject(); - QueryFlags rv = 0; - QString propName = name.toString(); - - if (obj) - rv = QmlEnginePrivate::get(engine)->queryObject(propName, id, obj); - - return rv; -} - -QScriptValue QmlObjectScriptClass::property(const QScriptValue &object, - const QScriptString &name, - uint id) -{ - QObject *obj = object.data().toQObject(); - - QScriptValue rv = - QmlEnginePrivate::get(engine)->propertyObject(name, obj, id); - if (rv.isValid()) - return rv; - - return QScriptValue(); -} - -void QmlObjectScriptClass::setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value) -{ - Q_UNUSED(name); - Q_UNUSED(object); - QmlEnginePrivate::get(engine)->setPropertyObject(value, id); -} - - struct QmlEnginePrivate::ImportedNamespace { QStringList urls; QList majversions; diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 68019e2..764cc6c 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -73,6 +73,8 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -100,13 +102,9 @@ public: void init(); - QScriptClass::QueryFlags queryContext(const QString &name, uint *id, - QmlContext *); - QScriptValue propertyContext(const QScriptString &propName, uint id); - void setPropertyContext(const QScriptValue &, uint id); QScriptClass::QueryFlags queryObject(const QString &name, uint *id, QObject *); - QScriptValue propertyObject(const QScriptString &propName, QObject *, + QScriptValue propertyObject(const QString &propName, QObject *, uint id = 0); void setPropertyObject(const QScriptValue &, uint id); @@ -151,7 +149,6 @@ public: } resolveData; QmlContextScriptClass *contextClass; QmlObjectScriptClass *objectClass; - QScriptDeclarativeClass *objectClass2; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; // Used by DOM Core 3 API @@ -215,6 +212,7 @@ public: // ### Fixme typedef QHash, bool> FunctionCache; FunctionCache functionCache; + QHash propertyCache; QmlPropertyCache *cache(QObject *obj) { Q_Q(QmlEngine); @@ -285,19 +283,6 @@ public: class QmlScriptClass : public QScriptClass { public: - enum ClassId - { - InvalidId = -1, - - FunctionId = 0x80000000, - VariantPropertyId = 0x40000000, - PropertyId = 0x00000000, - - ClassIdMask = 0xC0000000, - - ClassIdSelectorMask = 0x3F000000, - }; - QmlScriptClass(QmlEngine *); static QVariant toVariant(QmlEngine *, const QScriptValue &); @@ -305,45 +290,6 @@ protected: QmlEngine *engine; }; -class QmlContextScriptClass : public QmlScriptClass -{ -public: - QmlContextScriptClass(QmlEngine *); - ~QmlContextScriptClass(); - - virtual QueryFlags queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id); - virtual QScriptValue property(const QScriptValue &object, - const QScriptString &name, - uint id); - virtual void setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value); -}; - -class QmlObjectScriptClass : public QmlScriptClass -{ -public: - QmlObjectScriptClass(QmlEngine *); - ~QmlObjectScriptClass(); - - virtual QScriptValue prototype () const; - QScriptValue prototypeObject; - - virtual QueryFlags queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id); - virtual QScriptValue property(const QScriptValue &object, - const QScriptString &name, - uint id); - virtual void setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value); -}; - class QmlTypeNameScriptClass : public QmlScriptClass { public: diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index e62bfdf..38b3191 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -165,7 +165,7 @@ public: struct { int bindingsSize; int parserStatusSize; - int idSize; + int contextCache; } init; struct { int type; diff --git a/src/declarative/qml/qmlintegercache.cpp b/src/declarative/qml/qmlintegercache.cpp new file mode 100644 index 0000000..1bc4086 --- /dev/null +++ b/src/declarative/qml/qmlintegercache.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlintegercache_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QmlIntegerCache::QmlIntegerCache(QmlEngine *e) +: engine(e) +{ +} + +QmlIntegerCache::~QmlIntegerCache() +{ + qDeleteAll(stringCache); +} + +void QmlIntegerCache::add(const QString &id, int value) +{ + Q_ASSERT(!stringCache.contains(id)); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + // ### use contextClass + QScriptDeclarativeClass::PersistentIdentifier *d = + enginePriv->objectClass->createPersistentIdentifier(id); + d->value = value; + + stringCache.insert(id, d); + identifierCache.insert(d->identifier, d); +} + +int QmlIntegerCache::value(const QString &id) +{ + Data *d = stringCache.value(id); + return d?d->value:-1; +} + +QmlIntegerCache *QmlIntegerCache::createForEnums(QmlType *type, QmlEngine *engine) +{ + Q_ASSERT(type); + Q_ASSERT(engine); + + QmlIntegerCache *cache = new QmlIntegerCache(engine); + + const QMetaObject *mo = type->metaObject(); + + for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum enumerator = mo->enumerator(ii); + + for (int jj = 0; jj < enumerator.keyCount(); ++jj) { + QString name = QLatin1String(enumerator.key(jj)); + int value = enumerator.value(jj); + + if (!name.at(0).isUpper()) + continue; + + if (cache->stringCache.contains(name)) + continue; + + cache->add(name, value); + } + } + + return cache; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlintegercache_p.h b/src/declarative/qml/qmlintegercache_p.h new file mode 100644 index 0000000..fda80c6 --- /dev/null +++ b/src/declarative/qml/qmlintegercache_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLINTEGERCACHE_P_H +#define QMLINTEGERCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlType; +class QmlEngine; +class QmlIntegerCache : public QmlRefCount +{ +public: + QmlIntegerCache(QmlEngine *); + virtual ~QmlIntegerCache(); + + inline int count() const; + void add(const QString &, int); + int value(const QString &); + inline int value(const QScriptDeclarativeClass::Identifier &id) const; + + static QmlIntegerCache *createForEnums(QmlType *, QmlEngine *); +private: + struct Data { + int value; + }; + + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; + + StringCache stringCache; + IdentifierCache identifierCache; + QmlEngine *engine; +}; + +int QmlIntegerCache::value(const QScriptDeclarativeClass::Identifier &id) const +{ + Data *d = identifierCache.value(id); + return d?d->value:-1; +} + +int QmlIntegerCache::count() const +{ + return stringCache.count(); +} + +QT_END_NAMESPACE + +#endif // QMLINTEGERCACHE_P_H + diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index f7882dc..ec143a7 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -218,7 +218,7 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (cache) { QmlPropertyCache::Data *data = cache->property(name); - if (data && !data->isFunction) { + if (data && !(data->flags & QmlPropertyCache::Data::IsFunction)) { type = QmlMetaProperty::Property; propType = data->propType; coreIdx = data->coreIndex; diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp new file mode 100644 index 0000000..0ae1809 --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -0,0 +1,283 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlobjectscriptclass_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct ObjectData { + ObjectData(QObject *o) : object(o) {} + QGuard object; +}; + +static QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().data().toQObject(); + QString ret = QLatin1String("Qml Object, "); + if(obj){ + //###Should this be designer or developer details? Dev for now. + //TODO: Can we print the id too? + ret += QLatin1String("\""); + ret += obj->objectName(); + ret += QLatin1String("\" "); + ret += QLatin1String(obj->metaObject()->className()); + ret += QLatin1String("(0x"); + ret += QString::number((quintptr)obj,16); + ret += QLatin1String(")"); + }else{ + ret += QLatin1String("null"); + } + return engine->newVariant(ret); +} + +static QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + if(obj){ + int delay = 0; + if(context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + obj->deleteLater(); + //### Should this be delayed as well? + context->thisObject().setData(QScriptValue(engine, 0)); + } + return engine->nullValue(); +} + +/* + The QmlObjectScriptClass handles property access for QObjects + via QtScript. It is also used to provide a more useful API in + QtScript for QML. + */ +QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), lastData(0), + engine(bindEngine) +{ + engine = bindEngine; + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); + + m_destroy = scriptEngine->newFunction(QmlObjectDestroy); + m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); +} + +QmlObjectScriptClass::~QmlObjectScriptClass() +{ + delete m_destroyId; +} + +QScriptValue QmlObjectScriptClass::newQObject(QObject *object) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, (Object)new ObjectData(object)); +} + +QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const +{ + return value.toQObject(); +} + +QScriptClass::QueryFlags +QmlObjectScriptClass::queryProperty(const Object &object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + return queryProperty(toQObject(object), name, flags); +} + +QScriptClass::QueryFlags +QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + lastData = 0; + + if (name == m_destroyId->identifier) + return QScriptClass::HandlesReadAccess; + + if (!obj) + return 0; + + QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (ddata) { cache->addref(); ddata->propertyCache = cache; } + } + + if (cache) { + QmlPropertyCache::Data *property = cache->property(name); + if (!property) return 0; + + if (flags == QScriptClass::HandlesReadAccess) { + lastData = property; + return QScriptClass::HandlesReadAccess; + } else if (property->propType > 0 && property->propType < QVariant::UserType) { + lastData = property; + return flags; + } + } + + // Fallback + return QmlEnginePrivate::get(engine)->queryObject(toString(name), &m_id, obj); +} + +QScriptValue QmlObjectScriptClass::property(const Object &object, const Identifier &name) +{ + return property(toQObject(object), name); +} + +QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name) +{ + if (name == m_destroyId->identifier) + return m_destroy; + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (!obj) { + return QScriptValue(); + } else if (lastData) { + + if (lastData->flags & QmlPropertyCache::Data::IsFunction) { + // ### Optimize + QScriptValue sobj = scriptEngine->newQObject(obj); + return sobj.property(toString(name)); + } else { + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); + if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { + enginePriv->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, + lastData->notifyIndex); + } + + if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { + QObject *rv = *(QObject **)var.constData(); + return newQObject(rv); + } else { + return qScriptValueFromValue(scriptEngine, var); + } + } + + } else { + return QmlEnginePrivate::get(engine)->propertyObject(toString(name), obj, m_id); + } +} + +void QmlObjectScriptClass::setProperty(const Object &object, + const Identifier &name, + const QScriptValue &value) +{ + return setProperty(toQObject(object), name, value); +} + +void QmlObjectScriptClass::setProperty(QObject *obj, + const Identifier &name, + const QScriptValue &value) +{ + Q_UNUSED(name); + Q_UNUSED(object); + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (!obj) { + return; + } else if (lastData) { + switch (lastData->propType) { + case 1: + { + bool b = value.toBoolean(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + case 2: + { + int b = value.toInteger(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + case 6: + { + double b = value.toNumber(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + default: + { + QMetaProperty p = obj->metaObject()->property(lastData->coreIndex); + p.write(obj, value.toVariant()); + } + } + } else { + QmlEnginePrivate::get(engine)->setPropertyObject(value, m_id); + } +} + +QObject *QmlObjectScriptClass::toQObject(const Object &object, bool *ok) +{ + if (ok) *ok = true; + + ObjectData *data = (ObjectData*)object; + return data->object.data(); +} + +void QmlObjectScriptClass::destroyed(const Object &object) +{ + ObjectData *data = (ObjectData*)object; + delete data; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h new file mode 100644 index 0000000..c25718c --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLOBJECTSCRIPTCLASS_P_H +#define QMLOBJECTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlObjectScriptClass : public QScriptDeclarativeClass +{ +public: + QmlObjectScriptClass(QmlEngine *); + ~QmlObjectScriptClass(); + + QScriptValue newQObject(QObject *); + QObject *toQObject(const QScriptValue &) const; + + QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, + QScriptClass::QueryFlags flags); + QScriptValue property(QObject *, const Identifier &); + void setProperty(QObject *, const Identifier &name, const QScriptValue &); + +protected: + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + virtual QObject *toQObject(const Object &, bool *ok = 0); + virtual void destroyed(const Object &); + +private: + uint m_id; + QmlPropertyCache::Data *lastData; + struct Dummy {}; + PersistentIdentifier *m_destroyId; + QScriptValue m_destroy; + QmlEngine *engine; +}; + +QT_END_NAMESPACE + +#endif // QMLOBJECTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index f88b3a3..95b819a 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -42,6 +42,8 @@ #include "qmlpropertycache_p.h" #include "qmlengine_p.h" +QT_BEGIN_NAMESPACE + QmlPropertyCache::QmlPropertyCache() { } @@ -78,12 +80,19 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject QMetaProperty p = metaObject->property(ii); QString propName = QLatin1String(p.name()); - QScriptDeclarativeClass::PersistentIdentifier *data = - enginePriv->objectClass2->createPersistentIdentifier(propName); + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass->createPersistentIdentifier(propName); + data->propType = p.userType(); data->coreIndex = ii; + data->notifyIndex = p.notifySignalIndex(); data->name = propName; + if (p.isConstant()) + data->flags |= Data::IsConstant; + if (QmlMetaType::isObject(data->propType)) + data->flags |= Data::IsQObjectDerived; + cache->indexCache[ii] = data; if (cache->stringCache.contains(propName)) @@ -107,14 +116,14 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject if (cache->stringCache.contains(methodName)) continue; - QScriptDeclarativeClass::PersistentIdentifier *data = - enginePriv->objectClass2->createPersistentIdentifier(methodName); + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass->createPersistentIdentifier(methodName); cache->stringCache.insert(methodName, data); cache->identifierCache.insert(data->identifier, data); data->addref(); data->addref(); - data->isFunction = true; + data->flags |= Data::IsFunction; } return cache; @@ -135,3 +144,4 @@ QmlPropertyCache::property(const QString &str) const return stringCache.value(str); } +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index c10fafa..21c8ef3 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -67,33 +67,50 @@ public: QmlPropertyCache(); virtual ~QmlPropertyCache(); - struct Data : public QmlRefCount { - Data() : isFunction(false) {} + struct Data { + inline Data(); - bool isFunction; + enum Flag { IsFunction = 0x00000001, + IsQObjectDerived = 0x00000002, + IsConstant = 0x00000004 }; + Q_DECLARE_FLAGS(Flags, Flag) + + Flags flags; int propType; int coreIndex; + int notifyIndex; QString name; }; static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); - Data *property(const QScriptDeclarativeClass::Identifier &id) const { - return identifierCache.value(id); - } - + inline Data *property(const QScriptDeclarativeClass::Identifier &id) const; Data *property(const QString &) const; Data *property(int) const; private: - typedef QVector *> IndexCache; - typedef QHash *> StringCache; - typedef QHash *> IdentifierCache; + struct RData : public Data, public QmlRefCount {}; + + typedef QVector *> IndexCache; + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; IndexCache indexCache; StringCache stringCache; IdentifierCache identifierCache; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlPropertyCache::Data::Flags); + +QmlPropertyCache::Data::Data() +: flags(0), propType(0), coreIndex(-1), notifyIndex(-1) +{ +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index a5d2732..4ba412b 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -166,8 +166,8 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, if (instr.init.parserStatusSize) parserStatus = QmlEnginePrivate::SimpleList(instr.init.parserStatusSize); - if (instr.init.idSize) - cp->setIdPropertyCount(instr.init.idSize); + if (instr.init.contextCache != -1) + cp->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache)); } break; diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index f2716e4..d8b4822 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -71,6 +71,7 @@ #include "bridge/qscriptclassobject_p.h" #include "bridge/qscriptvariant_p.h" #include "bridge/qscriptqobject_p.h" +#include "bridge/qscriptdeclarativeclass_p.h" /*! \since 4.3 @@ -1529,6 +1530,8 @@ QVariant QScriptValue::toVariant() const #endif else if (isArray()) return QScriptEnginePrivate::variantListFromArray(*this); + else if (QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(*this)) + return dc->toVariant(QScriptDeclarativeClass::object(*this)); // try to convert to primitive JSC::ExecState *exec = d->engine->currentFrame; JSC::JSValue savedException; @@ -1619,6 +1622,8 @@ QObject *QScriptValue::toQObject() const if (isQObject()) { QScriptObject *object = static_cast(JSC::asObject(d->jscValue)); return static_cast(object->delegate())->value(); + } else if (QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(*this)) { + return dc->toQObject(QScriptDeclarativeClass::object(*this)); } else if (isVariant()) { QVariant var = toVariant(); int type = var.userType(); diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index c753379..c017e13 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -219,3 +220,15 @@ void QScriptDeclarativeClass::destroyed(const Object &object) Q_UNUSED(object); } +QObject *QScriptDeclarativeClass::toQObject(const Object &, bool *ok) +{ + if (ok) *ok = false; + return 0; +} + +QVariant QScriptDeclarativeClass::toVariant(const Object &, bool *ok) +{ + if (ok) *ok = false; + return QVariant(); +} + diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 5705a51..a00a286 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -112,6 +112,8 @@ public: virtual QStringList propertyNames(const Object &); + virtual QObject *toQObject(const Object &, bool *ok = 0); + virtual QVariant toVariant(const Object &, bool *ok = 0); virtual void destroyed(const Object &); static void destroyPersistentIdentifier(void **); -- cgit v0.12 From 99cf375f554fe01cf47fd4e1a291d4bba62b4018 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 30 Sep 2009 18:51:45 +1000 Subject: Minor QmlMetaProperty cleanup --- src/declarative/qml/qmlmetaproperty.cpp | 53 ++++++++++++++++++++------------- src/declarative/qml/qmlmetaproperty_p.h | 2 ++ 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index ec143a7..fbe41dd 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -646,28 +646,11 @@ QVariant QmlMetaProperty::read() const if (sig && sig->index() == d->coreIdx) return sig->expression()->expression(); } + } else if (type() & Property) { - if (type() & Attached) { - return QVariant::fromValue(d->attachedObject()); - } else if(type() & ValueTypeProperty) { - QmlEnginePrivate *ep = d->context?static_cast(QObjectPrivate::get(d->context->engine())):0; - QmlValueType *valueType = 0; - if (ep) - valueType = ep->valueTypes[d->valueTypeId]; - else - valueType = QmlValueTypeFactory::valueType(d->valueTypeId); - Q_ASSERT(valueType); - - valueType->read(object(), d->coreIdx); - QVariant rv = - valueType->metaObject()->property(d->valueTypeIdx).read(valueType); - if (!ep) - delete valueType; - return rv; - } else { - return d->object->metaObject()->property(d->coreIdx).read(object()); - } + return d->readValueProperty(); + } return QVariant(); } @@ -696,6 +679,36 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) } } +QVariant QmlMetaPropertyPrivate::readValueProperty() +{ + if (type & QmlMetaProperty::Attached) { + + return QVariant::fromValue(attachedObject()); + + } else if(type & QmlMetaProperty::ValueTypeProperty) { + + QmlEnginePrivate *ep = context?QmlEnginePrivate::get(context->engine()):0; + QmlValueType *valueType = 0; + if (ep) + valueType = ep->valueTypes[valueTypeId]; + else + valueType = QmlValueTypeFactory::valueType(valueTypeId); + Q_ASSERT(valueType); + + valueType->read(object, coreIdx); + QVariant rv = + valueType->metaObject()->property(valueTypeIdx).read(valueType); + if (!ep) + delete valueType; + return rv; + + } else { + + return object->metaObject()->property(coreIdx).read(object.data()); + + } +} + void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, QmlMetaProperty::WriteSource source) { diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 0d96174..3193aaf 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -98,6 +98,8 @@ public: QmlMetaProperty::PropertyCategory propertyCategory() const; void writeSignalProperty(const QVariant &); + + QVariant readValueProperty(); void writeValueProperty(const QVariant &, QmlMetaProperty::WriteSource); static quint32 saveValueType(int, int); -- cgit v0.12 From 69c58d7e1c5713d1d6badeffc6c45eeacb1ba2d8 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Oct 2009 13:25:49 +1000 Subject: QmlMetaProperty cleanup --- src/declarative/qml/qmlmetaproperty.cpp | 550 ++++++++++++++----------------- src/declarative/qml/qmlmetaproperty_p.h | 40 +-- src/declarative/qml/qmlpropertycache.cpp | 55 +++- src/declarative/qml/qmlpropertycache_p.h | 35 +- 4 files changed, 348 insertions(+), 332 deletions(-) diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index fbe41dd..477377e 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -72,9 +72,7 @@ QmlMetaProperty::QmlMetaProperty() d->q = this; } -/*! - The destructor deletes its heap data. - */ +/*! \internal */ QmlMetaProperty::~QmlMetaProperty() { delete d; d = 0; @@ -114,11 +112,9 @@ void QmlMetaPropertyPrivate::initDefault(QObject *obj) object = obj; QMetaProperty p = QmlMetaType::defaultProperty(obj); - name = QLatin1String(p.name()); - propType = p.userType();; - coreIdx = p.propertyIndex(); - if (!name.isEmpty()) - type = QmlMetaProperty::Property | QmlMetaProperty::Default; + core.load(p); + if (core.isValid()) + isDefaultProperty = true; } /*! @@ -129,15 +125,12 @@ void QmlMetaPropertyPrivate::initDefault(QObject *obj) QmlMetaProperty::QmlMetaProperty(QObject *obj, int idx, QmlContext *ctxt) : d(new QmlMetaPropertyPrivate) { + Q_ASSERT(obj); + d->q = this; d->context = ctxt; d->object = obj; - d->type = Property; - QMetaProperty p = obj->metaObject()->property(idx); - d->propType = p.userType(); - d->coreIdx = idx; - if (p.name() != 0) - d->name = QLatin1String(p.name()); + d->core.load(obj->metaObject()->property(idx)); } /*! @@ -168,7 +161,6 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (context && context->engine()) enginePrivate = QmlEnginePrivate::get(context->engine()); - this->name = name; object = obj; if (name.isEmpty() || !obj) @@ -185,8 +177,6 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) enginePrivate->resolveType(typeData->imports, name.toLatin1(), &t, 0, 0, 0, 0); if (t && t->attachedPropertiesFunction()) { attachedFunc = t->index(); - if (attachedFunc != -1) - type = QmlMetaProperty::Property | QmlMetaProperty::Attached; } typeData->release(); } @@ -200,9 +190,9 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) QString signalName = name.mid(2); signalName[0] = signalName.at(0).toLower(); - findSignalInt(obj, signalName); - if (signal.signature() != 0) { - type = QmlMetaProperty::SignalProperty; + QMetaMethod method = findSignal(obj, signalName); + if (method.signature()) { + core.load(method); return; } } @@ -218,18 +208,13 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (cache) { QmlPropertyCache::Data *data = cache->property(name); - if (data && !(data->flags & QmlPropertyCache::Data::IsFunction)) { - type = QmlMetaProperty::Property; - propType = data->propType; - coreIdx = data->coreIndex; - } + if (data && !(data->flags & QmlPropertyCache::Data::IsFunction)) + core = *data; + } else { - // Can't cache + // No cache available QMetaProperty p = QmlMetaType::property(obj, name.toUtf8().constData()); - propType = p.userType(); - coreIdx = p.propertyIndex(); - if (p.name()) - type = QmlMetaProperty::Property; + core.load(p); } } @@ -279,33 +264,31 @@ QmlMetaProperty::PropertyCategory QmlMetaProperty::propertyCategory() const QmlMetaProperty::PropertyCategory QmlMetaPropertyPrivate::propertyCategory() const { - if (category == QmlMetaProperty::Unknown) { + uint type = q->type(); + + if (type & QmlMetaProperty::ValueTypeProperty) { + return QmlMetaProperty::Normal; + } else if (type & QmlMetaProperty::Attached) { + return QmlMetaProperty::Object; + } else if (type & QmlMetaProperty::Property) { int type = propertyType(); - if (type == QmlMetaProperty::Invalid) - category = QmlMetaProperty::InvalidProperty; - else if (type < QVariant::UserType) - category = QmlMetaProperty::Normal; + if (type == QVariant::Invalid) + return QmlMetaProperty::InvalidProperty; + else if ((uint)type < QVariant::UserType) + return QmlMetaProperty::Normal; else if (type == qMetaTypeId()) - category = QmlMetaProperty::Bindable; - else { - QmlMetaType::TypeCategory tc = QmlMetaType::typeCategory(type); - switch(tc) { - case QmlMetaType::Object: - category = QmlMetaProperty::Object; - break; - case QmlMetaType::QmlList: - category = QmlMetaProperty::QmlList; - break; - case QmlMetaType::List: - category = QmlMetaProperty::List; - break; - case QmlMetaType::Unknown: - category = QmlMetaProperty::Normal; - break; - } - } + return QmlMetaProperty::Bindable; + else if (core.flags & QmlPropertyCache::Data::IsQObjectDerived) + return QmlMetaProperty::Object; + else if (core.flags & QmlPropertyCache::Data::IsQmlList) + return QmlMetaProperty::QmlList; + else if (core.flags & QmlPropertyCache::Data::IsQList) + return QmlMetaProperty::List; + else + return QmlMetaProperty::Normal; + } else { + return QmlMetaProperty::InvalidProperty; } - return category; } /*! @@ -314,8 +297,21 @@ QmlMetaPropertyPrivate::propertyCategory() const */ const char *QmlMetaProperty::propertyTypeName() const { - if (!d->name.isEmpty() && d->object) { - return d->object->metaObject()->property(d->coreIdx).typeName(); + if (type() & ValueTypeProperty) { + + QmlEnginePrivate *ep = d->context?QmlEnginePrivate::get(d->context->engine()):0; + QmlValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[d->core.propType]; + else valueType = QmlValueTypeFactory::valueType(d->core.propType); + Q_ASSERT(valueType); + + const char *rv = valueType->metaObject()->property(d->valueTypeCoreIdx).typeName(); + + if (!ep) delete valueType; + + return rv; + } else if (d->object && type() & Property && d->core.isValid()) { + return d->object->metaObject()->property(d->core.coreIndex).typeName(); } else { return 0; } @@ -327,10 +323,13 @@ const char *QmlMetaProperty::propertyTypeName() const */ bool QmlMetaProperty::operator==(const QmlMetaProperty &other) const { - return d->name == other.d->name && - d->signal.signature() == other.d->signal.signature() && - d->type == other.d->type && - d->object == other.d->object; + // category is intentially omitted here as it is generated + // from the other members + return d->object == other.d->object && + d->core == other.d->core && + d->valueTypeCoreIdx == other.d->valueTypeCoreIdx && + d->valueTypePropType == other.d->valueTypePropType && + d->attachedFunc == other.d->attachedFunc; } /*! @@ -344,18 +343,19 @@ int QmlMetaProperty::propertyType() const int QmlMetaPropertyPrivate::propertyType() const { - int rv = QVariant::Invalid; - - if (!name.isEmpty()) { - if (propType == (int)QVariant::LastType) - rv = qMetaTypeId(); + uint type = q->type(); + if (type & QmlMetaProperty::ValueTypeProperty) { + return valueTypePropType; + } else if (type & QmlMetaProperty::Attached) { + return qMetaTypeId(); + } else if (type & QmlMetaProperty::Property) { + if (core.propType == (int)QVariant::LastType) + return qMetaTypeId(); else - rv = propType; - } else if (attachedFunc) { - rv = qMetaTypeId(); - } - - return rv; + return core.propType; + } else { + return QVariant::Invalid; + } } /*! @@ -363,7 +363,16 @@ int QmlMetaPropertyPrivate::propertyType() const */ QmlMetaProperty::Type QmlMetaProperty::type() const { - return (Type)d->type; + if (d->core.flags & QmlPropertyCache::Data::IsFunction) + return SignalProperty; + else if (d->attachedFunc != -1) + return Attached; + else if (d->valueTypeCoreIdx != -1) + return (Type)(Property | ValueTypeProperty); + else if (d->core.isValid()) + return (Type)(Property | ((d->isDefaultProperty)?Default:0)); + else + return Invalid; } /*! @@ -395,17 +404,16 @@ QObject *QmlMetaProperty::object() const */ QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other) { - d->name = other.d->name; - d->signal = other.d->signal; d->context = other.d->context; - d->coreIdx = other.d->coreIdx; - d->valueTypeIdx = other.d->valueTypeIdx; - d->valueTypeId = other.d->valueTypeId; - d->type = other.d->type; - d->attachedFunc = other.d->attachedFunc; d->object = other.d->object; - d->propType = other.d->propType; - d->category = other.d->category; + + d->isDefaultProperty = other.d->isDefaultProperty; + d->core = other.d->core; + + d->valueTypeCoreIdx = other.d->valueTypeCoreIdx; + d->valueTypePropType = other.d->valueTypePropType; + + d->attachedFunc = other.d->attachedFunc; return *this; } @@ -414,12 +422,14 @@ QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other) */ bool QmlMetaProperty::isWritable() const { - if (propertyCategory() == List || propertyCategory() == QmlList) + QmlMetaProperty::PropertyCategory category = propertyCategory(); + + if (category == List || category == QmlList) return true; else if (type() & SignalProperty) return true; - else if (!d->name.isEmpty() && d->object) - return d->object->metaObject()->property(d->coreIdx).isWritable(); + else if (d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex).isWritable(); else return false; } @@ -429,8 +439,8 @@ bool QmlMetaProperty::isWritable() const */ bool QmlMetaProperty::isDesignable() const { - if (!d->name.isEmpty() && d->object) - return d->object->metaObject()->property(d->coreIdx).isDesignable(); + if (type() & Property && d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex).isDesignable(); else return false; } @@ -449,6 +459,7 @@ bool QmlMetaProperty::isValid() const */ QStringList QmlMetaProperty::properties(QObject *obj) { + // ### What is this used for? if (!obj) return QStringList(); @@ -467,7 +478,23 @@ QStringList QmlMetaProperty::properties(QObject *obj) */ QString QmlMetaProperty::name() const { - return d->name; + if (type() & ValueTypeProperty) { + QString rv = d->core.name + QLatin1String("."); + + QmlEnginePrivate *ep = d->context?QmlEnginePrivate::get(d->context->engine()):0; + QmlValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[d->core.propType]; + else valueType = QmlValueTypeFactory::valueType(d->core.propType); + Q_ASSERT(valueType); + + rv += QLatin1String(valueType->metaObject()->property(d->valueTypeCoreIdx).name()); + + if (!ep) delete valueType; + + return rv; + } else { + return d->core.name; + } } /*! @@ -476,13 +503,26 @@ QString QmlMetaProperty::name() const */ QMetaProperty QmlMetaProperty::property() const { - if (d->object) - return d->object->metaObject()->property(d->coreIdx); + if (type() & Property && d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex); else return QMetaProperty(); } /*! + Return the QMetaMethod for this property if it is a SignalProperty, + otherwise returns an invalid QMetaMethod. +*/ +QMetaMethod QmlMetaProperty::method() const +{ + if (type() & SignalProperty && d->object) + return d->object->metaObject()->method(d->core.coreIndex); + else + return QMetaMethod(); +} + + +/*! Returns the binding associated with this property, or 0 if no binding exists. */ @@ -495,13 +535,13 @@ QmlAbstractBinding *QmlMetaProperty::binding() const if (!data) return 0; - if (!data->hasBindingBit(d->coreIdx)) + if (!data->hasBindingBit(d->core.coreIndex)) return 0; QmlAbstractBinding *binding = data->bindings; while (binding) { // ### This wont work for value types - if (binding->propertyIndex() == d->coreIdx) + if (binding->propertyIndex() == d->core.coreIndex) return binding; binding = binding->m_nextBinding; } @@ -527,11 +567,11 @@ QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding) const QmlDeclarativeData *data = QmlDeclarativeData::get(d->object, 0 != newBinding); - if (data && data->hasBindingBit(d->coreIdx)) { + if (data && data->hasBindingBit(d->core.coreIndex)) { QmlAbstractBinding *binding = data->bindings; while (binding) { // ### This wont work for value types - if (binding->propertyIndex() == d->coreIdx) { + if (binding->propertyIndex() == d->core.coreIndex) { binding->setEnabled(false); if (newBinding) @@ -594,15 +634,14 @@ QmlExpression *QmlMetaProperty::setSignalExpression(QmlExpression *expr) const } if (expr) { - QmlBoundSignal *signal = new QmlBoundSignal(d->object, d->signal, - d->object); + QmlBoundSignal *signal = new QmlBoundSignal(d->object, method(), d->object); return signal->setExpression(expr); } else { return 0; } } -void QmlMetaPropertyPrivate::findSignalInt(QObject *obj, const QString &name) +QMetaMethod QmlMetaPropertyPrivate::findSignal(QObject *obj, const QString &name) { const QMetaObject *mo = obj->metaObject(); @@ -613,12 +652,10 @@ void QmlMetaPropertyPrivate::findSignalInt(QObject *obj, const QString &name) int idx = methodName.indexOf(QLatin1Char('(')); methodName = methodName.left(idx); - if (methodName == name) { - signal = method; - coreIdx = ii; - return; - } + if (methodName == name) + return method; } + return QMetaMethod(); } QObject *QmlMetaPropertyPrivate::attachedObject() const @@ -643,7 +680,7 @@ QVariant QmlMetaProperty::read() const for (int ii = 0; ii < children.count(); ++ii) { QmlBoundSignal *sig = QmlBoundSignal::cast(children.at(ii)); - if (sig && sig->index() == d->coreIdx) + if (sig && sig->index() == d->core.coreIndex) return sig->expression()->expression(); } @@ -662,7 +699,7 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) for (int ii = 0; ii < children.count(); ++ii) { QmlBoundSignal *sig = QmlBoundSignal::cast(children.at(ii)); - if (sig && sig->index() == coreIdx) { + if (sig && sig->index() == core.coreIndex) { if (expr.isEmpty()) { sig->disconnect(); sig->deleteLater(); @@ -675,12 +712,13 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) if (!expr.isEmpty()) { // XXX scope - (void *)new QmlBoundSignal(qmlContext(object), expr, object, signal, object); + (void *)new QmlBoundSignal(qmlContext(object), expr, object, q->method(), object); } } QVariant QmlMetaPropertyPrivate::readValueProperty() { + uint type = q->type(); if (type & QmlMetaProperty::Attached) { return QVariant::fromValue(attachedObject()); @@ -689,22 +727,21 @@ QVariant QmlMetaPropertyPrivate::readValueProperty() QmlEnginePrivate *ep = context?QmlEnginePrivate::get(context->engine()):0; QmlValueType *valueType = 0; - if (ep) - valueType = ep->valueTypes[valueTypeId]; - else - valueType = QmlValueTypeFactory::valueType(valueTypeId); + if (ep) valueType = ep->valueTypes[core.propType]; + else valueType = QmlValueTypeFactory::valueType(core.propType); Q_ASSERT(valueType); - valueType->read(object, coreIdx); + valueType->read(object, core.coreIndex); + QVariant rv = - valueType->metaObject()->property(valueTypeIdx).read(valueType); - if (!ep) - delete valueType; + valueType->metaObject()->property(valueTypeCoreIdx).read(valueType); + + if (!ep) delete valueType; return rv; } else { - return object->metaObject()->property(coreIdx).read(object.data()); + return object->metaObject()->property(core.coreIndex).read(object.data()); } } @@ -712,40 +749,49 @@ QVariant QmlMetaPropertyPrivate::readValueProperty() void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, QmlMetaProperty::WriteSource source) { - QObject *object = this->object; - int coreIdx = this->coreIdx; - - QmlValueType *writeBack = 0; - QObject *writeBackObj = 0; - int writeBackIdx = -1; - bool deleteWriteBack = false; - // Remove any existing bindings on this property if (source != QmlMetaProperty::Binding) delete q->setBinding(0); + uint type = q->type(); if (type & QmlMetaProperty::ValueTypeProperty) { - QmlEnginePrivate *ep = context?static_cast(QObjectPrivate::get(context->engine())):0; + QmlEnginePrivate *ep = + context?static_cast(QObjectPrivate::get(context->engine())):0; + QmlValueType *writeBack = 0; if (ep) { - writeBack = ep->valueTypes[valueTypeId]; + writeBack = ep->valueTypes[core.propType]; } else { - writeBack = QmlValueTypeFactory::valueType(valueTypeId); - deleteWriteBack = true; + writeBack = QmlValueTypeFactory::valueType(core.propType); } - writeBackObj = this->object; - writeBackIdx = this->coreIdx; - writeBack->read(writeBackObj, writeBackIdx); - object = writeBack; - coreIdx = valueTypeIdx; + writeBack->read(object, core.coreIndex); + + QmlPropertyCache::Data data = core; + data.coreIndex = valueTypeCoreIdx; + data.propType = valueTypePropType; + write(writeBack, data, value, context); + + writeBack->write(object, core.coreIndex); + if (!ep) delete writeBack; + + } else { + + write(object, core, value, context); + } +} - QMetaProperty prop = object->metaObject()->property(coreIdx); +void QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data &property, + const QVariant &value, QmlContext *context) +{ + int coreIdx = property.coreIndex; - if (prop.isEnumType()) { + if (property.flags & QmlPropertyCache::Data::IsEnumType) { + QMetaProperty prop = object->metaObject()->property(property.coreIndex); QVariant v = value; - if (value.type() == QVariant::Double) { //enum values come through the script engine as doubles + // Enum values come through the script engine as doubles + if (value.type() == QVariant::Double) { double integral; double fractional = modf(value.toDouble(), &integral); if (qFuzzyCompare(fractional, (double)0.0)) @@ -753,19 +799,36 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, } prop.write(object, v); - if (writeBack) { - writeBack->write(writeBackObj, writeBackIdx); - if (deleteWriteBack) delete writeBack; - } return; } - int t = propertyType(); + int t = property.propType; int vt = value.userType(); - int category = propertyCategory(); - if (vt == t - && t != QVariant::Url) { // always resolve relative urls + if (t == QVariant::Url) { + + QUrl u; + bool found = false; + if (vt == QVariant::Url) { + u = value.toUrl(); + found = true; + } else if (vt == QVariant::ByteArray) { + u = QUrl(QLatin1String(value.toByteArray())); + found = true; + } else if (vt == QVariant::String) { + u = QUrl(value.toString()); + found = true; + } + + if (found) { + if (context && u.isRelative() && !u.isEmpty()) + u = context->baseUrl().resolved(u); + void *a[1]; + a[0] = &u; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + } + + } else if (vt == t) { void *a[1]; a[0] = (void *)value.constData(); @@ -773,9 +836,11 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, } else if (qMetaTypeId() == t) { - prop.write(object, value); + void *a[1]; + a[0] = (void *)&value; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); - } else if (category == QmlMetaProperty::Object) { + } else if (property.flags & QmlPropertyCache::Data::IsQObjectDerived) { QObject *o = QmlMetaType::toQObject(value); @@ -802,9 +867,10 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, } - } else if (category == QmlMetaProperty::List) { + } else if (property.flags & QmlPropertyCache::Data::IsQList) { int listType = QmlMetaType::listType(t); + QMetaProperty prop = object->metaObject()->property(property.coreIndex); if (value.userType() == qMetaTypeId >()) { const QList &list = @@ -822,9 +888,11 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, QmlMetaType::clear(listVar); QmlMetaType::append(listVar, value); } - } else if (category == QmlMetaProperty::QmlList) { + + } else if (property.flags & QmlPropertyCache::Data::IsQmlList) { // XXX - optimize! + QMetaProperty prop = object->metaObject()->property(property.coreIndex); QVariant list = prop.read(object); QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)list.constData(); @@ -854,118 +922,25 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, void *d = (void *)&obj; li->append(d); } - } else if (category == QmlMetaProperty::Normal) { - - bool found = false; - switch(t) { - case QVariant::Double: - { - double d; - if (vt == QVariant::Int) { - d = value.toInt(); - found = true; - } else if (vt == QVariant::UInt) { - d = value.toUInt(); - found = true; - } - - if (found) { - void *a[1]; - a[0] = &d; - QMetaObject::metacall(object, - QMetaObject::WriteProperty, - coreIdx, a); - } - } - break; - - case QVariant::Int: - { - int i; - if (vt == QVariant::Double) { - i = (int)value.toDouble(); - found = true; - } else if (vt == QVariant::UInt) { - i = (int)value.toUInt(); - found = true; - } - - if (found) { - void *a[1]; - a[0] = &i; - QMetaObject::metacall(object, - QMetaObject::WriteProperty, - coreIdx, a); - } - } - break; - - case QVariant::String: - { - QString s; - if (vt == QVariant::ByteArray) { - s = QLatin1String(value.toByteArray()); - found = true; - } - - if (found) { - void *a[1]; - a[0] = &s; - QMetaObject::metacall(object, - QMetaObject::WriteProperty, - coreIdx, a); - } - } - break; - - case QVariant::Url: - { - QUrl u; - if (vt == QVariant::Url) { - u = value.toUrl(); - found = true; - } else if (vt == QVariant::ByteArray) { - u = QUrl(QLatin1String(value.toByteArray())); - found = true; - } else if (vt == QVariant::String) { - u = QUrl(value.toString()); - found = true; - } + } else { + Q_ASSERT(vt != t); - if (found) { - if (context && u.isRelative() && !u.isEmpty()) - u = context->baseUrl().resolved(u); + QVariant v = value; + if (v.convert((QVariant::Type)t)) { + void *a[1]; + a[0] = (void *)v.constData(); + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + } else if ((uint)t >= QVariant::UserType && vt == QVariant::String) { + QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(t); + if (con) { + QVariant v = con(value.toString()); + if (v.userType() == t) { void *a[1]; - a[0] = &u; - QMetaObject::metacall(object, - QMetaObject::WriteProperty, - coreIdx, a); + a[0] = (void *)v.constData(); + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); } - } - break; - - - default: - { - if ((uint)t >= QVariant::UserType && vt == QVariant::String) { - QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(t); - if (con) { - QVariant v = con(value.toString()); - prop.write(object, v); - found = true; - } - } - } - break; } - if (!found) - prop.write(object, value); - } - - if (writeBack) { - writeBack->write(writeBackObj, writeBackIdx); - if (deleteWriteBack) delete writeBack; } } @@ -986,7 +961,7 @@ void QmlMetaProperty::write(const QVariant &value, WriteSource source) const d->writeSignalProperty(value); - } else if (d->coreIdx != -1) { + } else if (d->core.isValid()) { d->writeValueProperty(value, source); @@ -999,7 +974,7 @@ void QmlMetaProperty::write(const QVariant &value, WriteSource source) const bool QmlMetaProperty::hasChangedNotifier() const { if (type() & Property && !(type() & Attached) && d->object) { - return d->object->metaObject()->property(d->coreIdx).hasNotifySignal(); + return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal(); } return false; } @@ -1030,7 +1005,7 @@ bool QmlMetaProperty::connectNotifier(QObject *dest, int method) const if (!(type() & Property) || (type() & Attached) || !d->object) return false; - QMetaProperty prop = d->object->metaObject()->property(d->coreIdx); + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); if (prop.hasNotifySignal()) { return QMetaObject::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection); } else { @@ -1051,7 +1026,7 @@ bool QmlMetaProperty::connectNotifier(QObject *dest, const char *slot) const if (!(type() & Property) || (type() & Attached) || !d->object) return false; - QMetaProperty prop = d->object->metaObject()->property(d->coreIdx); + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); if (prop.hasNotifySignal()) { QByteArray signal(QByteArray("2") + prop.notifySignal().signature()); return QObject::connect(d->object, signal.constData(), dest, slot); @@ -1065,7 +1040,7 @@ bool QmlMetaProperty::connectNotifier(QObject *dest, const char *slot) const */ int QmlMetaProperty::coreIndex() const { - return d->coreIdx; + return d->core.coreIndex; } Q_GLOBAL_STATIC(QmlValueTypeFactory, qmlValueTypes); @@ -1080,17 +1055,17 @@ quint32 QmlMetaProperty::save() const if (type() & Attached) { rv = d->attachedFunc; } else if (type() != Invalid) { - rv = d->coreIdx; + rv = d->core.coreIndex; } Q_ASSERT(rv <= 0x7FF); Q_ASSERT(type() <= 0x3F); - Q_ASSERT(d->valueTypeIdx <= 0x7F); + Q_ASSERT(d->valueTypeCoreIdx <= 0x7F); rv |= (type() << 18); if (type() & ValueTypeProperty) - rv |= (d->valueTypeIdx << 11); + rv |= (d->valueTypeCoreIdx << 11); return rv; } @@ -1131,12 +1106,12 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) d->context = ctxt; id &= 0xFFFFFF; - d->type = id >> 18; + uint type = id >> 18; id &= 0xFFFF; - if (d->type & Attached) { + if (type & Attached) { d->attachedFunc = id; - } else if (d->type & ValueTypeProperty) { + } else if (type & ValueTypeProperty) { int coreIdx = id & 0x7FF; int valueTypeIdx = id >> 11; @@ -1147,46 +1122,31 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) QMetaProperty p2(valueType->metaObject()->property(valueTypeIdx)); - d->name = QLatin1String(p2.name()); - d->propType = p2.userType(); - d->coreIdx = coreIdx; - d->valueTypeIdx = valueTypeIdx; - d->valueTypeId = p.type(); - - } else if (d->type & Property) { + d->core.load(p); + d->valueTypeCoreIdx = valueTypeIdx; + d->valueTypePropType = p.userType(); + } else if (type & Property) { QmlPropertyCache *cache = enginePrivate?enginePrivate->cache(obj):0; - d->coreIdx = id; - if (cache) { QmlPropertyCache::Data *data = cache->property(id); - d->propType = data->propType; - d->name = data->name; + if (data) d->core = *data; } else { QMetaProperty p(obj->metaObject()->property(id)); - d->name = QLatin1String(p.name()); - d->propType = p.userType(); + d->core.load(p); } - } else if (d->type & SignalProperty) { - d->signal = obj->metaObject()->method(id); - d->coreIdx = id; + } else if (type & SignalProperty) { + + QMetaMethod method = obj->metaObject()->method(id); + d->core.load(method); } else { *this = QmlMetaProperty(); } } /*! - Return the QMetaMethod for this property if it is a SignalProperty, - otherwise returns an invalid QMetaMethod. -*/ -QMetaMethod QmlMetaProperty::method() const -{ - return d->signal; -} - -/*! \internal Creates a QmlMetaProperty for the property \a name of \a obj. Unlike @@ -1213,17 +1173,11 @@ QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData()); if (idx == -1) return QmlMetaProperty(); + QMetaProperty vtProp = typeObject->metaObject()->property(idx); - QmlMetaProperty p; - p.d->name = pathName + QLatin1String(".") + path.last(); - p.d->context = 0; - p.d->coreIdx = prop.coreIndex(); - p.d->valueTypeIdx = idx; - p.d->valueTypeId = prop.propertyType(); - p.d->type = QmlMetaProperty::ValueTypeProperty | - QmlMetaProperty::Property; - p.d->object = obj; - p.d->propType = typeObject->metaObject()->property(idx).userType(); + QmlMetaProperty p = prop; + p.d->valueTypeCoreIdx = idx; + p.d->valueTypePropType = vtProp.userType(); return p; } diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 3193aaf..729236b 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -54,7 +54,8 @@ // #include "qmlmetaproperty.h" -#include "private/qobject_p.h" +#include +#include QT_BEGIN_NAMESPACE @@ -63,36 +64,34 @@ class QmlMetaPropertyPrivate { public: QmlMetaPropertyPrivate() - : q(0), context(0), coreIdx(-1), valueTypeIdx(-1), valueTypeId(0), - type(QmlMetaProperty::Invalid), attachedFunc(-1), - object(0), propType(-1), category(QmlMetaProperty::Unknown) {} + : q(0), context(0), object(0), isDefaultProperty(false), valueTypeCoreIdx(-1), + valueTypePropType(0), attachedFunc(-1) {} + QmlMetaPropertyPrivate(const QmlMetaPropertyPrivate &other) - : q(0), name(other.name), signal(other.signal), context(other.context), - coreIdx(other.coreIdx), valueTypeIdx(other.valueTypeIdx), - valueTypeId(other.valueTypeId), type(other.type), - attachedFunc(other.attachedFunc), object(other.object), - propType(other.propType), category(other.category) {} + : q(0), context(other.context), object(other.object), + isDefaultProperty(other.isDefaultProperty), core(other.core), + valueTypeCoreIdx(other.valueTypeCoreIdx), + valueTypePropType(other.valueTypePropType), attachedFunc(other.attachedFunc) {} QmlMetaProperty *q; - - QString name; - QMetaMethod signal; QmlContext *context; - int coreIdx; - int valueTypeIdx; - int valueTypeId; - uint type; - int attachedFunc; QGuard object; - int propType; - mutable QmlMetaProperty::PropertyCategory category; + bool isDefaultProperty; + QmlPropertyCache::Data core; + + // Describes the "virtual" value-type sub-property. + int valueTypeCoreIdx; // The prop index of the access property on the value type wrapper + int valueTypePropType; // The QVariant::Type of access property on the value type wrapper + + // The attached property accessor + int attachedFunc; void initProperty(QObject *obj, const QString &name); void initDefault(QObject *obj); QObject *attachedObject() const; - void findSignalInt(QObject *, const QString &); + QMetaMethod findSignal(QObject *, const QString &); int propertyType() const; QmlMetaProperty::PropertyCategory propertyCategory() const; @@ -101,6 +100,7 @@ public: QVariant readValueProperty(); void writeValueProperty(const QVariant &, QmlMetaProperty::WriteSource); + static void write(QObject *, const QmlPropertyCache::Data &, const QVariant &, QmlContext *); static quint32 saveValueType(int, int); static quint32 saveProperty(int); diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index 95b819a..7d234fd 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -40,10 +40,48 @@ ****************************************************************************/ #include "qmlpropertycache_p.h" -#include "qmlengine_p.h" +#include +#include QT_BEGIN_NAMESPACE +void QmlPropertyCache::Data::load(const QMetaProperty &p) +{ + propType = p.userType(); + coreIndex = p.propertyIndex(); + notifyIndex = p.notifySignalIndex(); + name = QLatin1String(p.name()); + + if (p.isConstant()) + flags |= Data::IsConstant; + + if (propType == qMetaTypeId()) { + flags |= Data::IsQmlBinding; + } else if (p.isEnumType()) { + flags |= Data::IsEnumType; + } else { + QmlMetaType::TypeCategory cat = QmlMetaType::typeCategory(propType); + if (cat == QmlMetaType::Object) + flags |= Data::IsQObjectDerived; + else if (cat == QmlMetaType::List) + flags |= Data::IsQList; + else if (cat == QmlMetaType::QmlList) + flags |= Data::IsQmlList; + } +} + +void QmlPropertyCache::Data::load(const QMetaMethod &m) +{ + name = QLatin1String(m.signature()); + int parenIdx = name.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + name = name.left(parenIdx); + + coreIndex = m.methodIndex(); + flags |= Data::IsFunction; +} + + QmlPropertyCache::QmlPropertyCache() { } @@ -83,15 +121,7 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject QScriptDeclarativeClass::PersistentIdentifier *data = enginePriv->objectClass->createPersistentIdentifier(propName); - data->propType = p.userType(); - data->coreIndex = ii; - data->notifyIndex = p.notifySignalIndex(); - data->name = propName; - - if (p.isConstant()) - data->flags |= Data::IsConstant; - if (QmlMetaType::isObject(data->propType)) - data->flags |= Data::IsQObjectDerived; + data->load(p); cache->indexCache[ii] = data; @@ -118,12 +148,13 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject QScriptDeclarativeClass::PersistentIdentifier *data = enginePriv->objectClass->createPersistentIdentifier(methodName); + + data->load(m); + cache->stringCache.insert(methodName, data); cache->identifierCache.insert(data->identifier, data); data->addref(); data->addref(); - - data->flags |= Data::IsFunction; } return cache; diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index 21c8ef3..149d2a0 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -69,18 +69,40 @@ public: struct Data { inline Data(); + inline bool operator==(const Data &); - enum Flag { IsFunction = 0x00000001, + enum Flag { + // Can apply to all properties, except IsFunction + IsConstant = 0x00000004, + + // These are mutually exclusive + IsFunction = 0x00000001, IsQObjectDerived = 0x00000002, - IsConstant = 0x00000004 }; + IsEnumType = 0x00000008, + IsQmlList = 0x00000010, + IsQList = 0x00000020, + IsQmlBinding = 0x00000040 + }; Q_DECLARE_FLAGS(Flags, Flag) + bool isValid() const { return coreIndex != -1; } + Flags flags; int propType; int coreIndex; int notifyIndex; QString name; + + void load(const QMetaProperty &); + void load(const QMetaMethod &); + }; + +#if 0 + struct ValueTypeData { + int valueTypeCoreIdx; // The prop index of the access property on the value type wrapper + int valueTypePropType; // The QVariant::Type of access property on the value type wrapper }; +#endif static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); @@ -106,6 +128,15 @@ QmlPropertyCache::Data::Data() { } +bool QmlPropertyCache::Data::operator==(const QmlPropertyCache::Data::Data &other) +{ + return flags == other.flags && + propType == other.propType && + coreIndex == other.coreIndex && + notifyIndex == other.notifyIndex && + name == other.name; +} + QmlPropertyCache::Data * QmlPropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const { -- cgit v0.12 From 361a605e9269f3072c1f5597a8db0622cf3b116b Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Oct 2009 17:36:35 +1000 Subject: Read/write property directly from QmlObjectScriptClass --- src/declarative/qml/qmlcontext.cpp | 1 - src/declarative/qml/qmlobjectscriptclass.cpp | 110 +++++++++------------------ src/declarative/qml/qmlobjectscriptclass_p.h | 2 + src/declarative/qml/qmlpropertycache.cpp | 37 +++++++++ src/declarative/qml/qmlpropertycache_p.h | 16 ++-- 5 files changed, 83 insertions(+), 83 deletions(-) diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 1c9d177..5e74d1a 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -386,7 +386,6 @@ void QmlContextPrivate::setIdProperty(const QString &name, int idx, notifyIndex = q->metaObject()->methodCount(); } - propertyNames->add(name, idx); idValues[idx].priv = this; idValues[idx] = obj; } diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 0ae1809..28a808a 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -149,20 +149,19 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, } if (cache) { - QmlPropertyCache::Data *property = cache->property(name); - if (!property) return 0; - - if (flags == QScriptClass::HandlesReadAccess) { - lastData = property; - return QScriptClass::HandlesReadAccess; - } else if (property->propType > 0 && property->propType < QVariant::UserType) { - lastData = property; - return flags; - } + lastData = cache->property(name); + } else { + local = QmlPropertyCache::create(obj->metaObject(), toString(name)); + if (local.isValid()) + lastData = &local; } - // Fallback - return QmlEnginePrivate::get(engine)->queryObject(toString(name), &m_id, obj); + if (!lastData) return 0; + + QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess; + if (lastData->flags & QmlPropertyCache::Data::IsWritable) + rv |= QScriptClass::HandlesWriteAccess; + return rv; } QScriptValue QmlObjectScriptClass::property(const Object &object, const Identifier &name) @@ -175,35 +174,31 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name if (name == m_destroyId->identifier) return m_destroy; + Q_ASSERT(lastData); + Q_ASSERT(obj); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); - if (!obj) { - return QScriptValue(); - } else if (lastData) { + if (lastData->flags & QmlPropertyCache::Data::IsFunction) { + // ### Optimize + QScriptValue sobj = scriptEngine->newQObject(obj); + return sobj.property(toString(name)); + } else { + + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); + if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { + enginePriv->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); + } - if (lastData->flags & QmlPropertyCache::Data::IsFunction) { - // ### Optimize - QScriptValue sobj = scriptEngine->newQObject(obj); - return sobj.property(toString(name)); + if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { + QObject *rv = *(QObject **)var.constData(); + return newQObject(rv); } else { - QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); - if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { - enginePriv->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, - lastData->notifyIndex); - } - - if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { - QObject *rv = *(QObject **)var.constData(); - return newQObject(rv); - } else { - return qScriptValueFromValue(scriptEngine, var); - } + return qScriptValueFromValue(scriptEngine, var); } - } else { - return QmlEnginePrivate::get(engine)->propertyObject(toString(name), obj, m_id); } } @@ -219,51 +214,16 @@ void QmlObjectScriptClass::setProperty(QObject *obj, const QScriptValue &value) { Q_UNUSED(name); - Q_UNUSED(object); + + Q_ASSERT(obj); + Q_ASSERT(lastData); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); - if (!obj) { - return; - } else if (lastData) { - switch (lastData->propType) { - case 1: - { - bool b = value.toBoolean(); - void *a[1]; - a[0] = &b; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); - } - break; - - case 2: - { - int b = value.toInteger(); - void *a[1]; - a[0] = &b; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); - } - break; - - case 6: - { - double b = value.toNumber(); - void *a[1]; - a[0] = &b; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); - } - break; - - default: - { - QMetaProperty p = obj->metaObject()->property(lastData->coreIndex); - p.write(obj, value.toVariant()); - } - } - } else { - QmlEnginePrivate::get(engine)->setPropertyObject(value, m_id); - } + // ### Can well known types be optimized? + QVariant v = QmlScriptClass::toVariant(engine, value); + QmlMetaPropertyPrivate::write(obj, *lastData, v, enginePriv->currentExpression->context()); } QObject *QmlObjectScriptClass::toQObject(const Object &object, bool *ok) diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index c25718c..f126192 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -86,6 +86,8 @@ protected: private: uint m_id; QmlPropertyCache::Data *lastData; + QmlPropertyCache::Data local; + struct Dummy {}; PersistentIdentifier *m_destroyId; QScriptValue m_destroy; diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index 7d234fd..cc4c2ab 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -54,6 +54,8 @@ void QmlPropertyCache::Data::load(const QMetaProperty &p) if (p.isConstant()) flags |= Data::IsConstant; + if (p.isWritable()) + flags |= Data::IsWritable; if (propType == qMetaTypeId()) { flags |= Data::IsQmlBinding; @@ -100,6 +102,41 @@ QmlPropertyCache::~QmlPropertyCache() (*iter)->release(); } +QmlPropertyCache::Data QmlPropertyCache::create(const QMetaObject *metaObject, + const QString &property) +{ + Q_ASSERT(metaObject); + + QmlPropertyCache::Data rv; + + int propCount = metaObject->propertyCount(); + for (int ii = propCount - 1; ii >= 0; --ii) { + QMetaProperty p = metaObject->property(ii); + QString propName = QLatin1String(p.name()); + if (propName == property) { + rv.load(p); + return rv; + } + } + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 0; --ii) { + QMetaMethod m = metaObject->method(ii); + QString methodName = QLatin1String(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + if (methodName == property) { + rv.load(m); + return rv; + } + } + + return rv; +} + // ### Optimize - check engine for the parent meta object etc. QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject *metaObject) { diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index 149d2a0..82b8737 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -73,15 +73,16 @@ public: enum Flag { // Can apply to all properties, except IsFunction - IsConstant = 0x00000004, + IsConstant = 0x00000001, + IsWritable = 0x00000002, // These are mutually exclusive - IsFunction = 0x00000001, - IsQObjectDerived = 0x00000002, - IsEnumType = 0x00000008, - IsQmlList = 0x00000010, - IsQList = 0x00000020, - IsQmlBinding = 0x00000040 + IsFunction = 0x00000004, + IsQObjectDerived = 0x00000008, + IsEnumType = 0x00000010, + IsQmlList = 0x00000020, + IsQList = 0x00000040, + IsQmlBinding = 0x00000080 }; Q_DECLARE_FLAGS(Flags, Flag) @@ -105,6 +106,7 @@ public: #endif static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); + static Data create(const QMetaObject *, const QString &); inline Data *property(const QScriptDeclarativeClass::Identifier &id) const; Data *property(const QString &) const; -- cgit v0.12 From 02a248c9c57714d4ad1ba775d9e60a7f286f10c6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Oct 2009 18:52:53 +1000 Subject: Prevent writes to the global object Also add toString() method to qobjects --- demos/declarative/samegame/content/samegame.js | 28 ++++---- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlengine.cpp | 16 +++-- src/declarative/qml/qmlengine_p.h | 2 + src/declarative/qml/qmlglobalscriptclass.cpp | 94 ++++++++++++++++++++++++++ src/declarative/qml/qmlglobalscriptclass_p.h | 81 ++++++++++++++++++++++ src/declarative/qml/qmlobjectscriptclass.cpp | 83 +++++++++++++---------- src/declarative/qml/qmlobjectscriptclass_p.h | 8 +++ 8 files changed, 260 insertions(+), 58 deletions(-) create mode 100644 src/declarative/qml/qmlglobalscriptclass.cpp create mode 100644 src/declarative/qml/qmlglobalscriptclass_p.h diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index 4a9179b..09057eb 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -24,7 +24,7 @@ function timeStr(msecs) { function initBoard() { - for(i = 0; i= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) return; if(board[index(xIdx, yIdx)] == null) @@ -105,14 +105,14 @@ function floodFill(xIdx,yIdx,type) function shuffleDown() { //Fall down - for(xIdx=0; xIdx=0; yIdx--){ + for(var xIdx=0; xIdx=0; yIdx--){ if(board[index(xIdx,yIdx)] == null){ fallDist += 1; }else{ if(fallDist > 0){ - obj = board[index(xIdx,yIdx)]; + var obj = board[index(xIdx,yIdx)]; obj.targetY += fallDist * tileSize; board[index(xIdx,yIdx+fallDist)] = obj; board[index(xIdx,yIdx)] = null; @@ -143,8 +143,8 @@ function shuffleDown() function victoryCheck() { //awards bonuses for no tiles left - deservesBonus = true; - for(xIdx=maxX-1; xIdx>=0; xIdx--) + var deservesBonus = true; + for(var xIdx=maxX-1; xIdx>=0; xIdx--) if(board[index(xIdx, maxY - 1)] != null) deservesBonus = false; if(deservesBonus) @@ -166,7 +166,7 @@ function floodMoveCheck(xIdx, yIdx, type) return false; if(board[index(xIdx, yIdx)] == null) return false; - myType = board[index(xIdx, yIdx)].type; + var myType = board[index(xIdx, yIdx)].type; if(type == myType) return true; return floodMoveCheck(xIdx + 1, yIdx, myType) || @@ -174,7 +174,7 @@ function floodMoveCheck(xIdx, yIdx, type) } function createBlock(xIdx,yIdx){ - if(component==null) + if(component==null) component = createComponent(tileSrc); // Note that we don't wait for the component to become ready. This will @@ -182,7 +182,7 @@ function createBlock(xIdx,yIdx){ // not be ready immediately. There is a statusChanged signal on the // component you could use if you want to wait to load remote files. if(component.isReady){ - dynamicObject = component.createObject(); + var dynamicObject = component.createObject(); if(dynamicObject == null){ print("error creating block"); print(component.errorsString()); diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 1a6dad3..eb761e3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -38,7 +38,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlpropertycache.cpp \ qml/qmlintegercache.cpp \ qml/qmlobjectscriptclass.cpp \ - qml/qmlcontextscriptclass.cpp + qml/qmlcontextscriptclass.cpp \ + qml/qmlglobalscriptclass.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -94,7 +95,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlpropertycache_p.h \ qml/qmlintegercache_p.h \ qml/qmlobjectscriptclass_p.h \ - qml/qmlcontextscriptclass_p.h + qml/qmlcontextscriptclass_p.h \ + qml/qmlglobalscriptclass_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index d680fa1..4afd245 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef QT_SCRIPTTOOLS_LIB #include @@ -156,7 +157,7 @@ static QString userLocalDataPath(const QString& app) QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : rootContext(0), currentExpression(0), - isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), + isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), globalClass(0), nodeListClass(0), namedNodeMapClass(0), sqlQueryClass(0), scriptEngine(this), rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1) { @@ -183,6 +184,14 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) qtObject.setProperty(QLatin1String("lighter"), scriptEngine.newFunction(QmlEnginePrivate::lighter, 1)); qtObject.setProperty(QLatin1String("darker"), scriptEngine.newFunction(QmlEnginePrivate::darker, 1)); qtObject.setProperty(QLatin1String("tint"), scriptEngine.newFunction(QmlEnginePrivate::tint, 2)); + + scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), + scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), + scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); + + //scriptEngine.globalObject().setScriptClass(new QmlGlobalScriptClass(&scriptEngine)); + globalClass = new QmlGlobalScriptClass(&scriptEngine); } QmlEnginePrivate::~QmlEnginePrivate() @@ -250,11 +259,6 @@ void QmlEnginePrivate::init() } #endif - scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), - scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); - scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), - scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); - if (QCoreApplication::instance()->thread() == q->thread() && QmlEngineDebugServer::isDebuggingEnabled()) { qmlEngineDebugServer(); diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 764cc6c..231388d 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -151,6 +151,8 @@ public: QmlObjectScriptClass *objectClass; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; + // Global script class + QScriptClass *globalClass; // Used by DOM Core 3 API QScriptClass *nodeListClass; QScriptClass *namedNodeMapClass; diff --git a/src/declarative/qml/qmlglobalscriptclass.cpp b/src/declarative/qml/qmlglobalscriptclass.cpp new file mode 100644 index 0000000..0ade5ee --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlglobalscriptclass_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/* + Used to prevent any writes to the global object. +*/ +QmlGlobalScriptClass::QmlGlobalScriptClass(QScriptEngine *engine) +: QScriptClass(engine) +{ + QScriptValue v = engine->newObject(); + globalObject = engine->globalObject(); + + QScriptValueIterator iter(globalObject); + while (iter.hasNext()) { + iter.next(); + v.setProperty(iter.scriptName(), iter.value()); + } + + v.setScriptClass(this); + engine->setGlobalObject(v); +} + +QScriptClass::QueryFlags +QmlGlobalScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + return HandlesReadAccess | HandlesWriteAccess; +} + +QScriptValue +QmlGlobalScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ + return engine()->undefinedValue(); +} + +void QmlGlobalScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, const QScriptValue &value) +{ + QString error = QLatin1String("Invalid write to global property \"") + + name.toString() + QLatin1String("\""); + engine()->currentContext()->throwError(error); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlglobalscriptclass_p.h b/src/declarative/qml/qmlglobalscriptclass_p.h new file mode 100644 index 0000000..1b58f1e --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLGLOBALSCRIPTCLASS_P_H +#define QMLGLOBALSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QmlGlobalScriptClass : public QScriptClass +{ +public: + QmlGlobalScriptClass(QScriptEngine *); + + virtual QueryFlags queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id); + + virtual QScriptValue property(const QScriptValue &object, + const QScriptString &name, uint id); + + virtual void setProperty(QScriptValue &object, const QScriptString &name, + uint id, const QScriptValue &value); + +private: + QScriptValue globalObject; +}; + +QT_END_NAMESPACE + +#endif // QMLGLOBALSCRIPTCLASS_P_H diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 28a808a..bb5f191 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -51,40 +51,6 @@ struct ObjectData { QGuard object; }; -static QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - QString ret = QLatin1String("Qml Object, "); - if(obj){ - //###Should this be designer or developer details? Dev for now. - //TODO: Can we print the id too? - ret += QLatin1String("\""); - ret += obj->objectName(); - ret += QLatin1String("\" "); - ret += QLatin1String(obj->metaObject()->className()); - ret += QLatin1String("(0x"); - ret += QString::number((quintptr)obj,16); - ret += QLatin1String(")"); - }else{ - ret += QLatin1String("null"); - } - return engine->newVariant(ret); -} - -static QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().toQObject(); - if(obj){ - int delay = 0; - if(context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - obj->deleteLater(); - //### Should this be delayed as well? - context->thisObject().setData(QScriptValue(engine, 0)); - } - return engine->nullValue(); -} - /* The QmlObjectScriptClass handles property access for QObjects via QtScript. It is also used to provide a more useful API in @@ -97,8 +63,10 @@ QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) engine = bindEngine; QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); - m_destroy = scriptEngine->newFunction(QmlObjectDestroy); + m_destroy = scriptEngine->newFunction(destroy); m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); + m_toString = scriptEngine->newFunction(tostring); + m_toStringId = createPersistentIdentifier(QLatin1String("toString")); } QmlObjectScriptClass::~QmlObjectScriptClass() @@ -132,7 +100,8 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, Q_UNUSED(flags); lastData = 0; - if (name == m_destroyId->identifier) + if (name == m_destroyId->identifier || + name == m_toStringId->identifier) return QScriptClass::HandlesReadAccess; if (!obj) @@ -173,6 +142,8 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name { if (name == m_destroyId->identifier) return m_destroy; + else if (name == m_toStringId->identifier) + return m_toString; Q_ASSERT(lastData); Q_ASSERT(obj); @@ -240,4 +211,44 @@ void QmlObjectScriptClass::destroyed(const Object &object) delete data; } +QScriptValue QmlObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + + QString ret; + if(obj){ + QString objectName = obj->objectName(); + + ret += QLatin1String(obj->metaObject()->className()); + ret += QLatin1String("(0x"); + ret += QString::number((quintptr)obj,16); + + if (!objectName.isEmpty()) { + ret += QLatin1String(", \""); + ret += objectName; + ret += QLatin1String("\""); + } + + ret += QLatin1String(")"); + }else{ + ret += QLatin1String("null"); + } + return QScriptValue(ret); +} + +QScriptValue QmlObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + if(obj){ + int delay = 0; + if(context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + obj->deleteLater(); + //### Should this be delayed as well? + context->thisObject().setData(QScriptValue(engine, 0)); + } + return engine->nullValue(); +} + + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index f126192..cd67fac 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE class QmlEngine; +class QScriptContext; +class QScriptEngine; class QmlObjectScriptClass : public QScriptDeclarativeClass { public: @@ -90,7 +92,13 @@ private: struct Dummy {}; PersistentIdentifier *m_destroyId; + PersistentIdentifier *m_toStringId; QScriptValue m_destroy; + QScriptValue m_toString; + + static QScriptValue tostring(QScriptContext *context, QScriptEngine *engine); + static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine); + QmlEngine *engine; }; -- cgit v0.12 From 15498e4c5990e934e5f2a3ee27f71c020e277e56 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 10:04:35 +1000 Subject: Only start timer if it isn't already active --- src/corelib/animation/qabstractanimation.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 6bbd801..4c68ee7 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -231,7 +231,8 @@ void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation) Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer); QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true; animationsToStart << animation; - startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); + if (!startStopAnimationTimer.isActive()) + startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); } void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) @@ -250,7 +251,8 @@ void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) } else { animationsToStart.removeOne(animation); } - QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false; + if (!startStopAnimationTimer.isActive()) + startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); } void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) -- cgit v0.12 From b3605d7f45c1cdb61bbd2a572e58bd29aaea6956 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 10:49:14 +1000 Subject: API changes --- src/script/bridge/qscriptdeclarativeclass.cpp | 107 ++++++++++++++++++-------- src/script/bridge/qscriptdeclarativeclass_p.h | 33 ++++---- 2 files changed, 87 insertions(+), 53 deletions(-) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index c017e13..371a3c3 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -51,39 +51,38 @@ QT_BEGIN_NAMESPACE -class QScriptDeclarativeClassPrivate +QScriptDeclarativeClass::PersistentIdentifier::PersistentIdentifier() { -public: - QScriptDeclarativeClassPrivate() {} - - QScriptEngine *engine; - QScriptDeclarativeClass *q_ptr; -}; + new (&d) JSC::Identifier(); +} -void QScriptDeclarativeClass::destroyPersistentIdentifier(void **d) +QScriptDeclarativeClass::PersistentIdentifier::~PersistentIdentifier() { - ((JSC::Identifier *)d)->JSC::Identifier::~Identifier(); + ((JSC::Identifier &)d).JSC::Identifier::~Identifier(); } -void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, const QString &str) +QScriptDeclarativeClass::PersistentIdentifier::PersistentIdentifier(const PersistentIdentifier &other) { - QScriptEnginePrivate *p = - static_cast(QObjectPrivate::get(d_ptr->engine)); - JSC::ExecState* exec = p->currentFrame; + identifier = other.identifier; + new (&d) JSC::Identifier((JSC::Identifier &)(other.d)); +} - new (d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); - *i = (Identifier)((JSC::Identifier *)d)->ustring().rep(); +QScriptDeclarativeClass::PersistentIdentifier & +QScriptDeclarativeClass::PersistentIdentifier::operator=(const PersistentIdentifier &other) +{ + identifier = other.identifier; + ((JSC::Identifier &)d) = (JSC::Identifier &)(other.d); + return *this; } -void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, const Identifier &id) +class QScriptDeclarativeClassPrivate { - QScriptEnginePrivate *p = - static_cast(QObjectPrivate::get(d_ptr->engine)); - JSC::ExecState* exec = p->currentFrame; +public: + QScriptDeclarativeClassPrivate() {} - new (d) JSC::Identifier(exec, (JSC::UString::Rep *)id); - *i = id; -} + QScriptEngine *engine; + QScriptDeclarativeClass *q_ptr; +}; QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine) : d_ptr(new QScriptDeclarativeClassPrivate) @@ -132,6 +131,51 @@ QScriptDeclarativeClass::Object QScriptDeclarativeClass::object(const QScriptVal return static_cast(delegate)->object(); } +QScriptValue QScriptDeclarativeClass::function(const QScriptValue &v, const Identifier &name) +{ + QScriptValuePrivate *d = QScriptValuePrivate::get(v); + + if (!d->isObject()) + return QScriptValue(); + + JSC::ExecState *exec = d->engine->currentFrame; + JSC::JSObject *object = d->jscValue.getObject(); + JSC::PropertySlot slot(const_cast(object)); + JSC::JSValue result; + + JSC::Identifier id(exec, (JSC::UString::Rep *)name); + + if (const_cast(object)->getOwnPropertySlot(exec, id, slot)) { + result = slot.getValue(exec, id); + if (QScript::isFunction(result)) + return d->engine->scriptValueFromJSCValue(result); + } + + return QScriptValue(); +} + +QScriptValue QScriptDeclarativeClass::property(const QScriptValue &v, const Identifier &name) +{ + QScriptValuePrivate *d = QScriptValuePrivate::get(v); + + if (!d->isObject()) + return QScriptValue(); + + JSC::ExecState *exec = d->engine->currentFrame; + JSC::JSObject *object = d->jscValue.getObject(); + JSC::PropertySlot slot(const_cast(object)); + JSC::JSValue result; + + JSC::Identifier id(exec, (JSC::UString::Rep *)name); + + if (const_cast(object)->getOwnPropertySlot(exec, id, slot)) { + result = slot.getValue(exec, id); + return d->engine->scriptValueFromJSCValue(result); + } + + return QScriptValue(); +} + QScriptDeclarativeClass::~QScriptDeclarativeClass() { } @@ -141,34 +185,31 @@ QScriptEngine *QScriptDeclarativeClass::engine() const return d_ptr->engine; } -/* -QScriptDeclarativeClass::PersistentIdentifier * +QScriptDeclarativeClass::PersistentIdentifier QScriptDeclarativeClass::createPersistentIdentifier(const QString &str) { QScriptEnginePrivate *p = static_cast(QObjectPrivate::get(d_ptr->engine)); JSC::ExecState* exec = p->currentFrame; - PersistentIdentifierPrivate *rv = new PersistentIdentifierPrivate; - rv->identifierValue = JSC::Identifier(exec, (UChar *)str.constData(), str.size()); - rv->identifier = (void *)rv->identifierValue.ustring().rep(); + PersistentIdentifier rv(true); + new (&rv.d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); + rv.identifier = (void *)((JSC::Identifier &)rv.d).ustring().rep(); return rv; } -QScriptDeclarativeClass::PersistentIdentifier * +QScriptDeclarativeClass::PersistentIdentifier QScriptDeclarativeClass::createPersistentIdentifier(const Identifier &id) { QScriptEnginePrivate *p = static_cast(QObjectPrivate::get(d_ptr->engine)); JSC::ExecState* exec = p->currentFrame; - PersistentIdentifierPrivate *rv = new PersistentIdentifierPrivate; - rv->identifierValue = JSC::Identifier(exec, (JSC::UString::Rep *)id); - rv->identifier = (void *)rv->identifierValue.ustring().rep(); + PersistentIdentifier rv(true); + new (&rv.d) JSC::Identifier(exec, (JSC::UString::Rep *)id); + rv.identifier = (void *)((JSC::Identifier &)rv.d).ustring().rep(); return rv; } -*/ - QString QScriptDeclarativeClass::toString(const Identifier &identifier) { diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index a00a286..16f6942 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -71,15 +71,22 @@ public: static QScriptDeclarativeClass *scriptClass(const QScriptValue &); static Object object(const QScriptValue &); - template - class PersistentIdentifier :