From 067b419199b369b6c81fa1ae387257aa87cab20c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 6 Oct 2009 15:31:56 +1000 Subject: Improve scope handling --- src/declarative/qml/qmlcontext.cpp | 11 +---- src/declarative/qml/qmlcontext_p.h | 3 +- src/declarative/qml/qmlcontextscriptclass.cpp | 45 +++++++++++++++++---- src/declarative/qml/qmlcontextscriptclass_p.h | 6 +++ src/declarative/qml/qmlexpression.cpp | 22 +++++----- src/declarative/qml/qmlobjectscriptclass.cpp | 56 ++++++++++++++++---------- src/declarative/qml/qmlobjectscriptclass_p.h | 3 +- src/declarative/qml/qmltypenamescriptclass.cpp | 3 +- src/declarative/util/qmlscript.cpp | 6 +-- 9 files changed, 96 insertions(+), 59 deletions(-) diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 968597c..a1eb5de 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -103,16 +103,7 @@ void QmlContextPrivate::init() //set scope chain QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - 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; - if (!parent) - scopeChain.append(scriptEngine->globalObject()); - else - scopeChain = parent->d_func()->scopeChain; - scopeChain.prepend(scopeObj); + scriptValue = QmlEnginePrivate::get(engine)->contextClass->newContext(q); } void QmlContextPrivate::addDefaultObject(QObject *object, Priority priority) diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index 8fd2e92..22e5895 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -85,14 +85,13 @@ public: bool isInternal; QmlIntegerCache *propertyNames; -// QHash propertyNames; QList propertyValues; int notifyIndex; QObjectList defaultObjects; int highPriorityCount; - QScriptValueList scopeChain; + QScriptValue scriptValue; QList scripts; diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index 226c34c..6d2c58c 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -72,51 +72,80 @@ QScriptValue QmlContextScriptClass::newContext(QmlContext *context) return newObject(scriptEngine, this, new ContextData(context)); } +QmlContext *QmlContextScriptClass::contextFromValue(const QScriptValue &v) +{ + if (scriptClass(v) != this) + return 0; + + ContextData *data = (ContextData *)object(v); + return data->context; +} + +#include QScriptClass::QueryFlags QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags flags) { Q_UNUSED(flags); + lastContext = 0; + lastData = 0; lastPropertyIndex = -1; lastDefaultObject = -1; - lastData = 0; QmlContext *bindContext = ((ContextData *)object)->context.data(); if (!bindContext) return 0; + while (bindContext) { + QScriptClass::QueryFlags rv = queryProperty(bindContext, name, flags); + if (rv) return rv; + bindContext = bindContext->parentContext(); + } + + return 0; +} + +QScriptClass::QueryFlags +QmlContextScriptClass::queryProperty(QmlContext *bindContext, const Identifier &name, + QScriptClass::QueryFlags flags) +{ QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); lastPropertyIndex = cp->propertyNames?cp->propertyNames->value(name):-1; - if (lastPropertyIndex != -1) + if (lastPropertyIndex != -1) { + lastContext = bindContext; return QScriptClass::HandlesReadAccess; + } - if (ep->currentExpression && cp->imports && bindContext == ep->currentExpression->context()) { + if (cp->imports) { QmlTypeNameCache::Data *data = cp->imports->data(name); if (data) { lastData = data; + lastContext = bindContext; return QScriptClass::HandlesReadAccess; } } for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { QScriptClass::QueryFlags rv = - ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, - QmlObjectScriptClass::SkipAttachedProperties); + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, 0); if (rv) { lastDefaultObject = ii; + lastContext = bindContext; return rv; } } for (int ii = 0; ii < cp->scripts.count(); ++ii) { lastFunction = QScriptDeclarativeClass::function(cp->scripts.at(ii), name); - if (lastFunction.isValid()) + if (lastFunction.isValid()) { + lastContext = bindContext; return QScriptClass::HandlesReadAccess; + } } return 0; } @@ -125,7 +154,7 @@ QScriptValue QmlContextScriptClass::property(Object *object, const Identifier &n { Q_UNUSED(object); - QmlContext *bindContext = ((ContextData *)object)->context.data(); + QmlContext *bindContext = lastContext; Q_ASSERT(bindContext); QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); @@ -170,7 +199,7 @@ void QmlContextScriptClass::setProperty(Object *object, const Identifier &name, { Q_ASSERT(lastDefaultObject != -1); - QmlContext *bindContext = ((ContextData *)object)->context.data(); + QmlContext *bindContext = lastContext; Q_ASSERT(bindContext); QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h index acb8926..761a115 100644 --- a/src/declarative/qml/qmlcontextscriptclass_p.h +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -69,6 +69,8 @@ public: QScriptValue newContext(QmlContext *); + QmlContext *contextFromValue(const QScriptValue &); + protected: virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); @@ -76,8 +78,12 @@ protected: virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); private: + QScriptClass::QueryFlags queryProperty(QmlContext *, const Identifier &, + QScriptClass::QueryFlags flags); + QmlEngine *engine; + QmlContext *lastContext; QmlTypeNameCache::Data *lastData; int lastPropertyIndex; int lastDefaultObject; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 61c14a9..e1c7afe 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -82,17 +82,20 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, int progIdx = *(data + 1); QmlEngine *engine = ctxt->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(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)); + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(ctxtPriv->scriptValue); + if (me) + scriptContext->pushScope(ep->objectClass->newQObject(me)); expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]); + expressionFunctionValid = true; scriptEngine->popContext(); } @@ -239,9 +242,8 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QmlContextPrivate *ctxtPriv = context()->d_func(); QmlEngine *engine = context()->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - if (me) - ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, me); if (secondaryScope) ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, secondaryScope); @@ -250,9 +252,11 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) if (!expressionFunctionValid) { - QScriptContext *scriptContext = scriptEngine->pushContext(); - for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) - scriptContext->pushScope(ctxtPriv->scopeChain.at(i)); + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(ctxtPriv->scriptValue); + + if (me) + scriptContext->pushScope(ep->objectClass->newQObject(me)); if (expressionRewritten) { expressionFunction = scriptEngine->evaluate(expression, fileName, line); @@ -283,8 +287,6 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) } } - if (me) - ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); if (secondaryScope) ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 330eddd..2d69590 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -80,6 +80,9 @@ QScriptValue QmlObjectScriptClass::newQObject(QObject *object) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + if (!object) + return newObject(scriptEngine, this, new ObjectData(object)); + QmlDeclarativeData *ddata = QmlDeclarativeData::get(object, true); if (!ddata->scriptValue.isValid()) { @@ -101,12 +104,12 @@ QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags flags) { - return queryProperty(toQObject(object), name, flags); + return queryProperty(toQObject(object), name, flags, 0); } QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, - QScriptClass::QueryFlags flags, QueryMode mode) + QScriptClass::QueryFlags flags, QmlContext *evalContext) { Q_UNUSED(flags); lastData = 0; @@ -120,21 +123,7 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, return 0; QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); - - if (mode == IncludeAttachedProperties) { - QmlContext *evalContext = enginePrivate->currentExpression->context(); - QmlContextPrivate *cp = QmlContextPrivate::get(evalContext); - // ### Check for attached properties - - if (cp->imports) { - QmlTypeNameCache::Data *data = cp->imports->data(name); - if (data) { - lastTNData = data; - return QScriptClass::HandlesReadAccess; - } - } - - } + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QmlPropertyCache *cache = 0; QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); @@ -153,12 +142,35 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, lastData = &local; } - if (!lastData) return 0; + if (lastData) { + QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess; + if (lastData->flags & QmlPropertyCache::Data::IsWritable) + rv |= QScriptClass::HandlesWriteAccess; + return rv; + } + + if (!evalContext && context) { + // Global object, QScriptContext activation object, QmlContext object + QScriptValue scopeNode = scopeChainValue(context, 3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass); + + evalContext = enginePrivate->contextClass->contextFromValue(scopeNode); + } + + if (evalContext) { + QmlContextPrivate *cp = QmlContextPrivate::get(evalContext); + + if (cp->imports) { + QmlTypeNameCache::Data *data = cp->imports->data(name); + if (data) { + lastTNData = data; + return QScriptClass::HandlesReadAccess; + } + } + } - QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess; - if (lastData->flags & QmlPropertyCache::Data::IsWritable) - rv |= QScriptClass::HandlesWriteAccess; - return rv; + return 0; } QScriptValue QmlObjectScriptClass::property(Object *object, const Identifier &name) diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index 6de63ca..3fcf009 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -63,6 +63,7 @@ QT_BEGIN_NAMESPACE class QmlEngine; class QScriptContext; class QScriptEngine; +class QmlContext; class QmlObjectScriptClass : public QScriptDeclarativeClass { public: @@ -76,7 +77,7 @@ public: QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, QScriptClass::QueryFlags flags, - QueryMode = IncludeAttachedProperties); + QmlContext *evalContext); QScriptValue property(QObject *, const Identifier &); void setProperty(QObject *, const Identifier &name, const QScriptValue &); diff --git a/src/declarative/qml/qmltypenamescriptclass.cpp b/src/declarative/qml/qmltypenamescriptclass.cpp index 4e1ac4b..c0613d1 100644 --- a/src/declarative/qml/qmltypenamescriptclass.cpp +++ b/src/declarative/qml/qmltypenamescriptclass.cpp @@ -131,8 +131,7 @@ QmlTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, // Must be an attached property object = qmlAttachedPropertiesObjectById(data->type->index(), data->object); if (!object) return 0; - return ep->objectClass->queryProperty(object, name, flags, - QmlObjectScriptClass::SkipAttachedProperties); + return ep->objectClass->queryProperty(object, name, flags, 0); } } diff --git a/src/declarative/util/qmlscript.cpp b/src/declarative/util/qmlscript.cpp index 2031a54..5d58f64 100644 --- a/src/declarative/util/qmlscript.cpp +++ b/src/declarative/util/qmlscript.cpp @@ -178,10 +178,8 @@ void QmlScriptPrivate::addScriptToEngine(const QString &script, const QString &s QmlContext *context = qmlContext(q); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - QScriptContext *scriptContext = scriptEngine->pushContext(); - for (int i = context->d_func()->scopeChain.size() - 1; i >= 0; --i) { - scriptContext->pushScope(context->d_func()->scopeChain.at(i)); - } + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(QmlContextPrivate::get(context)->scriptValue); QScriptValue scope = scriptEngine->newObject(); scriptContext->pushScope(scope); -- cgit v0.12