diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2017-05-31 12:05:26 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2017-05-31 12:05:39 +0200 |
commit | dece229a7c2284598c36fb668de766309a6893cf (patch) | |
tree | 6e34cfa52416b2f27d2fa0631cf34f8ffd171be4 /src/qml/jsruntime/qv4qobjectwrapper.cpp | |
parent | e2520ff76be49c5aa917741cc6a380fe1549e47d (diff) | |
parent | c158ca8be49a75026e83751dfd825c5bdd63189a (diff) |
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Change-Id: Iea0bb0788357bc615d0e9ea411087114b8b3b720
Diffstat (limited to 'src/qml/jsruntime/qv4qobjectwrapper.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 252 |
1 files changed, 187 insertions, 65 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 1dd90995d3..83730d632a 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -74,9 +74,14 @@ #include <QtCore/qtimer.h> #include <QtCore/qatomic.h> #include <QtCore/qmetaobject.h> +#include <QtCore/qabstractitemmodel.h> +#include <QtCore/qloggingcategory.h> +#include <vector> QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg) + // The code in this file does not violate strict aliasing, but GCC thinks it does // so turn off the warnings for us to have a clean build QT_WARNING_DISABLE_GCC("-Wstrict-aliasing") @@ -202,19 +207,61 @@ void QObjectWrapper::initializeBindings(ExecutionEngine *engine) QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const { + QObject *o = d()->object(); + return findProperty(engine, o, qmlContext, name, revisionMode, local); +} + +QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) +{ Q_UNUSED(revisionMode); - QQmlData *ddata = QQmlData::get(d()->object(), false); - if (!ddata) - return 0; + QQmlData *ddata = QQmlData::get(o, false); QQmlPropertyData *result = 0; if (ddata && ddata->propertyCache) - result = ddata->propertyCache->property(name, d()->object(), qmlContext); + result = ddata->propertyCache->property(name, o, qmlContext); else - result = QQmlPropertyCache::property(engine->jsEngine(), d()->object(), name, qmlContext, *local); + result = QQmlPropertyCache::property(engine->jsEngine(), o, name, qmlContext, *local); return result; } +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired) +{ + QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex())); + + if (property->isFunction() && !property->isVarProperty()) { + if (property->isVMEFunction()) { + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); + Q_ASSERT(vmemo); + return vmemo->vmeMethod(property->coreIndex()); + } else if (property->isV4Function()) { + Scope scope(engine); + ScopedContext global(scope, engine->qmlContext()); + if (!global) + global = engine->rootContext(); + return QV4::QObjectMethod::create(global, object, property->coreIndex()); + } else if (property->isSignalHandler()) { + QmlSignalHandler::initProto(engine); + return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue(); + } else { + ExecutionContext *global = engine->rootContext(); + return QV4::QObjectMethod::create(global, object, property->coreIndex()); + } + } + + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + + if (captureRequired && ep && ep->propertyCapture && !property->isConstant()) + ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex()); + + if (property->isVarProperty()) { + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); + Q_ASSERT(vmemo); + return vmemo->vmeProperty(property->coreIndex()); + } else { + return loadProperty(engine, object, *property); + } +} + ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, bool includeImports) const { @@ -250,11 +297,11 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String if (r.scriptIndex != -1) { return QV4::Encode::undefined(); } else if (r.type) { - return QmlTypeWrapper::create(v4, d()->object(), - r.type, Heap::QmlTypeWrapper::ExcludeEnums); + return QQmlTypeWrapper::create(v4, d()->object(), + r.type, Heap::QQmlTypeWrapper::ExcludeEnums); } else if (r.importNamespace) { - return QmlTypeWrapper::create(v4, d()->object(), - qmlContext->imports, r.importNamespace, Heap::QmlTypeWrapper::ExcludeEnums); + return QQmlTypeWrapper::create(v4, d()->object(), + qmlContext->imports, r.importNamespace, Heap::QQmlTypeWrapper::ExcludeEnums); } Q_ASSERT(!"Unreachable"); } @@ -279,42 +326,19 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String return getProperty(v4, d()->object(), result); } -ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired) +ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired) { - QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex())); - - if (property->isFunction() && !property->isVarProperty()) { - if (property->isVMEFunction()) { - QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); - Q_ASSERT(vmemo); - return vmemo->vmeMethod(property->coreIndex()); - } else if (property->isV4Function()) { - Scope scope(engine); - ScopedContext global(scope, engine->qmlContext()); - if (!global) - global = engine->rootContext(); - return QV4::QObjectMethod::create(global, object, property->coreIndex()); - } else if (property->isSignalHandler()) { - QmlSignalHandler::initProto(engine); - return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue(); - } else { - ExecutionContext *global = engine->rootContext(); - return QV4::QObjectMethod::create(global, object, property->coreIndex()); - } - } - - QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; - - if (captureRequired && ep && ep->propertyCapture && !property->isConstant()) - ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex()); + if (QQmlData::wasDeleted(object)) + return QV4::Encode::null(); + QQmlData *ddata = QQmlData::get(object, /*create*/false); + if (!ddata) + return QV4::Encode::undefined(); - if (property->isVarProperty()) { - QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); - Q_ASSERT(vmemo); - return vmemo->vmeProperty(property->coreIndex()); - } else { - return loadProperty(engine, object, *property); - } + QQmlPropertyCache *cache = ddata->propertyCache; + Q_ASSERT(cache); + QQmlPropertyData *property = cache->property(propertyIndex); + Q_ASSERT(property); // We resolved this property earlier, so it better exist! + return getProperty(engine, object, property, captureRequired); } ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty) @@ -325,12 +349,49 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC return QV4::Encode::null(); } - if (!QQmlData::get(object, true)) { + if (name->equals(engine->id_destroy()) || name->equals(engine->id_toString())) { + int index = name->equals(engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; if (hasProperty) - *hasProperty = false; - return QV4::Encode::null(); + *hasProperty = true; + ExecutionContext *global = engine->rootContext(); + return QV4::QObjectMethod::create(global, object, index); } + QQmlData *ddata = QQmlData::get(object, false); + QQmlPropertyData local; + QQmlPropertyData *result = findProperty(engine, object, qmlContext, name, revisionMode, &local); + + if (result) { + if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) { + if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) { + if (hasProperty) + *hasProperty = false; + return QV4::Encode::undefined(); + } + } + + if (hasProperty) + *hasProperty = true; + + return getProperty(engine, object, result); + } else { + // Check if this object is already wrapped. + if (!ddata || (ddata->jsWrapper.isUndefined() && + (ddata->jsEngineId == 0 || // Nobody owns the QObject + !ddata->hasTaintedV4Object))) { // Someone else has used the QObject, but it isn't tainted + + // Not wrapped. Last chance: try query QObjectWrapper's prototype. + // If it can't handle this, then there is no point + // to wrap the QObject just to look at an empty set of JS props. + QV4::Object *proto = QObjectWrapper::defaultPrototype(engine); + return proto->get(name, hasProperty); + } + } + + // If we get here, we must already be wrapped (which implies a ddata). + // There's no point wrapping again, as there wouldn't be any new props. + Q_ASSERT(ddata); + QV4::Scope scope(engine); QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(engine, object)); if (!wrapper) { @@ -341,6 +402,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC return wrapper->getQmlProperty(qmlContext, name, revisionMode, hasProperty); } + bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, const Value &value) { @@ -399,10 +461,23 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP } } - if (newBinding) + if (newBinding) { QQmlPropertyPrivate::setBinding(newBinding); - else + } else { + if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) { + if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) { + Q_ASSERT(!binding->isValueTypeProxy()); + const auto qmlBinding = static_cast<const QQmlBinding*>(binding); + const auto stackFrame = engine->currentStackFrame(); + qCInfo(lcBindingRemoval, + "Overwriting binding on %s::%s at %s:%d that was initially bound at %s", + object->metaObject()->className(), qPrintable(property->name(object)), + qPrintable(stackFrame.source), stackFrame.line, + qPrintable(qmlBinding->expressionIdentifier())); + } + } QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex())); + } if (!newBinding && property->isVarProperty()) { // allow assignment of "special" values (null, undefined, function) to var properties @@ -554,21 +629,6 @@ void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack) markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack); } -ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired) -{ - if (QQmlData::wasDeleted(object)) - return QV4::Encode::null(); - QQmlData *ddata = QQmlData::get(object, /*create*/false); - if (!ddata) - return QV4::Encode::undefined(); - - QQmlPropertyCache *cache = ddata->propertyCache; - Q_ASSERT(cache); - QQmlPropertyData *property = cache->property(propertyIndex); - Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return getProperty(engine, object, property, captureRequired); -} - void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value) { setProperty(engine, d()->object(), propertyIndex, value); @@ -598,7 +658,7 @@ bool QObjectWrapper::isEqualTo(Managed *a, Managed *b) QV4::QObjectWrapper *qobjectWrapper = static_cast<QV4::QObjectWrapper *>(a); QV4::Object *o = b->as<Object>(); if (o) { - if (QV4::QmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QmlTypeWrapper>()) + if (QV4::QQmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QQmlTypeWrapper>()) return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object(); } @@ -1034,12 +1094,21 @@ private: inline void cleanup(); + template <class T, class M> + void fromContainerValue(const QV4::Object *object, int type, M CallArgument::*member, bool &queryEngine); + union { float floatValue; double doubleValue; quint32 intValue; bool boolValue; QObject *qobjectPtr; + std::vector<int> *stdVectorIntPtr; + std::vector<qreal> *stdVectorRealPtr; + std::vector<bool> *stdVectorBoolPtr; + std::vector<QString> *stdVectorQStringPtr; + std::vector<QUrl> *stdVectorQUrlPtr; + std::vector<QModelIndex> *stdVectorQModelIndexPtr; char allocData[MaxSizeOf8<QVariant, QString, @@ -1469,6 +1538,18 @@ void *CallArgument::dataPtr() { if (type == -1) return qvariantPtr->data(); + else if (type == qMetaTypeId<std::vector<int>>()) + return stdVectorIntPtr; + else if (type == qMetaTypeId<std::vector<qreal>>()) + return stdVectorRealPtr; + else if (type == qMetaTypeId<std::vector<bool>>()) + return stdVectorBoolPtr; + else if (type == qMetaTypeId<std::vector<QString>>()) + return stdVectorQStringPtr; + else if (type == qMetaTypeId<std::vector<QUrl>>()) + return stdVectorQUrlPtr; + else if (type == qMetaTypeId<std::vector<QModelIndex>>()) + return stdVectorQModelIndexPtr; else if (type != 0) return (void *)&allocData; return 0; @@ -1518,6 +1599,19 @@ void CallArgument::initAsType(int callType) } } +template <class T, class M> +void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine) +{ + if (object && object->isListType()) { + T* ptr = static_cast<T*>(QV4::SequencePrototype::getRawContainerPtr(object, callType)); + if (ptr) { + (this->*member) = ptr; + type = callType; + queryEngine = false; + } + } +} + void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const QV4::Value &value) { if (type != 0) { @@ -1556,7 +1650,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q qobjectPtr = 0; if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) qobjectPtr = qobjectWrapper->object(); - else if (const QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>()) + else if (const QV4::QQmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QQmlTypeWrapper>()) queryEngine = qmlTypeWrapper->isSingleton(); type = callType; } else if (callType == qMetaTypeId<QVariant>()) { @@ -1599,6 +1693,33 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q type = callType; } else if (callType == QMetaType::Void) { *qvariantPtr = QVariant(); + } else if (callType == qMetaTypeId<std::vector<int>>() + || callType == qMetaTypeId<std::vector<qreal>>() + || callType == qMetaTypeId<std::vector<bool>>() + || callType == qMetaTypeId<std::vector<QString>>() + || callType == qMetaTypeId<std::vector<QUrl>>() + || callType == qMetaTypeId<std::vector<QModelIndex>>()) { + queryEngine = true; + const QV4::Object* object = value.as<Object>(); + if (callType == qMetaTypeId<std::vector<int>>()) { + stdVectorIntPtr = nullptr; + fromContainerValue<std::vector<int>>(object, callType, &CallArgument::stdVectorIntPtr, queryEngine); + } else if (callType == qMetaTypeId<std::vector<qreal>>()) { + stdVectorRealPtr = nullptr; + fromContainerValue<std::vector<qreal>>(object, callType, &CallArgument::stdVectorRealPtr, queryEngine); + } else if (callType == qMetaTypeId<std::vector<bool>>()) { + stdVectorBoolPtr = nullptr; + fromContainerValue<std::vector<bool>>(object, callType, &CallArgument::stdVectorBoolPtr, queryEngine); + } else if (callType == qMetaTypeId<std::vector<QString>>()) { + stdVectorQStringPtr = nullptr; + fromContainerValue<std::vector<QString>>(object, callType, &CallArgument::stdVectorQStringPtr, queryEngine); + } else if (callType == qMetaTypeId<std::vector<QUrl>>()) { + stdVectorQUrlPtr = nullptr; + fromContainerValue<std::vector<QUrl>>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine); + } else if (callType == qMetaTypeId<std::vector<QModelIndex>>()) { + stdVectorQModelIndexPtr = nullptr; + fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine); + } } else { queryEngine = true; } @@ -2085,3 +2206,4 @@ void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object) QT_END_NAMESPACE +#include "moc_qv4qobjectwrapper_p.cpp" |