diff options
Diffstat (limited to 'src/qml/qml')
29 files changed, 720 insertions, 917 deletions
diff --git a/src/qml/qml/ftw/qbitfield_p.h b/src/qml/qml/ftw/qbitfield_p.h index 0b7d507b11..e3b6b0e498 100644 --- a/src/qml/qml/ftw/qbitfield_p.h +++ b/src/qml/qml/ftw/qbitfield_p.h @@ -129,15 +129,16 @@ QBitField QBitField::united(const QBitField &o) rv.bits = max; rv.ownData = new quint32[length + 1]; *(rv.ownData) = 1; - rv.data = rv.ownData + 1; + quint32 *rvdata; + rv.data = rvdata = rv.ownData + 1; if (bits > o.bits) { - ::memcpy((quint32 *)rv.data, data, length * sizeof(quint32)); + ::memcpy(rvdata, data, length * sizeof(quint32)); for (quint32 ii = 0; ii < (o.bits + quint32(31)) / 32; ++ii) - ((quint32 *)rv.data)[ii] |= o.data[ii]; + (rvdata)[ii] |= o.data[ii]; } else { - ::memcpy((quint32 *)rv.data, o.data, length * sizeof(quint32)); + ::memcpy(rvdata, o.data, length * sizeof(quint32)); for (quint32 ii = 0; ii < (bits + quint32(31)) / 32; ++ii) - ((quint32 *)rv.data)[ii] |= data[ii]; + (rvdata)[ii] |= data[ii]; } return rv; } diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h index 6ae2e17267..d38fd668f3 100644 --- a/src/qml/qml/ftw/qhashedstring_p.h +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -252,14 +252,14 @@ public: inline bool equals(const QHashedStringRef &string) const { return length == string.length() && hash == string.hash() && - (isQString()?QHashedString::compare(string.constData(), (QChar *)utf16Data(), length): + (isQString()?QHashedString::compare(string.constData(), (const QChar *)utf16Data(), length): QHashedString::compare(string.constData(), cStrData(), length)); } inline bool equals(const QHashedCStringRef &string) const { return length == string.length() && hash == string.hash() && - (isQString()?QHashedString::compare((QChar *)utf16Data(), string.constData(), length): + (isQString()?QHashedString::compare((const QChar *)utf16Data(), string.constData(), length): QHashedString::compare(string.constData(), cStrData(), length)); } }; diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index d6fd7b96f6..23cb69e2f1 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -502,17 +502,13 @@ namespace QtQml { } #endif -#if defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wheader-hygiene" -#endif +QT_WARNING_PUSH +QT_WARNING_DISABLE_CLANG("-Wheader-hygiene") // This is necessary to allow for QtQuick1 and QtQuick2 scenes in a single application. using namespace QtQml; -#if defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) -#pragma clang diagnostic pop -#endif +QT_WARNING_POP //The C++ version of protected namespaces in qmldir Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion); diff --git a/src/qml/qml/qqmlabstracturlinterceptor.cpp b/src/qml/qml/qqmlabstracturlinterceptor.cpp index e64b33b181..cb57bc2146 100644 --- a/src/qml/qml/qqmlabstracturlinterceptor.cpp +++ b/src/qml/qml/qqmlabstracturlinterceptor.cpp @@ -58,7 +58,7 @@ To implement support for a custom networked scheme, see setNetworkAccessManagerFactory. */ -/* +/*! \enum QQmlAbstractUrlInterceptor::DataType Specifies where URL interception is taking place. diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index f17009569f..3613c17242 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -44,6 +44,7 @@ #include <private/qqmlcontextwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> #include <private/qqmlvmemetaobject_p.h> +#include <private/qqmlvaluetypewrapper_p.h> #include <QVariant> #include <QtCore/qdebug.h> @@ -253,6 +254,11 @@ bool QQmlBinding::write(const QQmlPropertyData &core, QUICK_STORE(QString, result.toQStringNoThrow()) break; default: + if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { + if (vtw->d()->valueType->typeId == core.propType) { + return vtw->write(m_target.data(), core.coreIndex); + } + } break; } } @@ -327,7 +333,7 @@ bool QQmlBinding::write(const QQmlPropertyData &core, const char *propertyType = 0; if (value.userType() == QMetaType::QObjectStar) { - if (QObject *o = *(QObject **)value.constData()) { + if (QObject *o = *(QObject *const *)value.constData()) { valueType = o->metaObject()->className(); QQmlMetaObject propertyMetaObject = QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate::get(engine), type); diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 56326df979..b056731e96 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -782,7 +782,7 @@ QString QQmlContextData::findObjectId(const QObject *obj) const if (publicContext) { QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext); for (int ii = 0; ii < p->propertyValues.count(); ++ii) - if (p->propertyValues.at(ii) == QVariant::fromValue((QObject *)obj)) + if (p->propertyValues.at(ii) == QVariant::fromValue(const_cast<QObject *>(obj))) return properties.findId(ii); } diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 23084fb202..1007029416 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -93,19 +93,6 @@ ReturnedValue QmlContextWrapper::urlScope(ExecutionEngine *v4, const QUrl &url) return w.asReturnedValue(); } -QQmlContextData *QmlContextWrapper::getContext(const Value &value) -{ - if (!value.isObject()) - return 0; - - QV4::ExecutionEngine *v4 = value.as<Object>()->engine(); - Scope scope(v4); - QV4::Scoped<QmlContextWrapper> c(scope, value); - - return c ? c->getContext() : 0; -} - - ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty) { Q_ASSERT(m->as<QmlContextWrapper>()); @@ -323,68 +310,4 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) Object::put(m, name, value); } -void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const CompiledData::Function *compiledFunction) -{ - // Let the caller check and avoid the function call :) - Q_ASSERT(compiledFunction->hasQmlDependencies()); - - QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; - if (!ep) - return; - QQmlPropertyCapture *capture = ep->propertyCapture; - if (!capture) - return; - - QV4::Scope scope(engine); - QV4::Scoped<QmlContext> context(scope, engine->qmlContext()); - QQmlContextData *qmlContext = context->qmlContext(); - - const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); - const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; - for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) { - Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount); - capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings); - } - - Q_ASSERT(qmlContext->contextObject); - const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); - const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; - for (int i = 0; i < contextPropertyDependencyCount; ++i) { - const int propertyIndex = *contextPropertyDependency++; - const int notifyIndex = *contextPropertyDependency++; - capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex); - } - - QObject *scopeObject = context->qmlScope(); - const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); - const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; - for (int i = 0; i < scopePropertyDependencyCount; ++i) { - const int propertyIndex = *scopePropertyDependency++; - const int notifyIndex = *scopePropertyDependency++; - capture->captureProperty(scopeObject, propertyIndex, notifyIndex); - } - -} - -ReturnedValue QmlContextWrapper::qmlSingletonWrapper(ExecutionEngine *v4, String *name) -{ - if (!d()->context->imports) - return Encode::undefined(); - // Search for attached properties, enums and imported scripts - QQmlTypeNameCache::Result r = d()->context->imports->query(name); - - Q_ASSERT(r.isValid()); - Q_ASSERT(r.type); - Q_ASSERT(r.type->isSingleton()); - Q_ASSERT(v4); - - QQmlEngine *e = v4->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo(); - siinfo->init(e); - - if (QObject *qobjectSingleton = siinfo->qobjectApi(e)) - return QV4::QObjectWrapper::wrap(engine(), qobjectSingleton); - return QJSValuePrivate::convertedToValue(engine(), siinfo->scriptApi(e)); -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index 7b5d3216df..192df9aed6 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -92,16 +92,11 @@ struct Q_QML_EXPORT QmlContextWrapper : Object inline QObject *getScopeObject() const { return d()->scopeObject; } inline QQmlContextData *getContext() const { return d()->context; } - static QQmlContextData *getContext(const Value &value); void setReadOnly(bool b) { d()->readOnly = b; } static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const Value &value); - - static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction); - - ReturnedValue qmlSingletonWrapper(ExecutionEngine *e, String *name); }; } diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 70c682dedd..9c5e48ae32 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -258,6 +258,18 @@ void QQmlEnginePrivate::activateDesignerMode() on producing the image without blocking the main thread. */ +/*! + \fn QQmlImageProviderBase::imageType() const + + Implement this method to return the image type supported by this image provider. +*/ + +/*! + \fn QQmlImageProviderBase::flags() const + + Implement this to return the properties of this image provider. +*/ + /*! \internal */ QQmlImageProviderBase::QQmlImageProviderBase() { @@ -1355,6 +1367,9 @@ QQmlEngine::ObjectOwnership QQmlEngine::objectOwnership(QObject *object) return ddata->indestructible?CppOwnership:JavaScriptOwnership; } +/*! + \reimp +*/ bool QQmlEngine::event(QEvent *e) { Q_D(QQmlEngine); @@ -1496,16 +1511,28 @@ QQmlDataExtended::~QQmlDataExtended() void QQmlData::NotifyList::layout(QQmlNotifierEndpoint *endpoint) { - if (endpoint->next) - layout(endpoint->next); + // Add a temporary sentinel at beginning of list. This will be overwritten + // when the end point is inserted into the notifies further down. + endpoint->prev = 0; - int index = endpoint->sourceSignal; - index = qMin(index, 0xFFFF - 1); + while (endpoint->next) { + Q_ASSERT(reinterpret_cast<QQmlNotifierEndpoint *>(endpoint->next->prev) == endpoint); + endpoint = endpoint->next; + } + + while (endpoint) { + QQmlNotifierEndpoint *ep = (QQmlNotifierEndpoint *) endpoint->prev; - endpoint->next = notifies[index]; - if (endpoint->next) endpoint->next->prev = &endpoint->next; - endpoint->prev = ¬ifies[index]; - notifies[index] = endpoint; + int index = endpoint->sourceSignal; + index = qMin(index, 0xFFFF - 1); + + endpoint->next = notifies[index]; + if (endpoint->next) endpoint->next->prev = &endpoint->next; + endpoint->prev = ¬ifies[index]; + notifies[index] = endpoint; + + endpoint = ep; + } } void QQmlData::NotifyList::layout() @@ -2182,7 +2209,7 @@ QObject *QQmlEnginePrivate::toQObject(const QVariant &v, bool *ok) const int t = v.userType(); if (t == QMetaType::QObjectStar || m_compositeTypes.contains(t)) { if (ok) *ok = true; - return *(QObject **)(v.constData()); + return *(QObject *const *)(v.constData()); } else { return QQmlMetaType::toQObject(v, ok); } diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp index 7b560268ba..d86fbc5999 100644 --- a/src/qml/qml/qqmlextensionplugin.cpp +++ b/src/qml/qml/qqmlextensionplugin.cpp @@ -44,71 +44,7 @@ QT_BEGIN_NAMESPACE \ingroup plugins - QQmlExtensionPlugin is a plugin interface that makes it possible to - create QML extensions that can be loaded dynamically into QML applications. - These extensions allow custom QML types to be made available to the QML engine. - - To write a QML extension plugin: - - \list - \li Subclass QQmlExtensionPlugin, implement registerTypes() method to register types - using qmlRegisterType(), and export the class using the Q_PLUGIN_METADATA() macro - \li Write an appropriate project file for the plugin - \li Create a \l{Module Definition qmldir Files}{qmldir file} to describe the plugin - \endlist - - QML extension plugins can be used to provide either application-specific or - library-like plugins. Library plugins should limit themselves to registering types, - as any manipulation of the engine's root context may cause conflicts - or other issues in the library user's code. - - - \section1 An Example - - Suppose there is a new \c TimeModel C++ class that should be made available - as a new QML element. It provides the current time through \c hour and \c minute - properties, like this: - - \snippet qmlextensionplugins/plugin.cpp 0 - \dots - - To make this class available as a QML type, create a plugin that registers - this type with a specific \l {QML Modules}{module} using qmlRegisterType(). For this example the plugin - module will be named \c TimeExample (as defined in the project - file further below). - - \snippet qmlextensionplugins/plugin.cpp plugin - - This registers the \c TimeModel class with the 1.0 version of this - plugin library, as a QML type called \c Time. The Q_ASSERT statement - ensures the module is imported correctly by any QML components that use this plugin. - - The project file defines the project as a plugin library and specifies - it should be built into the \c imports/TimeExample directory: - - \code - TEMPLATE = lib - CONFIG += qt plugin - QT += qml - - DESTDIR = imports/TimeExample - TARGET = qmlqtimeexampleplugin - ... - \endcode - - Finally, a \l{Module Definition qmldir Files}{qmldir file} is required in the \c imports/TimeExample directory - that describes the plugin. This directory includes a \c Clock.qml file that - should be bundled with the plugin, so it needs to be specified in the \c qmldir - file: - - \quotefile qmlextensionplugins/imports/TimeExample/qmldir - - Once the project is built and installed, the new \c Time element can be - used by any QML component that imports the \c TimeExample module: - - \snippet qmlextensionplugins/plugins.qml 0 - - The full source code is available in the \l {qmlextensionplugins}{plugins example}. + \include qqmlextensionplugin.qdocinc The \l {Writing QML Extensions with C++} tutorial also contains a chapter on creating QML plugins. diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp index 3ee7bb3040..8597e8a5c7 100644 --- a/src/qml/qml/qqmlfileselector.cpp +++ b/src/qml/qml/qqmlfileselector.cpp @@ -102,6 +102,9 @@ QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent) d->engine->setUrlInterceptor(d->myInstance.data()); } +/*! + Destroys the QQmlFileSelector object. +*/ QQmlFileSelector::~QQmlFileSelector() { Q_D(QQmlFileSelector); diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index 0a2f4079c2..aa2b4b6aee 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -62,40 +62,11 @@ const QMetaObject *QQmlValueTypeProvider::metaObjectForMetaType(int type) return 0; } -bool QQmlValueTypeProvider::initValueType(int type, void *data, size_t n) +bool QQmlValueTypeProvider::initValueType(int type, QVariant& dst) { - Q_ASSERT(data); - - QQmlValueTypeProvider *p = this; - do { - if (p->init(type, data, n)) - return true; - } while ((p = p->next)); - - return false; -} - -bool QQmlValueTypeProvider::destroyValueType(int type, void *data, size_t n) -{ - Q_ASSERT(data); - QQmlValueTypeProvider *p = this; do { - if (p->destroy(type, data, n)) - return true; - } while ((p = p->next)); - - return false; -} - -bool QQmlValueTypeProvider::copyValueType(int type, const void *src, void *dst, size_t n) -{ - Q_ASSERT(src); - Q_ASSERT(dst); - - QQmlValueTypeProvider *p = this; - do { - if (p->copy(type, src, dst, n)) + if (p->init(type, dst)) return true; } while ((p = p->next)); @@ -188,14 +159,13 @@ QVariant QQmlValueTypeProvider::createVariantFromJsObject(int type, QQmlV4Handle return QVariant(); } -bool QQmlValueTypeProvider::equalValueType(int type, const void *lhs, const void *rhs, size_t rhsSize) +bool QQmlValueTypeProvider::equalValueType(int type, const void *lhs, const QVariant& rhs) { Q_ASSERT(lhs); - Q_ASSERT(rhs); QQmlValueTypeProvider *p = this; do { - if (p->equal(type, lhs, rhs, rhsSize)) + if (p->equal(type, lhs, rhs)) return true; } while ((p = p->next)); @@ -216,28 +186,26 @@ bool QQmlValueTypeProvider::storeValueType(int type, const void *src, void *dst, return false; } -bool QQmlValueTypeProvider::readValueType(int srcType, const void *src, size_t srcSize, int dstType, void *dst) +bool QQmlValueTypeProvider::readValueType(const QVariant& src, void *dst, int dstType) { - Q_ASSERT(src); Q_ASSERT(dst); QQmlValueTypeProvider *p = this; do { - if (p->read(srcType, src, srcSize, dstType, dst)) + if (p->read(src, dst, dstType)) return true; } while ((p = p->next)); return false; } -bool QQmlValueTypeProvider::writeValueType(int type, const void *src, void *dst, size_t n) +bool QQmlValueTypeProvider::writeValueType(int type, const void *src, QVariant& dst) { Q_ASSERT(src); - Q_ASSERT(dst); QQmlValueTypeProvider *p = this; do { - if (p->write(type, src, dst, n)) + if (p->write(type, src, dst)) return true; } while ((p = p->next)); @@ -245,19 +213,17 @@ bool QQmlValueTypeProvider::writeValueType(int type, const void *src, void *dst, } const QMetaObject *QQmlValueTypeProvider::getMetaObjectForMetaType(int) { return 0; } -bool QQmlValueTypeProvider::init(int, void *, size_t) { return false; } -bool QQmlValueTypeProvider::destroy(int, void *, size_t) { return false; } -bool QQmlValueTypeProvider::copy(int, const void *, void *, size_t) { return false; } +bool QQmlValueTypeProvider::init(int, QVariant&) { return false; } bool QQmlValueTypeProvider::create(int, int, const void *[], QVariant *) { return false; } bool QQmlValueTypeProvider::createFromString(int, const QString &, void *, size_t) { return false; } bool QQmlValueTypeProvider::createStringFrom(int, const void *, QString *) { return false; } bool QQmlValueTypeProvider::variantFromString(const QString &, QVariant *) { return false; } bool QQmlValueTypeProvider::variantFromString(int, const QString &, QVariant *) { return false; } bool QQmlValueTypeProvider::variantFromJsObject(int, QQmlV4Handle, QV4::ExecutionEngine *, QVariant *) { return false; } -bool QQmlValueTypeProvider::equal(int, const void *, const void *, size_t) { return false; } +bool QQmlValueTypeProvider::equal(int, const void *, const QVariant&) { return false; } bool QQmlValueTypeProvider::store(int, const void *, void *, size_t) { return false; } -bool QQmlValueTypeProvider::read(int, const void *, size_t, int, void *) { return false; } -bool QQmlValueTypeProvider::write(int, const void *, void *, size_t) { return false; } +bool QQmlValueTypeProvider::read(const QVariant&, void *, int) { return false; } +bool QQmlValueTypeProvider::write(int, const void *, QVariant&) { return false; } Q_GLOBAL_STATIC(QQmlValueTypeProvider, nullValueTypeProvider) static QQmlValueTypeProvider *valueTypeProvider = 0; diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index 7856d85376..d09ae21f56 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -224,9 +224,7 @@ public: const QMetaObject *metaObjectForMetaType(int); - bool initValueType(int, void *, size_t); - bool destroyValueType(int, void *, size_t); - bool copyValueType(int, const void *, void *, size_t); + bool initValueType(int, QVariant&); QVariant createValueType(int, int, const void *[]); bool createValueFromString(int, const QString &, void *, size_t); @@ -236,16 +234,14 @@ public: QVariant createVariantFromString(int, const QString &, bool *); QVariant createVariantFromJsObject(int, QQmlV4Handle, QV4::ExecutionEngine *, bool*); - bool equalValueType(int, const void *, const void *, size_t); + bool equalValueType(int, const void *, const QVariant&); bool storeValueType(int, const void *, void *, size_t); - bool readValueType(int, const void *, size_t, int, void *); - bool writeValueType(int, const void *, void *, size_t); + bool readValueType(const QVariant&, void *, int); + bool writeValueType(int, const void *, QVariant&); private: virtual const QMetaObject *getMetaObjectForMetaType(int); - virtual bool init(int, void *, size_t); - virtual bool destroy(int, void *, size_t); - virtual bool copy(int, const void *, void *, size_t); + virtual bool init(int, QVariant&); virtual bool create(int, int, const void *[], QVariant *); virtual bool createFromString(int, const QString &, void *, size_t); @@ -255,10 +251,10 @@ private: virtual bool variantFromString(int, const QString &, QVariant *); virtual bool variantFromJsObject(int, QQmlV4Handle, QV4::ExecutionEngine *, QVariant *); - virtual bool equal(int, const void *, const void *, size_t); + virtual bool equal(int, const void *, const QVariant&); virtual bool store(int, const void *, void *, size_t); - virtual bool read(int, const void *, size_t, int, void *); - virtual bool write(int, const void *, void *, size_t); + virtual bool read(const QVariant&, void *, int); + virtual bool write(int, const void *, QVariant&); friend Q_QML_PRIVATE_EXPORT void QQml_addValueTypeProvider(QQmlValueTypeProvider *); friend Q_QML_PRIVATE_EXPORT void QQml_removeValueTypeProvider(QQmlValueTypeProvider *); diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index cf509a96ec..b17bb0455d 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -1653,7 +1653,7 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, \row \li Unix/Linux \li \c .so \row \li AIX \li \c .a \row \li HP-UX \li \c .sl, \c .so (HP-UXi) - \row \li Mac OS X \li \c .dylib, \c .bundle, \c .so + \row \li OS X \li \c .dylib, \c .bundle, \c .so \endtable Version number on unix are ignored. diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 5f30eac066..967a7e75d7 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -287,6 +287,50 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n) } } +void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction) +{ + // Let the caller check and avoid the function call :) + Q_ASSERT(compiledFunction->hasQmlDependencies()); + + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + if (!ep) + return; + QQmlPropertyCapture *capture = ep->propertyCapture; + if (!capture) + return; + + QV4::Scope scope(engine); + QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext()); + QQmlContextData *qmlContext = context->qmlContext(); + + const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); + const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; + for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) { + Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount); + capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings); + } + + Q_ASSERT(qmlContext->contextObject); + const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); + const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; + for (int i = 0; i < contextPropertyDependencyCount; ++i) { + const int propertyIndex = *contextPropertyDependency++; + const int notifyIndex = *contextPropertyDependency++; + capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex); + } + + QObject *scopeObject = context->qmlScope(); + const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); + const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; + for (int i = 0; i < scopePropertyDependencyCount; ++i) { + const int propertyIndex = *scopePropertyDependency++; + const int notifyIndex = *scopePropertyDependency++; + capture->captureProperty(scopeObject, propertyIndex, notifyIndex); + } + +} + + void QQmlJavaScriptExpression::clearError() { if (m_error) diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index dfcf8b2d68..f0a3741588 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -176,6 +176,8 @@ public: void captureProperty(QQmlNotifier *); void captureProperty(QObject *, int, int); + static void registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction); + QQmlEngine *engine; QQmlJavaScriptExpression *expression; QQmlJavaScriptExpression::DeleteWatcher *watcher; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 41629801ea..fbb21f4562 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -225,6 +225,9 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) v4->pushGlobalContext(); QObject *o = qobjectCallback(e, e); setQObjectApi(e, o); + if (!o) { + qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.", qPrintable(typeName)); + } // if this object can use a property cache, create it now QQmlData::ensurePropertyCache(e, o); v4->popContext(); @@ -1510,7 +1513,7 @@ QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok) if (ok) *ok = true; - return *(QObject **)v.constData(); + return *(QObject *const *)v.constData(); } bool QQmlMetaType::isQObject(int userType) diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp index 4ce5be4d1a..ea3f7a1530 100644 --- a/src/qml/qml/qqmlnotifier.cpp +++ b/src/qml/qml/qqmlnotifier.cpp @@ -51,30 +51,52 @@ static Callback QQmlNotifier_callbacks[] = { QQmlVMEMetaObjectEndpoint_callback }; +namespace { + struct NotifyListTraversalData { + NotifyListTraversalData(QQmlNotifierEndpoint *ep = 0) + : originalSenderPtr(0) + , disconnectWatch(0) + , endpoint(ep) + {} + + qintptr originalSenderPtr; + qintptr *disconnectWatch; + QQmlNotifierEndpoint *endpoint; + }; +} + void QQmlNotifier::emitNotify(QQmlNotifierEndpoint *endpoint, void **a) { - qintptr originalSenderPtr; - qintptr *disconnectWatch; - - if (!endpoint->isNotifying()) { - originalSenderPtr = endpoint->senderPtr; - disconnectWatch = &originalSenderPtr; - endpoint->senderPtr = qintptr(disconnectWatch) | 0x1; - } else { - disconnectWatch = (qintptr *)(endpoint->senderPtr & ~0x1); + QVarLengthArray<NotifyListTraversalData> stack; + while (endpoint) { + stack.append(NotifyListTraversalData(endpoint)); + endpoint = endpoint->next; } - if (endpoint->next) - emitNotify(endpoint->next, a); + int i = 0; + for (; i < stack.size(); ++i) { + NotifyListTraversalData &data = stack[i]; + + if (!data.endpoint->isNotifying()) { + data.originalSenderPtr = data.endpoint->senderPtr; + data.disconnectWatch = &data.originalSenderPtr; + data.endpoint->senderPtr = qintptr(data.disconnectWatch) | 0x1; + } else { + data.disconnectWatch = (qintptr *)(data.endpoint->senderPtr & ~0x1); + } + } - if (*disconnectWatch) { + while (--i >= 0) { + const NotifyListTraversalData &data = stack.at(i); + if (*data.disconnectWatch) { - Q_ASSERT(QQmlNotifier_callbacks[endpoint->callback]); - QQmlNotifier_callbacks[endpoint->callback](endpoint, a); + Q_ASSERT(QQmlNotifier_callbacks[data.endpoint->callback]); + QQmlNotifier_callbacks[data.endpoint->callback](data.endpoint, a); - if (disconnectWatch == &originalSenderPtr && originalSenderPtr) { - // End of notifying, restore values - endpoint->senderPtr = originalSenderPtr; + if (data.disconnectWatch == &data.originalSenderPtr && data.originalSenderPtr) { + // End of notifying, restore values + data.endpoint->senderPtr = data.originalSenderPtr; + } } } } diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h index bd2c0e6506..90902c089d 100644 --- a/src/qml/qml/qqmlnotifier_p.h +++ b/src/qml/qml/qqmlnotifier_p.h @@ -60,6 +60,8 @@ private: class QQmlEngine; class QQmlNotifierEndpoint { + QQmlNotifierEndpoint *next; + QQmlNotifierEndpoint **prev; public: // QQmlNotifierEndpoint can only invoke one of a set of pre-defined callbacks. // To add another callback, extend this enum and add the callback to the top @@ -103,9 +105,6 @@ private: // The index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). signed int sourceSignal:28; - - QQmlNotifierEndpoint *next; - QQmlNotifierEndpoint **prev; }; QQmlNotifier::QQmlNotifier() @@ -137,7 +136,7 @@ void QQmlNotifier::notify() } QQmlNotifierEndpoint::QQmlNotifierEndpoint(Callback callback) -: senderPtr(0), callback(callback), sourceSignal(-1), next(0), prev(0) +: next(0), prev(0), senderPtr(0), callback(callback), sourceSignal(-1) { } diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index c6d2d44ee1..16138508dd 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -35,6 +35,7 @@ #include <private/qqmlpropertycache_p.h> #include <private/qqmldata_p.h> #include <private/qmetaobjectbuilder_p.h> +#include <private/qv8engine_p.h> #include <qqmlengine.h> #include <qdebug.h> @@ -106,6 +107,28 @@ QMetaObject *QQmlOpenMetaObjectType::metaObject() const return d->mem; } +void QQmlOpenMetaObjectType::createProperties(const QVector<QByteArray> &names) +{ + for (int i = 0; i < names.count(); ++i) { + const QByteArray &name = names.at(i); + const int id = d->mob.propertyCount(); + d->mob.addSignal("__" + QByteArray::number(id) + "()"); + QMetaPropertyBuilder build = d->mob.addProperty(name, "QVariant", id); + propertyCreated(id, build); + d->names.insert(name, id); + } + free(d->mem); + d->mem = d->mob.toMetaObject(); + QSet<QQmlOpenMetaObject*>::iterator it = d->referers.begin(); + while (it != d->referers.end()) { + QQmlOpenMetaObject *omo = *it; + *static_cast<QMetaObject *>(omo) = *d->mem; + if (d->cache) + d->cache->update(omo); + ++it; + } +} + int QQmlOpenMetaObjectType::createProperty(const QByteArray &name) { int id = d->mob.propertyCount(); @@ -230,6 +253,14 @@ QQmlOpenMetaObjectType *QQmlOpenMetaObject::type() const return d->type; } +void QQmlOpenMetaObject::emitPropertyNotification(const QByteArray &propertyName) +{ + QHash<QByteArray, int>::ConstIterator iter = d->type->d->names.constFind(propertyName); + if (iter == d->type->d->names.constEnd()) + return; + activate(d->object, *iter + d->type->d->signalOffset, 0); +} + int QQmlOpenMetaObject::metaCall(QMetaObject::Call c, int id, void **a) { if (( c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) @@ -337,7 +368,7 @@ void QQmlOpenMetaObject::setCached(bool c) QQmlData *qmldata = QQmlData::get(d->object, true); if (d->cacheProperties) { if (!d->type->d->cache) - d->type->d->cache = new QQmlPropertyCache(d->type->d->engine, this); + d->type->d->cache = new QQmlPropertyCache(QV8Engine::getV4(d->type->d->engine), this); qmldata->propertyCache = d->type->d->cache; d->type->d->cache->addref(); } else { diff --git a/src/qml/qml/qqmlopenmetaobject_p.h b/src/qml/qml/qqmlopenmetaobject_p.h index 6a29d08d4e..75ce9addd6 100644 --- a/src/qml/qml/qqmlopenmetaobject_p.h +++ b/src/qml/qml/qqmlopenmetaobject_p.h @@ -54,6 +54,7 @@ public: QQmlOpenMetaObjectType(const QMetaObject *base, QQmlEngine *engine); ~QQmlOpenMetaObjectType(); + void createProperties(const QVector<QByteArray> &names); int createProperty(const QByteArray &name); int propertyOffset() const; @@ -101,6 +102,8 @@ public: QQmlOpenMetaObjectType *type() const; + void emitPropertyNotification(const QByteArray &propertyName); + protected: virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); virtual int createProperty(const char *, const char *); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 414bf8fe0f..c1120b4542 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1240,12 +1240,12 @@ bool QQmlPropertyPrivate::write(QObject *object, QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv); } else if (variantType == propertyType) { - void *a[] = { (void *)value.constData(), 0, &status, &flags }; + void *a[] = { const_cast<void *>(value.constData()), 0, &status, &flags }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); } else if (qMetaTypeId<QVariant>() == propertyType) { - void *a[] = { (void *)&value, 0, &status, &flags }; + void *a[] = { const_cast<QVariant *>(&value), 0, &status, &flags }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); } else if (property.isQObject()) { @@ -1255,7 +1255,7 @@ bool QQmlPropertyPrivate::write(QObject *object, if (valMo.isNull()) return false; - QObject *o = *(QObject **)value.constData(); + QObject *o = *(QObject *const *)value.constData(); QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType); if (o) valMo = o; @@ -1401,7 +1401,7 @@ bool QQmlPropertyPrivate::write(QObject *object, } if (ok) { - void *a[] = { (void *)v.constData(), 0, &status, &flags}; + void *a[] = { const_cast<void *>(v.constData()), 0, &status, &flags}; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); } else { return false; @@ -1411,7 +1411,6 @@ bool QQmlPropertyPrivate::write(QObject *object, return true; } - QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType) { QMetaType metaType(userType); diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 294f3ccdf9..9a935ed55f 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -231,10 +231,10 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) /*! Creates a new empty QQmlPropertyCache. */ -QQmlPropertyCache::QQmlPropertyCache(QJSEngine *e) -: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(0), argumentsCache(0) +QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e) + : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), + signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), + _metaObject(0), argumentsCache(0) { Q_ASSERT(engine); } @@ -242,10 +242,10 @@ QQmlPropertyCache::QQmlPropertyCache(QJSEngine *e) /*! Creates a new QQmlPropertyCache of \a metaObject. */ -QQmlPropertyCache::QQmlPropertyCache(QJSEngine *e, const QMetaObject *metaObject) -: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(0), argumentsCache(0) +QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject *metaObject) + : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), + signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), + _metaObject(0), argumentsCache(0) { Q_ASSERT(engine); Q_ASSERT(metaObject); @@ -271,7 +271,7 @@ QQmlPropertyCache::~QQmlPropertyCache() stringCache.clear(); if (_parent) _parent->release(); - if (_ownMetaObject) free((void *)_metaObject); + if (_ownMetaObject) free(const_cast<QMetaObject *>(_metaObject)); _metaObject = 0; _parent = 0; engine = 0; @@ -818,7 +818,7 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const data->propType = registerResult == -1 ? QMetaType::UnknownType : registerResult; } } - data->flags |= flagsForPropertyType(data->propType, qobject_cast<QQmlEngine*>(engine)); + data->flags |= flagsForPropertyType(data->propType, engine->qmlEngine()); } data->flags &= ~QQmlPropertyData::NotFullyResolved; @@ -1134,7 +1134,7 @@ QString QQmlPropertyCache::signalParameterStringForJS(int index, QString *errorS } QString error; - QString parameters = signalParameterStringForJS(QV8Engine::getV4(engine), parameterNameList, &error); + QString parameters = signalParameterStringForJS(engine, parameterNameList, &error); A *arguments = static_cast<A *>(signalData->arguments); arguments->signalParameterStringForJS = new QString(!error.isEmpty() ? error : parameters); diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 4d8c6dd9a5..2ee399c496 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -243,8 +243,8 @@ class QQmlPropertyCacheMethodArguments; class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup { public: - QQmlPropertyCache(QJSEngine *); - QQmlPropertyCache(QJSEngine *, const QMetaObject *); + QQmlPropertyCache(QV4::ExecutionEngine *); + QQmlPropertyCache(QV4::ExecutionEngine *, const QMetaObject *); virtual ~QQmlPropertyCache(); void update(const QMetaObject *); @@ -377,8 +377,10 @@ private: _hasPropertyOverrides |= isOverride; } - QJSEngine *engine; +public: + QV4::ExecutionEngine *engine; +private: QQmlPropertyCache *_parent; int propertyIndexCacheStart; int methodIndexCacheStart; diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 7ebfcd64b7..6a71a07e9b 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -202,7 +202,7 @@ QQmlValueType::~QQmlValueType() QObjectPrivate *op = QObjectPrivate::get(this); Q_ASSERT(op->metaObject == this); op->metaObject = 0; - ::free((void*)_metaObject); + ::free(const_cast<QMetaObject *>(_metaObject)); metaType.destroy(gadgetPtr); } diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 08b1e09d76..0ffeddbabc 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 BasysKom GmbH. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -51,8 +52,8 @@ QT_BEGIN_NAMESPACE -QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr(bool isVar) - : QQmlGuard<QObject>(0), m_target(0), m_isVar(isVar), m_index(-1) +QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr() + : QQmlGuard<QObject>(0), m_target(0), m_index(-1) { } @@ -63,14 +64,12 @@ QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr() void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *) { if (m_target && m_index >= 0) { - if (m_isVar && m_target->varPropertiesInitialized && !m_target->varProperties.isUndefined()) { - // Set the var property to NULL - QV4::ExecutionEngine *v4 = m_target->varProperties.engine(); + if (m_target->propertiesInitialized && !m_target->properties.isUndefined()) { + QV4::ExecutionEngine *v4 = m_target->cache->engine; if (v4) { QV4::Scope scope(v4); - QV4::ScopedArrayObject a(scope, m_target->varProperties.value()); - if (a) - a->putIndexed(m_index - m_target->firstVarPropertyIndex, QV4::ScopedValue(scope, QV4::Primitive::nullValue())); + QV4::Scoped<QV4::MemberData> sp(scope, m_target->properties.value()); + *(sp->data() + m_index) = QV4::Primitive::nullValue(); } } @@ -86,505 +85,382 @@ void QQmlVMEVariantQObjectPtr::setGuardedValue(QObject *obj, QQmlVMEMetaObject * setObject(obj); } -class QQmlVMEVariant -{ -public: - inline QQmlVMEVariant(); - inline ~QQmlVMEVariant(); - - inline const void *dataPtr() const; - inline void *dataPtr(); - inline int dataType() const; - inline size_t dataSize() const; - - inline QObject *asQObject(); - inline const QVariant &asQVariant(); - inline int asInt(); - inline bool asBool(); - inline double asDouble(); - inline const QString &asQString(); - inline const QUrl &asQUrl(); - inline const QDate &asQDate(); - inline const QDateTime &asQDateTime(); - inline const QRectF &asQRectF(); - inline const QPointF &asQPointF(); - inline const QSizeF &asQSizeF(); - - inline void setValue(QObject *v, QQmlVMEMetaObject *target, int index); - inline void setValue(const QVariant &); - inline void setValue(int); - inline void setValue(bool); - inline void setValue(double); - inline void setValue(const QString &); - inline void setValue(const QUrl &); - inline void setValue(const QTime &); - inline void setValue(const QDate &); - inline void setValue(const QDateTime &); - inline void setValue(const QRectF &); - inline void setValue(const QPointF &); - inline void setValue(const QSizeF &); - - inline void ensureValueType(int); - -private: - int type; - void *data[8]; // Large enough to hold all types - - inline void cleanup(); -}; - class QQmlVMEMetaObjectEndpoint : public QQmlNotifierEndpoint { public: QQmlVMEMetaObjectEndpoint(); - static void vmecallback(QQmlNotifierEndpoint *, void **); void tryConnect(); QFlagPointer<QQmlVMEMetaObject> metaObject; }; - -QQmlVMEVariant::QQmlVMEVariant() -: type(QVariant::Invalid) +QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint() + : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint) { } -QQmlVMEVariant::~QQmlVMEVariant() +void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **) { - cleanup(); + QQmlVMEMetaObjectEndpoint *vmee = static_cast<QQmlVMEMetaObjectEndpoint*>(e); + vmee->tryConnect(); } -void QQmlVMEVariant::cleanup() +void QQmlVMEMetaObjectEndpoint::tryConnect() { - if (type == QVariant::Invalid) { - } else if (type == QMetaType::Int || - type == QMetaType::Bool || - type == QMetaType::Double) { - type = QVariant::Invalid; - } else if (type == QMetaType::QObjectStar) { - ((QQmlVMEVariantQObjectPtr*)dataPtr())->~QQmlVMEVariantQObjectPtr(); - type = QVariant::Invalid; - } else if (type == QMetaType::QString) { - ((QString *)dataPtr())->~QString(); - type = QVariant::Invalid; - } else if (type == QMetaType::QUrl) { - ((QUrl *)dataPtr())->~QUrl(); - type = QVariant::Invalid; - } else if (type == QMetaType::QTime) { - ((QTime *)dataPtr())->~QTime(); - type = QVariant::Invalid; - } else if (type == QMetaType::QDate) { - ((QDate *)dataPtr())->~QDate(); - type = QVariant::Invalid; - } else if (type == QMetaType::QDateTime) { - ((QDateTime *)dataPtr())->~QDateTime(); - type = QVariant::Invalid; - } else if (type == QMetaType::QRectF) { - ((QRectF *)dataPtr())->~QRectF(); - type = QVariant::Invalid; - } else if (type == QMetaType::QPointF) { - ((QPointF *)dataPtr())->~QPointF(); - type = QVariant::Invalid; - } else if (type == QMetaType::QSizeF) { - ((QSizeF *)dataPtr())->~QSizeF(); - type = QVariant::Invalid; - } else if (type == qMetaTypeId<QVariant>()) { - ((QVariant *)dataPtr())->~QVariant(); - type = QVariant::Invalid; + int aliasId = this - metaObject->aliasEndpoints; + + if (metaObject.flag()) { + // This is actually notify + int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount; + metaObject->activate(metaObject->object, sigIdx, 0); } else { - if (QQml_valueTypeProvider()->destroyValueType(type, dataPtr(), dataSize())) { - type = QVariant::Invalid; + QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId; + if (!d->isObjectAlias()) { + QQmlContextData *ctxt = metaObject->ctxt; + QObject *target = ctxt->idValues[d->contextIdx].data(); + if (!target) + return; + + if (d->notifySignal != -1) + connect(target, d->notifySignal, ctxt->engine); } + + metaObject.setFlag(); } } -int QQmlVMEVariant::dataType() const +QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o) { - return type; -} + if (!hasAssignedMetaObjectData) { + *static_cast<QMetaObject *>(this) = *cache->createMetaObject(); -const void *QQmlVMEVariant::dataPtr() const -{ - return &data; -} + if (parent.isT1()) + this->d.superdata = parent.asT1()->toDynamicMetaObject(o); + else + this->d.superdata = parent.asT2(); -void *QQmlVMEVariant::dataPtr() -{ - return &data; -} + hasAssignedMetaObjectData = true; + } -size_t QQmlVMEVariant::dataSize() const -{ - return sizeof(data); + return this; } -QObject *QQmlVMEVariant::asQObject() +QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, + QQmlPropertyCache *cache, + const QQmlVMEMetaData *meta, QV4::ExecutionContext *qmlBindingContext, QQmlCompiledData *compiledData) +: object(obj), + ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta), + hasAssignedMetaObjectData(false), aliasEndpoints(0), + propertiesInitialized(false), interceptors(0), methods(0) { - if (type != QMetaType::QObjectStar) - setValue((QObject *)0, 0, -1); - - return *(QQmlGuard<QObject> *)(dataPtr()); -} + QObjectPrivate *op = QObjectPrivate::get(obj); -const QVariant &QQmlVMEVariant::asQVariant() -{ - if (type != QMetaType::QVariant) - setValue(QVariant()); + if (op->metaObject) { + parent = op->metaObject; + // Use the extra flag in QBiPointer to know if we can safely cast parent.asT1() to QQmlVMEMetaObject* + parent.setFlagValue(QQmlData::get(obj)->hasVMEMetaObject); + } else + parent = obj->metaObject(); - return *(QVariant *)(dataPtr()); -} + op->metaObject = this; + QQmlData::get(obj)->hasVMEMetaObject = true; -int QQmlVMEVariant::asInt() -{ - if (type != QMetaType::Int) - setValue(int(0)); + aConnected.resize(metaData->aliasCount); + int list_type = qMetaTypeId<QQmlListProperty<QObject> >(); + int qobject_type = qMetaTypeId<QObject*>(); + int variant_type = qMetaTypeId<QVariant>(); + // Need JS wrapper to ensure properties are marked. + // ### FIXME: I hope that this can be removed once we have the proper scope chain + // set up and the JS wrappers always exist. + bool needsJSWrapper = (metaData->propertyCount > 0); - return *(int *)(dataPtr()); -} + // ### Optimize + for (int ii = 0; ii < metaData->propertyCount; ++ii) { + int t = (metaData->propertyData() + ii)->propertyType; + if (t == list_type) { + listProperties.append(List(methodOffset() + ii, this)); + writeProperty(ii, listProperties.count() - 1); + } else if (!needsJSWrapper && (t == qobject_type || t == variant_type)) { + needsJSWrapper = true; + } + } -bool QQmlVMEVariant::asBool() -{ - if (type != QMetaType::Bool) - setValue(bool(false)); + if (needsJSWrapper) + ensureQObjectWrapper(); - return *(bool *)(dataPtr()); -} + if (qmlBindingContext && metaData->methodCount) { + methods = new QV4::PersistentValue[metaData->methodCount]; -double QQmlVMEVariant::asDouble() -{ - if (type != QMetaType::Double) - setValue(double(0)); + QV4::CompiledData::CompilationUnit *compilationUnit = compiledData->compilationUnit; + QV4::Scope scope(cache->engine); + QV4::ScopedObject o(scope); + for (int index = 0; index < metaData->methodCount; ++index) { + QQmlVMEMetaData::MethodData *data = metaData->methodData() + index; - return *(double *)(dataPtr()); + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[data->runtimeFunctionIndex]; + o = QV4::FunctionObject::createScriptFunction(qmlBindingContext, runtimeFunction); + methods[index].set(qmlBindingContext->engine(), o); + } + } } -const QString &QQmlVMEVariant::asQString() +QQmlVMEMetaObject::~QQmlVMEMetaObject() { - if (type != QMetaType::QString) - setValue(QString()); + if (parent.isT1()) parent.asT1()->objectDestroyed(object); + delete [] aliasEndpoints; + delete [] methods; - return *(QString *)(dataPtr()); + qDeleteAll(varObjectGuards); } -const QUrl &QQmlVMEVariant::asQUrl() +QV4::MemberData *QQmlVMEMetaObject::propertiesAsMemberData() { - if (type != QMetaType::QUrl) - setValue(QUrl()); + if (!ensurePropertiesAllocated()) + return 0; - return *(QUrl *)(dataPtr()); + return static_cast<QV4::MemberData*>(properties.asManaged()); } -const QDate &QQmlVMEVariant::asQDate() +void QQmlVMEMetaObject::writeProperty(int id, int v) { - if (type != QMetaType::QDate) - setValue(QDate()); - - return *(QDate *)(dataPtr()); + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = QV4::Primitive::fromInt32(v); } -const QDateTime &QQmlVMEVariant::asQDateTime() +void QQmlVMEMetaObject::writeProperty(int id, bool v) { - if (type != QMetaType::QDateTime) - setValue(QDateTime()); - - return *(QDateTime *)(dataPtr()); + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = QV4::Primitive::fromBoolean(v); } -const QRectF &QQmlVMEVariant::asQRectF() +void QQmlVMEMetaObject::writeProperty(int id, double v) { - if (type != QMetaType::QRectF) - setValue(QRectF()); - - return *(QRectF *)(dataPtr()); + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = QV4::Primitive::fromDouble(v); } -const QSizeF &QQmlVMEVariant::asQSizeF() +void QQmlVMEMetaObject::writeProperty(int id, const QString& v) { - if (type != QMetaType::QSizeF) - setValue(QSizeF()); - - return *(QSizeF *)(dataPtr()); + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = cache->engine->newString(v); } -const QPointF &QQmlVMEVariant::asQPointF() +void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v) { - if (type != QMetaType::QPointF) - setValue(QPointF()); - - return *(QPointF *)(dataPtr()); + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } -void QQmlVMEVariant::setValue(QObject *v, QQmlVMEMetaObject *target, int index) +void QQmlVMEMetaObject::writeProperty(int id, const QDate& v) { - if (type != QMetaType::QObjectStar) { - cleanup(); - type = QMetaType::QObjectStar; - new (dataPtr()) QQmlVMEVariantQObjectPtr(false); - } - reinterpret_cast<QQmlVMEVariantQObjectPtr*>(dataPtr())->setGuardedValue(v, target, index); + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } -void QQmlVMEVariant::setValue(const QVariant &v) +void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v) { - if (type != qMetaTypeId<QVariant>()) { - cleanup(); - type = qMetaTypeId<QVariant>(); - new (dataPtr()) QVariant(v); - } else { - *(QVariant *)(dataPtr()) = v; - } + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } -void QQmlVMEVariant::setValue(int v) +void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v) { - if (type != QMetaType::Int) { - cleanup(); - type = QMetaType::Int; - } - *(int *)(dataPtr()) = v; + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } -void QQmlVMEVariant::setValue(bool v) +void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v) { - if (type != QMetaType::Bool) { - cleanup(); - type = QMetaType::Bool; - } - *(bool *)(dataPtr()) = v; + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } -void QQmlVMEVariant::setValue(double v) +void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v) { - if (type != QMetaType::Double) { - cleanup(); - type = QMetaType::Double; - } - *(double *)(dataPtr()) = v; + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } -void QQmlVMEVariant::setValue(const QString &v) +void QQmlVMEMetaObject::writeProperty(int id, QObject* v) { - if (type != QMetaType::QString) { - cleanup(); - type = QMetaType::QString; - new (dataPtr()) QString(v); - } else { - *(QString *)(dataPtr()) = v; - } -} + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + *(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v); -void QQmlVMEVariant::setValue(const QUrl &v) -{ - if (type != QMetaType::QUrl) { - cleanup(); - type = QMetaType::QUrl; - new (dataPtr()) QUrl(v); - } else { - *(QUrl *)(dataPtr()) = v; + QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id); + if (v && !guard) { + guard = new QQmlVMEVariantQObjectPtr(); + varObjectGuards.append(guard); } + if (guard) + guard->setGuardedValue(v, this, id); } -void QQmlVMEVariant::setValue(const QTime &v) +int QQmlVMEMetaObject::readPropertyAsInt(int id) { - if (type != QMetaType::QTime) { - cleanup(); - type = QMetaType::QTime; - new (dataPtr()) QTime(v); - } else { - *(QTime *)(dataPtr()) = v; - } -} + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return 0; -void QQmlVMEVariant::setValue(const QDate &v) -{ - if (type != QMetaType::QDate) { - cleanup(); - type = QMetaType::QDate; - new (dataPtr()) QDate(v); - } else { - *(QDate *)(dataPtr()) = v; - } + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + if (!sv->isInt32()) + return 0; + return sv->integerValue(); } -void QQmlVMEVariant::setValue(const QDateTime &v) +bool QQmlVMEMetaObject::readPropertyAsBool(int id) { - if (type != QMetaType::QDateTime) { - cleanup(); - type = QMetaType::QDateTime; - new (dataPtr()) QDateTime(v); - } else { - *(QDateTime *)(dataPtr()) = v; - } -} + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return false; -void QQmlVMEVariant::setValue(const QRectF &v) -{ - if (type != QMetaType::QRectF) { - cleanup(); - type = QMetaType::QRectF; - new (dataPtr()) QRectF(v); - } else { - *(QRectF *)(dataPtr()) = v; - } + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + if (!sv->isBoolean()) + return false; + return sv->booleanValue(); } -void QQmlVMEVariant::setValue(const QPointF &v) +double QQmlVMEMetaObject::readPropertyAsDouble(int id) { - if (type != QMetaType::QPointF) { - cleanup(); - type = QMetaType::QPointF; - new (dataPtr()) QPointF(v); - } else { - *(QPointF *)(dataPtr()) = v; - } -} + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return 0.0; -void QQmlVMEVariant::setValue(const QSizeF &v) -{ - if (type != QMetaType::QSizeF) { - cleanup(); - type = QMetaType::QSizeF; - new (dataPtr()) QSizeF(v); - } else { - *(QSizeF *)(dataPtr()) = v; - } + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + if (!sv->isDouble()) + return 0.0; + return sv->doubleValue(); } -void QQmlVMEVariant::ensureValueType(int t) +QString QQmlVMEMetaObject::readPropertyAsString(int id) { - if (type != t) { - cleanup(); - type = t; - QQml_valueTypeProvider()->initValueType(t, dataPtr(), dataSize()); - } -} + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return QString(); -QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint() - : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint) -{ + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + if (!sv->isString()) + return QString(); + return sv->stringValue()->toQString(); } -void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **) +QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) { - QQmlVMEMetaObjectEndpoint *vmee = static_cast<QQmlVMEMetaObjectEndpoint*>(e); - vmee->tryConnect(); + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return QUrl(); + + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); + if (!v || v->d()->data.type() != QVariant::Url) + return QUrl(); + return v->d()->data.value<QUrl>(); } -void QQmlVMEMetaObjectEndpoint::tryConnect() +QDate QQmlVMEMetaObject::readPropertyAsDate(int id) { - int aliasId = this - metaObject->aliasEndpoints; - - if (metaObject.flag()) { - // This is actually notify - int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount; - metaObject->activate(metaObject->object, sigIdx, 0); - } else { - QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId; - if (!d->isObjectAlias()) { - QQmlContextData *ctxt = metaObject->ctxt; - QObject *target = ctxt->idValues[d->contextIdx].data(); - if (!target) - return; - - if (d->notifySignal != -1) - connect(target, d->notifySignal, ctxt->engine); - } + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return QDate(); - metaObject.setFlag(); - } + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); + if (!v || v->d()->data.type() != QVariant::Date) + return QDate(); + return v->d()->data.value<QDate>(); } -QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o) +QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) { - if (!hasAssignedMetaObjectData) { - *static_cast<QMetaObject *>(this) = *cache->createMetaObject(); - - if (parent.isT1()) - this->d.superdata = parent.asT1()->toDynamicMetaObject(o); - else - this->d.superdata = parent.asT2(); + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return QDateTime(); - hasAssignedMetaObjectData = true; - } - - return this; + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); + if (!v || v->d()->data.type() != QVariant::DateTime) + return QDateTime(); + return v->d()->data.value<QDateTime>(); } -QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, - QQmlPropertyCache *cache, - const QQmlVMEMetaData *meta, QV4::ExecutionContext *qmlBindingContext, QQmlCompiledData *compiledData) -: object(obj), - ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta), - hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1), - varPropertiesInitialized(false), interceptors(0), v8methods(0) +QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) { - QObjectPrivate *op = QObjectPrivate::get(obj); + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return QSizeF(); - if (op->metaObject) { - parent = op->metaObject; - // Use the extra flag in QBiPointer to know if we can safely cast parent.asT1() to QQmlVMEMetaObject* - parent.setFlagValue(QQmlData::get(obj)->hasVMEMetaObject); - } else - parent = obj->metaObject(); - - op->metaObject = this; - QQmlData::get(obj)->hasVMEMetaObject = true; - - data = new QQmlVMEVariant[metaData->propertyCount - metaData->varPropertyCount]; - - aConnected.resize(metaData->aliasCount); - int list_type = qMetaTypeId<QQmlListProperty<QObject> >(); - int qobject_type = qMetaTypeId<QObject*>(); - int variant_type = qMetaTypeId<QVariant>(); - // Need JS wrapper to ensure variant and var properties are marked. - // ### FIXME: I hope that this can be removed once we have the proper scope chain - // set up and the JS wrappers always exist. - bool needsJSWrapper = (metaData->varPropertyCount > 0); - - // ### Optimize - for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) { - int t = (metaData->propertyData() + ii)->propertyType; - if (t == list_type) { - listProperties.append(List(methodOffset() + ii, this)); - data[ii].setValue(listProperties.count() - 1); - } else if (!needsJSWrapper && (t == qobject_type || t == variant_type)) { - needsJSWrapper = true; - } - } - - firstVarPropertyIndex = metaData->propertyCount - metaData->varPropertyCount; + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); + if (!v || v->d()->data.type() != QVariant::SizeF) + return QSizeF(); + return v->d()->data.value<QSizeF>(); +} - if (needsJSWrapper) - ensureQObjectWrapper(); +QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) +{ + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return QPointF(); - if (qmlBindingContext && metaData->methodCount) { - v8methods = new QV4::PersistentValue[metaData->methodCount]; + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); + if (!v || v->d()->data.type() != QVariant::PointF) + return QPointF(); + return v->d()->data.value<QPointF>(); +} - QV4::CompiledData::CompilationUnit *compilationUnit = compiledData->compilationUnit; - QV4::Scope scope(QQmlEnginePrivate::get(ctxt->engine)->v4engine()); - QV4::ScopedObject o(scope); - for (int index = 0; index < metaData->methodCount; ++index) { - QQmlVMEMetaData::MethodData *data = metaData->methodData() + index; +QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) +{ + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return 0; - QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[data->runtimeFunctionIndex]; - o = QV4::FunctionObject::createScriptFunction(qmlBindingContext, runtimeFunction); - v8methods[index].set(qmlBindingContext->engine(), o); - } - } + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + const QV4::QObjectWrapper *wrapper = sv->as<QV4::QObjectWrapper>(); + if (!wrapper) + return 0; + return wrapper->object(); } -QQmlVMEMetaObject::~QQmlVMEMetaObject() +QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) { - if (parent.isT1()) parent.asT1()->objectDestroyed(object); - delete [] data; - delete [] aliasEndpoints; - delete [] v8methods; + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) + return QRectF(); - qDeleteAll(varObjectGuards); + QV4::Scope scope(cache->engine); + QV4::ScopedValue sv(scope, *(md->data() + id)); + const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); + if (!v || v->d()->data.type() != QVariant::RectF) + return QRectF(); + return v->d()->data.value<QRectF>(); } -int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) +int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void **a) { + Q_ASSERT(o == object); + Q_UNUSED(o); + int id = _id; if (c == QMetaObject::WriteProperty && interceptors && !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyPrivate::BypassInterceptor)) { @@ -668,8 +544,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) int t = (metaData->propertyData() + id)->propertyType; bool needActivate = false; - if (id >= firstVarPropertyIndex) { - Q_ASSERT(t == QMetaType::QVariant); + if (t == QQmlVMEMetaData::VarPropertyType) { // the context can be null if accessing var properties from cpp after re-parenting an item. QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine(); @@ -689,50 +564,57 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) if (c == QMetaObject::ReadProperty) { switch(t) { case QVariant::Int: - *reinterpret_cast<int *>(a[0]) = data[id].asInt(); + *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id); break; case QVariant::Bool: - *reinterpret_cast<bool *>(a[0]) = data[id].asBool(); + *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id); break; case QVariant::Double: - *reinterpret_cast<double *>(a[0]) = data[id].asDouble(); + *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id); break; case QVariant::String: - *reinterpret_cast<QString *>(a[0]) = data[id].asQString(); + *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id); break; case QVariant::Url: - *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl(); + *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id); break; case QVariant::Date: - *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate(); + *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id); break; case QVariant::DateTime: - *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime(); + *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id); break; case QVariant::RectF: - *reinterpret_cast<QRectF *>(a[0]) = data[id].asQRectF(); + *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id); break; case QVariant::SizeF: - *reinterpret_cast<QSizeF *>(a[0]) = data[id].asQSizeF(); + *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id); break; case QVariant::PointF: - *reinterpret_cast<QPointF *>(a[0]) = data[id].asQPointF(); + *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id); break; case QMetaType::QObjectStar: - *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject(); + *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); break; case QMetaType::QVariant: *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); break; default: - QQml_valueTypeProvider()->readValueType(data[id].dataType(), data[id].dataPtr(), data->dataSize(), t, a[0]); + { + QV4::MemberData *md = propertiesAsMemberData(); + if (md) { + QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + if (v) + QQml_valueTypeProvider()->readValueType(v->d()->data, a[0], t); + } break; } + } if (t == qMetaTypeId<QQmlListProperty<QObject> >()) { - int listIndex = data[id].asInt(); + const int listIndex = readPropertyAsInt(id); const List *list = &listProperties.at(listIndex); *reinterpret_cast<QQmlListProperty<QObject> *>(a[0]) = - QQmlListProperty<QObject>(object, (void *)list, + QQmlListProperty<QObject>(object, const_cast<List *>(list), list_append, list_count, list_at, list_clear); } @@ -741,58 +623,67 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) switch(t) { case QVariant::Int: - needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt(); - data[id].setValue(*reinterpret_cast<int *>(a[0])); + needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id); + writeProperty(id, *reinterpret_cast<int *>(a[0])); break; case QVariant::Bool: - needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool(); - data[id].setValue(*reinterpret_cast<bool *>(a[0])); + needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id); + writeProperty(id, *reinterpret_cast<bool *>(a[0])); break; case QVariant::Double: - needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble(); - data[id].setValue(*reinterpret_cast<double *>(a[0])); + needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id); + writeProperty(id, *reinterpret_cast<double *>(a[0])); break; case QVariant::String: - needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString(); - data[id].setValue(*reinterpret_cast<QString *>(a[0])); + needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id); + writeProperty(id, *reinterpret_cast<QString *>(a[0])); break; case QVariant::Url: - needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl(); - data[id].setValue(*reinterpret_cast<QUrl *>(a[0])); + needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id); + writeProperty(id, *reinterpret_cast<QUrl *>(a[0])); break; case QVariant::Date: - needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate(); - data[id].setValue(*reinterpret_cast<QDate *>(a[0])); + needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id); + writeProperty(id, *reinterpret_cast<QDate *>(a[0])); break; case QVariant::DateTime: - needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime(); - data[id].setValue(*reinterpret_cast<QDateTime *>(a[0])); + needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id); + writeProperty(id, *reinterpret_cast<QDateTime *>(a[0])); break; case QVariant::RectF: - needActivate = *reinterpret_cast<QRectF *>(a[0]) != data[id].asQRectF(); - data[id].setValue(*reinterpret_cast<QRectF *>(a[0])); + needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id); + writeProperty(id, *reinterpret_cast<QRectF *>(a[0])); break; case QVariant::SizeF: - needActivate = *reinterpret_cast<QSizeF *>(a[0]) != data[id].asQSizeF(); - data[id].setValue(*reinterpret_cast<QSizeF *>(a[0])); + needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id); + writeProperty(id, *reinterpret_cast<QSizeF *>(a[0])); break; case QVariant::PointF: - needActivate = *reinterpret_cast<QPointF *>(a[0]) != data[id].asQPointF(); - data[id].setValue(*reinterpret_cast<QPointF *>(a[0])); + needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id); + writeProperty(id, *reinterpret_cast<QPointF *>(a[0])); break; case QMetaType::QObjectStar: - needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject(); - data[id].setValue(*reinterpret_cast<QObject **>(a[0]), this, id); + needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id); + writeProperty(id, *reinterpret_cast<QObject **>(a[0])); break; case QMetaType::QVariant: writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); break; - default: - data[id].ensureValueType(t); - needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], data[id].dataPtr(), data[id].dataSize()); - QQml_valueTypeProvider()->writeValueType(t, a[0], data[id].dataPtr(), data[id].dataSize()); + default: { + QV4::MemberData *md = propertiesAsMemberData(); + if (md) { + QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + if (!v) { + *(md->data() + id) = cache->engine->newVariantObject(QVariant()); + v = (md->data() + id)->as<QV4::VariantObject>(); + } + QQml_valueTypeProvider()->initValueType(t, v->d()->data); + needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], v->d()->data); + QQml_valueTypeProvider()->writeValueType(t, a[0], v->d()->data); + } break; } + } } } @@ -936,126 +827,122 @@ QV4::ReturnedValue QQmlVMEMetaObject::method(int index) return QV4::Primitive::undefinedValue().asReturnedValue(); } - if (!v8methods) - v8methods = new QV4::PersistentValue[metaData->methodCount]; + if (!methods) + methods = new QV4::PersistentValue[metaData->methodCount]; - return v8methods[index].value(); + return methods[index].value(); } QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) { - Q_ASSERT(id >= firstVarPropertyIndex); + Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType); - if (ensureVarPropertiesAllocated()) { - QV4::Scope scope(varProperties.engine()); - QV4::ScopedObject o(scope, varProperties.value()); - return o->getIndexed(id - firstVarPropertyIndex); - } + QV4::MemberData *md = propertiesAsMemberData(); + if (md) + return (md->data() + id)->asReturnedValue(); return QV4::Primitive::undefinedValue().asReturnedValue(); } QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) { - if (id >= firstVarPropertyIndex) { - if (ensureVarPropertiesAllocated()) { - QV4::ExecutionEngine *v4 = varProperties.engine(); - QV4::Scope scope(v4); - QV4::ScopedObject o(scope, varProperties.value()); - QV4::ScopedValue val(scope, o->getIndexed(id - firstVarPropertyIndex)); - return scope.engine->toVariant(val, -1); - } - return QVariant(); - } else { - if (data[id].dataType() == QMetaType::QObjectStar) { - return QVariant::fromValue(data[id].asQObject()); - } else { - return data[id].asQVariant(); - } + QV4::MemberData *md = propertiesAsMemberData(); + if (md) { + const QV4::QObjectWrapper *wrapper = (md->data() + id)->as<QV4::QObjectWrapper>(); + if (wrapper) + return QVariant::fromValue(wrapper->object()); + const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + if (v) + return v->d()->data; + return cache->engine->toVariant(*(md->data() + id), -1); } + return QVariant(); } void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) { - Q_ASSERT(id >= firstVarPropertyIndex); - if (!ensureVarPropertiesAllocated()) + Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType); + + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) return; - QV4::Scope scope(varProperties.engine()); // Importantly, if the current value is a scarce resource, we need to ensure that it // gets automatically released by the engine if no other references to it exist. - QV4::ScopedObject vp(scope, varProperties.value()); - QV4::Scoped<QV4::VariantObject> oldv(scope, vp->getIndexed(id - firstVarPropertyIndex)); - if (!!oldv) - oldv->removeVmePropertyReference(); + QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>(); + if (oldVariant) + oldVariant->removeVmePropertyReference(); QObject *valueObject = 0; QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id); - QV4::ScopedObject o(scope, value); - if (o) { - // And, if the new value is a scarce resource, we need to ensure that it does not get - // automatically released by the engine until no other references to it exist. - if (QV4::VariantObject *v = o->as<QV4::VariantObject>()) { - v->addVmePropertyReference(); - } else if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) { - // We need to track this QObject to signal its deletion - valueObject = wrapper->object(); - - // Do we already have a QObject guard for this property? - if (valueObject && !guard) { - guard = new QQmlVMEVariantQObjectPtr(true); - varObjectGuards.append(guard); - } + // And, if the new value is a scarce resource, we need to ensure that it does not get + // automatically released by the engine until no other references to it exist. + if (QV4::VariantObject *v = const_cast<QV4::VariantObject*>(value.as<QV4::VariantObject>())) { + v->addVmePropertyReference(); + } else if (QV4::QObjectWrapper *wrapper = const_cast<QV4::QObjectWrapper*>(value.as<QV4::QObjectWrapper>())) { + // We need to track this QObject to signal its deletion + valueObject = wrapper->object(); + + // Do we already have a QObject guard for this property? + if (valueObject && !guard) { + guard = new QQmlVMEVariantQObjectPtr(); + varObjectGuards.append(guard); } } - if (guard) { + if (guard) guard->setGuardedValue(valueObject, this, id); - } // Write the value and emit change signal as appropriate. - vp->putIndexed(id - firstVarPropertyIndex, value); + *(md->data() + id) = value; activate(object, methodOffset() + id, 0); } void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) { - if (id >= firstVarPropertyIndex) { - if (!ensureVarPropertiesAllocated()) + if ((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType) { + QV4::MemberData *md = propertiesAsMemberData(); + if (!md) return; - QV4::Scope scope(varProperties.engine()); - // Importantly, if the current value is a scarce resource, we need to ensure that it // gets automatically released by the engine if no other references to it exist. - QV4::ScopedObject vp(scope, varProperties.value()); - QV4::Scoped<QV4::VariantObject> oldv(scope, vp->getIndexed(id - firstVarPropertyIndex)); - if (!!oldv) + QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>(); + if (oldv) oldv->removeVmePropertyReference(); // And, if the new value is a scarce resource, we need to ensure that it does not get // automatically released by the engine until no other references to it exist. - QV4::ScopedValue newv(scope, scope.engine->fromVariant(value)); + QV4::Scope scope(cache->engine); + QV4::ScopedValue newv(scope, cache->engine->fromVariant(value)); QV4::Scoped<QV4::VariantObject> v(scope, newv); if (!!v) v->addVmePropertyReference(); // Write the value and emit change signal as appropriate. QVariant currentValue = readPropertyAsVariant(id); - vp->putIndexed(id - firstVarPropertyIndex, newv); + *(md->data() + id) = newv; if ((currentValue.userType() != value.userType() || currentValue != value)) activate(object, methodOffset() + id, 0); } else { bool needActivate = false; if (value.userType() == QMetaType::QObjectStar) { - QObject *o = *(QObject **)value.data(); - needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o); - data[id].setValue(o, this, id); + QObject *o = *(QObject *const *)value.data(); + needActivate = readPropertyAsQObject(id) != o; // TODO: still correct? + writeProperty(id, o); } else { - needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() || - data[id].asQVariant().userType() != value.userType() || - data[id].asQVariant() != value); - data[id].setValue(value); + QV4::MemberData *md = propertiesAsMemberData(); + if (md) { + QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + needActivate = (!v || + v->d()->data.userType() != value.userType() || + v->d()->data != value); + if (v) + v->removeVmePropertyReference(); + *(md->data() + id) = cache->engine->newVariantObject(value); + v = static_cast<QV4::VariantObject *>(md->data() + id); + v->addVmePropertyReference(); + } } if (needActivate) @@ -1137,11 +1024,11 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); - if (!v8methods) - v8methods = new QV4::PersistentValue[metaData->methodCount]; + if (!methods) + methods = new QV4::PersistentValue[metaData->methodCount]; int methodIndex = index - methodOffset() - plainSignals; - v8methods[methodIndex].set(function.as<QV4::Object>()->engine(), function); + methods[methodIndex].set(function.as<QV4::Object>()->engine(), function); } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) @@ -1163,58 +1050,47 @@ void QQmlVMEMetaObject::setVMEProperty(int index, const QV4::Value &v) return writeVarProperty(index - propOffset(), v); } -bool QQmlVMEMetaObject::ensureVarPropertiesAllocated() +bool QQmlVMEMetaObject::ensurePropertiesAllocated() { - if (!varPropertiesInitialized) - allocateVarPropertiesArray(); + if (!propertiesInitialized) + allocateProperties(); // in some situations, the QObject's v8object (and associated v8 data, // such as the varProperties array) will have been cleaned up, but the // QObject ptr will not yet have been deleted (eg, waiting on deleteLater). // In this situation, the varProperties handle will be (and should remain) // empty. - return !varProperties.isUndefined(); + return !properties.isUndefined(); } void QQmlVMEMetaObject::ensureQObjectWrapper() { - Q_ASSERT(ctxt && ctxt->engine); - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine); - QV4::ExecutionEngine *v4 = ep->v4engine(); + Q_ASSERT(cache && cache->engine); + QV4::ExecutionEngine *v4 = cache->engine; QV4::QObjectWrapper::wrap(v4, object); } void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) { - QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); - QV4::ExecutionEngine *v4 = (ep == 0) ? 0 : ep->v4engine(); + QV4::ExecutionEngine *v4 = cache ? cache->engine : 0; if (v4 != e) return; - varProperties.markOnce(e); - - // add references created by VMEVariant properties - int maxDataIdx = metaData->propertyCount - metaData->varPropertyCount; - for (int ii = 0; ii < maxDataIdx; ++ii) { // XXX TODO: optimize? - if (data[ii].dataType() == QMetaType::QObjectStar) { - // possible QObject reference. - if (QObject *ref = data[ii].asQObject()) - QV4::QObjectWrapper::markWrapper(ref, e); - } - } + properties.markOnce(e); if (QQmlVMEMetaObject *parent = parentVMEMetaObject()) parent->mark(e); } -void QQmlVMEMetaObject::allocateVarPropertiesArray() +void QQmlVMEMetaObject::allocateProperties() { - QQmlEngine *qml = qmlEngine(object); - Q_ASSERT(qml); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(qml->handle()); - QV4::Scope scope(v4); - varProperties.set(scope.engine, v4->newArrayObject(metaData->varPropertyCount)); - varPropertiesInitialized = true; + Q_ASSERT(cache && cache->engine); + QV4::ExecutionEngine *v4 = cache->engine; + QV4::Heap::MemberData *data = QV4::MemberData::reallocate(v4, 0, metaData->propertyCount); + properties.set(v4, data); + for (uint i = 0; i < data->size; ++i) + data->data[i] = QV4::Encode::undefined(); + propertiesInitialized = true; } bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index 44809a26f0..427e751f5d 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2015 BasysKom GmbH. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -71,7 +72,6 @@ QT_BEGIN_NAMESPACE struct QQmlVMEMetaData { - short varPropertyCount; short propertyCount; short aliasCount; short signalCount; @@ -108,6 +108,10 @@ struct QQmlVMEMetaData } }; + enum { + VarPropertyType = -1 + }; + struct PropertyData { int propertyType; }; @@ -119,7 +123,7 @@ struct QQmlVMEMetaData }; PropertyData *propertyData() const { - return (PropertyData *)(((const char *)this) + sizeof(QQmlVMEMetaData)); + return (PropertyData *)(((char *)const_cast<QQmlVMEMetaData *>(this)) + sizeof(QQmlVMEMetaData)); } AliasData *aliasData() const { @@ -135,15 +139,14 @@ class QQmlVMEMetaObject; class QQmlVMEVariantQObjectPtr : public QQmlGuard<QObject> { public: - inline QQmlVMEVariantQObjectPtr(bool isVar); + inline QQmlVMEVariantQObjectPtr(); inline ~QQmlVMEVariantQObjectPtr(); inline void objectDestroyed(QObject *); inline void setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index); QQmlVMEMetaObject *m_target; - unsigned m_isVar : 1; - int m_index : 31; + int m_index; }; class QQmlVMEVariant; @@ -177,7 +180,7 @@ public: static QQmlVMEMetaObject *getForSignal(QObject *o, int coreIndex); protected: - virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + virtual int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a); public: friend class QQmlVMEMetaObjectEndpoint; @@ -195,14 +198,37 @@ public: inline int signalCount() const; bool hasAssignedMetaObjectData; - QQmlVMEVariant *data; QQmlVMEMetaObjectEndpoint *aliasEndpoints; - QV4::WeakValue varProperties; - int firstVarPropertyIndex; - bool varPropertiesInitialized; - inline void allocateVarPropertiesArray(); - inline bool ensureVarPropertiesAllocated(); + QV4::WeakValue properties; + bool propertiesInitialized; + inline void allocateProperties(); + inline bool ensurePropertiesAllocated(); + QV4::MemberData *propertiesAsMemberData(); + + int readPropertyAsInt(int id); + bool readPropertyAsBool(int id); + double readPropertyAsDouble(int id); + QString readPropertyAsString(int id); + QSizeF readPropertyAsSizeF(int id); + QPointF readPropertyAsPointF(int id); + QUrl readPropertyAsUrl(int id); + QDate readPropertyAsDate(int id); + QDateTime readPropertyAsDateTime(int id); + QRectF readPropertyAsRectF(int id); + QObject* readPropertyAsQObject(int id); + + void writeProperty(int id, int v); + void writeProperty(int id, bool v); + void writeProperty(int id, double v); + void writeProperty(int id, const QString& v); + void writeProperty(int id, const QPointF& v); + void writeProperty(int id, const QSizeF& v); + void writeProperty(int id, const QUrl& v); + void writeProperty(int id, const QDate& v); + void writeProperty(int id, const QDateTime& v); + void writeProperty(int id, const QRectF& v); + void writeProperty(int id, QObject *v); void ensureQObjectWrapper(); @@ -213,7 +239,7 @@ public: QQmlPropertyValueInterceptor *interceptors; - QV4::PersistentValue *v8methods; + QV4::PersistentValue *methods; QV4::ReturnedValue method(int); QV4::ReturnedValue readVarProperty(int); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 0edb672517..0870e2b2c5 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -95,16 +95,6 @@ static inline QQmlXMLHttpRequestData *xhrdata(ExecutionEngine *v4) return (QQmlXMLHttpRequestData *)v4->v8Engine->xmlHttpRequestData(); } -static ReturnedValue constructMeObject(const Value &thisObj, ExecutionEngine *v4) -{ - Scope scope(v4); - ScopedObject meObj(scope, v4->newObject()); - meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ThisObject"))), thisObj); - ScopedValue v(scope, QmlContextWrapper::qmlScope(v4, v4->callingQmlContext(), 0)); - meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ActivationObject"))), v); - return meObj.asReturnedValue(); -} - QQmlXMLHttpRequestData::QQmlXMLHttpRequestData() { } @@ -1015,7 +1005,7 @@ public: Opened = 1, HeadersReceived = 2, Loading = 3, Done = 4 }; - QQmlXMLHttpRequest(ExecutionEngine *engine, QNetworkAccessManager *manager); + QQmlXMLHttpRequest(QNetworkAccessManager *manager); virtual ~QQmlXMLHttpRequest(); bool sendFlag() const; @@ -1024,9 +1014,9 @@ public: int replyStatus() const; QString replyStatusText() const; - ReturnedValue open(const Value &me, const QString &, const QUrl &, LoadType); - ReturnedValue send(const Value &me, const QByteArray &); - ReturnedValue abort(const Value &me); + ReturnedValue open(Object *thisObject, QQmlContextData *context, const QString &, const QUrl &, LoadType); + ReturnedValue send(Object *thisObject, QQmlContextData *context, const QByteArray &); + ReturnedValue abort(Object *thisObject, QQmlContextData *context); void addHeader(const QString &, const QString &); QString header(const QString &name); @@ -1049,7 +1039,6 @@ private slots: private: void requestFromUrl(const QUrl &url); - ExecutionEngine *v4; State m_state; bool m_errorFlag; bool m_sendFlag; @@ -1073,12 +1062,11 @@ private: #endif void readEncoding(); - ReturnedValue getMe() const; - void setMe(const Value &me); - PersistentValue m_me; + PersistentValue m_thisObject; + QQmlGuardedContextData m_qmlContext; - void dispatchCallbackImpl(const Value &me); - void dispatchCallback(const Value &me); + static void dispatchCallback(Object *thisObj, QQmlContextData *context); + void dispatchCallback(); int m_status; QString m_statusText; @@ -1094,9 +1082,8 @@ private: QV4::PersistentValue m_parsedDocument; }; -QQmlXMLHttpRequest::QQmlXMLHttpRequest(ExecutionEngine *engine, QNetworkAccessManager *manager) - : v4(engine) - , m_state(Unsent), m_errorFlag(false), m_sendFlag(false) +QQmlXMLHttpRequest::QQmlXMLHttpRequest(QNetworkAccessManager *manager) + : m_state(Unsent), m_errorFlag(false), m_sendFlag(false) , m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager) , m_responseType() , m_parsedDocument() @@ -1133,7 +1120,7 @@ QString QQmlXMLHttpRequest::replyStatusText() const return m_statusText; } -ReturnedValue QQmlXMLHttpRequest::open(const Value &me, const QString &method, const QUrl &url, LoadType loadType) +ReturnedValue QQmlXMLHttpRequest::open(Object *thisObject, QQmlContextData *context, const QString &method, const QUrl &url, LoadType loadType) { destroyNetwork(); m_sendFlag = false; @@ -1144,7 +1131,7 @@ ReturnedValue QQmlXMLHttpRequest::open(const Value &me, const QString &method, c m_request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, loadType == SynchronousLoad); m_state = Opened; m_addedHeaders.clear(); - dispatchCallback(me); + dispatchCallback(thisObject, context); return Encode::undefined(); } @@ -1279,21 +1266,22 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url) } } -ReturnedValue QQmlXMLHttpRequest::send(const Value &me, const QByteArray &data) +ReturnedValue QQmlXMLHttpRequest::send(Object *thisObject, QQmlContextData *context, const QByteArray &data) { m_errorFlag = false; m_sendFlag = true; m_redirectCount = 0; m_data = data; - setMe(me); + m_thisObject = thisObject; + m_qmlContext = context; requestFromUrl(m_url); return Encode::undefined(); } -ReturnedValue QQmlXMLHttpRequest::abort(const Value &me) +ReturnedValue QQmlXMLHttpRequest::abort(Object *thisObject, QQmlContextData *context) { destroyNetwork(); m_responseEntityBody = QByteArray(); @@ -1306,7 +1294,7 @@ ReturnedValue QQmlXMLHttpRequest::abort(const Value &me) m_state = Done; m_sendFlag = false; - dispatchCallback(me); + dispatchCallback(thisObject, context); } m_state = Unsent; @@ -1314,16 +1302,6 @@ ReturnedValue QQmlXMLHttpRequest::abort(const Value &me) return Encode::undefined(); } -ReturnedValue QQmlXMLHttpRequest::getMe() const -{ - return m_me.value(); -} - -void QQmlXMLHttpRequest::setMe(const Value &me) -{ - m_me.set(v4, me); -} - void QQmlXMLHttpRequest::readyRead() { m_status = @@ -1331,14 +1309,11 @@ void QQmlXMLHttpRequest::readyRead() m_statusText = QString::fromUtf8(m_network->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray()); - Scope scope(v4); - ScopedValue me(scope, m_me.value()); - // ### We assume if this is called the headers are now available if (m_state < HeadersReceived) { m_state = HeadersReceived; fillHeadersList (); - dispatchCallback(me); + dispatchCallback(); } bool wasEmpty = m_responseEntityBody.isEmpty(); @@ -1346,7 +1321,7 @@ void QQmlXMLHttpRequest::readyRead() if (wasEmpty && !m_responseEntityBody.isEmpty()) m_state = Loading; - dispatchCallback(me); + dispatchCallback(); } static const char *errorToString(QNetworkReply::NetworkError error) @@ -1377,9 +1352,6 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error) qWarning().nospace() << " " << error << ' ' << errorToString(error) << ' ' << m_statusText; } - Scope scope(v4); - ScopedValue me(scope, m_me.value()); - if (error == QNetworkReply::ContentAccessDenied || error == QNetworkReply::ContentOperationNotPermittedError || error == QNetworkReply::ContentNotFoundError || @@ -1388,15 +1360,14 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error) error == QNetworkReply::UnknownContentError || error == QNetworkReply::ProtocolInvalidOperationError) { m_state = Loading; - dispatchCallback(me); + dispatchCallback(); } else { m_errorFlag = true; m_responseEntityBody = QByteArray(); } m_state = Done; - - dispatchCallback(me); + dispatchCallback(); } #define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15 @@ -1428,7 +1399,7 @@ void QQmlXMLHttpRequest::finished() if (m_state < HeadersReceived) { m_state = HeadersReceived; fillHeadersList (); - dispatchCallback(*m_me.valueRef()); + dispatchCallback(); } m_responseEntityBody.append(m_network->readAll()); readEncoding(); @@ -1445,15 +1416,14 @@ void QQmlXMLHttpRequest::finished() destroyNetwork(); if (m_state < Loading) { m_state = Loading; - dispatchCallback(*m_me.valueRef()); + dispatchCallback(); } m_state = Done; - dispatchCallback(*m_me.valueRef()); + dispatchCallback(); - Scope scope(v4); - ScopedValue v(scope, Primitive::undefinedValue()); - setMe(v); + m_thisObject.clear(); + m_qmlContext.setContextData(0); } @@ -1567,57 +1537,38 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const return m_responseEntityBody; } -void QQmlXMLHttpRequest::dispatchCallbackImpl(const Value &me) +void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *context) { - QV4::Scope scope(v4); - ScopedObject o(scope, me); - if (!o) { - v4->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); - return; - } + Q_ASSERT(thisObj); - ScopedString s(scope, v4->newString(QStringLiteral("ThisObject"))); - ScopedObject thisObj(scope, o->get(s)); - if (!thisObj) { - v4->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); + if (!context) + // if the calling context object is no longer valid, then it has been + // deleted explicitly (e.g., by a Loader deleting the itemContext when + // the source is changed). We do nothing in this case, as the evaluation + // cannot succeed. return; - } - s = v4->newString(QStringLiteral("onreadystatechange")); + QV4::Scope scope(thisObj->engine()); + ScopedString s(scope, scope.engine->newString(QStringLiteral("onreadystatechange"))); ScopedFunctionObject callback(scope, thisObj->get(s)); if (!callback) { // not an error, but no onreadystatechange function to call. return; } - s = v4->newString(QStringLiteral("ActivationObject")); - ScopedObject activationObject(scope, o->get(s)); - if (!activationObject) { - v4->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject")); - return; - } + QV4::ScopedCallData callData(scope); + callData->thisObject = Encode::undefined(); + callback->call(callData); - QQmlContextData *callingContext = QmlContextWrapper::getContext(activationObject); - if (callingContext) { - QV4::ScopedCallData callData(scope); - callData->thisObject = activationObject.asReturnedValue(); - callback->call(callData); + if (scope.engine->hasException) { + QQmlError error = scope.engine->catchExceptionAsQmlError(); + QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error); } - - // if the callingContext object is no longer valid, then it has been - // deleted explicitly (e.g., by a Loader deleting the itemContext when - // the source is changed). We do nothing in this case, as the evaluation - // cannot succeed. - } -void QQmlXMLHttpRequest::dispatchCallback(const Value &me) +void QQmlXMLHttpRequest::dispatchCallback() { - dispatchCallbackImpl(me); - if (v4->hasException) { - QQmlError error = v4->catchExceptionAsQmlError(); - QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v4->qmlEngine()), error); - } + dispatchCallback(m_thisObject.as<Object>(), m_qmlContext.contextData()); } void QQmlXMLHttpRequest::destroyNetwork() @@ -1676,7 +1627,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject if (!ctor) return scope.engine->throwTypeError(); - QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine, scope.engine->v8Engine->networkAccessManager()); + QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager()); Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->alloc<QQmlXMLHttpRequestWrapper>(scope.engine, r)); ScopedObject proto(scope, ctor->d()->proto); w->setPrototype(proto); @@ -1813,8 +1764,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) if (!username.isNull()) url.setUserName(username); if (!password.isNull()) url.setPassword(password); - ScopedValue meObject(scope, constructMeObject(ctx->thisObject(), scope.engine)); - return r->open(meObject, method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad); + return r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad); } ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx) @@ -1880,8 +1830,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_send(CallContext *ctx) if (ctx->argc() > 0) data = ctx->args()[0].toQStringNoThrow().toUtf8(); - ScopedValue meObject(scope, constructMeObject(ctx->thisObject(), scope.engine)); - return r->send(meObject, data); + return r->send(w, scope.engine->callingQmlContext(), data); } ReturnedValue QQmlXMLHttpRequestCtor::method_abort(CallContext *ctx) @@ -1892,8 +1841,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_abort(CallContext *ctx) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - ScopedValue meObject(scope, constructMeObject(ctx->thisObject(), scope.engine)); - return r->abort(meObject); + return r->abort(w, scope.engine->callingQmlContext()); } ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx) diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 5d12244dcb..08bbbb8548 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -63,6 +63,7 @@ #include <private/qv4value_p.h> #include <private/qv4object_p.h> #include <private/qv4identifier_p.h> +#include <private/qqmlcontextwrapper_p.h> QT_BEGIN_NAMESPACE @@ -119,8 +120,8 @@ class QQmlV4Function public: int length() const { return callData->argc; } QV4::ReturnedValue operator[](int idx) { return (idx < callData->argc ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); } - QQmlContextData *context() { return ctx; } - QV4::ReturnedValue qmlGlobal() { return callData->thisObject.asReturnedValue(); } + QQmlContextData *context() { return e->qmlContextObject()->context.contextData(); } + QV4::ReturnedValue qmlGlobal() { return e->qmlContextObject()->asReturnedValue(); } void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; } QV4::ExecutionEngine *v4engine() const { return e; } private: @@ -129,16 +130,14 @@ private: QQmlV4Function(const QQmlV4Function &); QQmlV4Function &operator=(const QQmlV4Function &); - QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, - const QV4::Value &global, QQmlContextData *c, QV4::ExecutionEngine *e) - : callData(callData), retVal(retVal), ctx(c), e(e) + QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e) + : callData(callData), retVal(retVal), e(e) { - callData->thisObject = QV4::Value::fromReturnedValue(global.asReturnedValue()); + callData->thisObject = QV4::Encode::undefined(); } QV4::CallData *callData; QV4::Value *retVal; - QQmlContextData *ctx; QV4::ExecutionEngine *e; }; |