diff options
Diffstat (limited to 'src/qml/qml')
37 files changed, 789 insertions, 212 deletions
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 325f752cd5..9453e6480b 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -54,6 +54,7 @@ #include <QVariant> #include <QtCore/qdebug.h> +#include <QVector> QT_BEGIN_NAMESPACE @@ -195,7 +196,7 @@ class QQmlNonbindingBinding: public QQmlBinding { protected: void doUpdate(const DeleteWatcher &watcher, - QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE Q_DECL_FINAL + QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE { auto ep = QQmlEnginePrivate::get(scope.engine); ep->referenceScarceResources(); @@ -296,6 +297,55 @@ protected: } }; +class QQmlTranslationBinding : public GenericBinding<QMetaType::QString> { +public: + QQmlTranslationBinding(QV4::CompiledData::CompilationUnit *compilationUnit, const QV4::CompiledData::Binding *binding) + { + setCompilationUnit(compilationUnit); + m_binding = binding; + setSourceLocation(QQmlSourceLocation(compilationUnit->fileName(), binding->valueLocation.line, binding->valueLocation.column)); + } + + void doUpdate(const DeleteWatcher &watcher, + QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE Q_DECL_FINAL + { + if (watcher.wasDeleted()) + return; + + if (!isAddedToObject() || hasError()) + return; + + const QString result = m_binding->valueAsString(m_compilationUnit->data); + + Q_ASSERT(targetObject()); + + QQmlPropertyData *pd; + QQmlPropertyData vpd; + getPropertyData(&pd, &vpd); + Q_ASSERT(pd); + if (pd->propType() == QMetaType::QString) { + doStore(result, pd, flags); + } else { + QV4::ScopedString value(scope, scope.engine->newString(result)); + slowWrite(*pd, vpd, value, /*isUndefined*/false, flags); + } + } + +private: + const QV4::CompiledData::Binding *m_binding; +}; + +QQmlBinding *QQmlBinding::createTranslationBinding(QV4::CompiledData::CompilationUnit *unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt) +{ + QQmlTranslationBinding *b = new QQmlTranslationBinding(unit, binding); + + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(ctxt); + b->setScopeObject(obj); + + return b; +} + Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, const QV4::Value &result, @@ -535,6 +585,37 @@ void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyD } } +QVector<QQmlProperty> QQmlBinding::dependencies() const +{ + QVector<QQmlProperty> dependencies; + if (!m_target.data()) + return dependencies; + + for (const auto &guardList : { permanentGuards, activeGuards }) { + for (QQmlJavaScriptExpressionGuard *guard = guardList.first(); guard; guard = guardList.next(guard)) { + if (guard->signalIndex() == -1) // guard's sender is a QQmlNotifier, not a QObject*. + continue; + + QObject *senderObject = guard->senderAsObject(); + if (!senderObject) + continue; + + const QMetaObject *senderMeta = senderObject->metaObject(); + if (!senderMeta) + continue; + + for (int i = 0; i < senderMeta->propertyCount(); i++) { + QMetaProperty property = senderMeta->property(i); + if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) { + dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name()))); + } + } + } + } + + return dependencies; +} + class QObjectPointerBinding: public QQmlNonbindingBinding { QQmlMetaObject targetMetaObject; diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 0f2fb329f5..38d59a8919 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -77,6 +77,8 @@ public: const QString &url = QString(), quint16 lineNumber = 0); static QQmlBinding *create(const QQmlPropertyData *property, QV4::Function *function, QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope); + static QQmlBinding *createTranslationBinding(QV4::CompiledData::CompilationUnit *unit, const QV4::CompiledData::Binding *binding, + QObject *obj, QQmlContextData *ctxt); ~QQmlBinding(); void setTarget(const QQmlProperty &); @@ -100,6 +102,15 @@ public: QString expressionIdentifier() const override; void expressionChanged() override; + /** + * This method returns a snapshot of the currently tracked dependencies of + * this binding. The dependencies can change upon reevaluation. This method is + * used in GammaRay to visualize binding hierarchies. + * + * Call this method from the UI thread. + */ + QVector<QQmlProperty> dependencies() const; + protected: virtual void doUpdate(const DeleteWatcher &watcher, QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) = 0; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 4da6b7958c..e895f1df1b 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1060,20 +1060,52 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, enginePriv->incubate(incubator, forContextData); } +/* + This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData + arguments instead of QQmlContext which means we don't have to construct the rather weighty + wrapper class for every delegate item. + + This is used by QQmlDelegateModel. +*/ +void QQmlComponentPrivate::incubateObject( + QQmlIncubator *incubationTask, + QQmlComponent *component, + QQmlEngine *engine, + QQmlContextData *context, + QQmlContextData *forContext) +{ + QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask); + QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine); + QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component); + + incubatorPriv->compilationUnit = componentPriv->compilationUnit; + incubatorPriv->enginePriv = enginePriv; + incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext)); + incubatorPriv->subComponentToCreate = componentPriv->start; + + enginePriv->incubate(*incubationTask, forContext); +} + + + class QQmlComponentIncubator; namespace QV4 { namespace Heap { -struct QmlIncubatorObject : Object { +#define QmlIncubatorObjectMembers(class, Member) \ + Member(class, HeapValue, HeapValue, valuemap) \ + Member(class, HeapValue, HeapValue, statusChanged) \ + Member(class, Pointer, QmlContext *, qmlContext) \ + Member(class, NoMark, QQmlComponentIncubator *, incubator) \ + Member(class, NoMark, QQmlQPointer<QObject>, parent) + +DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) { + DECLARE_MARK_TABLE(QmlIncubatorObject); + void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); inline void destroy(); - QQmlComponentIncubator *incubator; - QQmlQPointer<QObject> parent; - QV4::Value valuemap; - QV4::Value statusChanged; - Pointer<Heap::QmlContext> qmlContext; }; } @@ -1089,8 +1121,6 @@ struct QmlIncubatorObject : public QV4::Object static void method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData); - static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e); - void statusChanged(QQmlIncubator::Status); void setInitialState(QObject *); }; @@ -1394,8 +1424,8 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) r->setPrototype(p); if (!valuemap->isUndefined()) - r->d()->valuemap = valuemap; - r->d()->qmlContext = v4->qmlContext(); + r->d()->valuemap.set(scope.engine, valuemap); + r->d()->qmlContext.set(scope.engine, v4->qmlContext()); r->d()->parent = parent; QQmlIncubator *incubator = r->d()->incubator; @@ -1479,7 +1509,7 @@ void QV4::QmlIncubatorObject::method_set_statusChanged(const BuiltinFunction *, if (!o || callData->argc < 1) THROW_TYPE_ERROR(); - o->d()->statusChanged = callData->args[0]; + o->d()->statusChanged.set(scope.engine, callData->args[0]); RETURN_UNDEFINED(); } @@ -1491,10 +1521,10 @@ QQmlComponentExtension::~QQmlComponentExtension() void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m) { Object::init(); - valuemap = QV4::Primitive::undefinedValue(); - statusChanged = QV4::Primitive::undefinedValue(); + valuemap.set(internalClass->engine, QV4::Primitive::undefinedValue()); + statusChanged.set(internalClass->engine, QV4::Primitive::undefinedValue()); parent.init(); - qmlContext = nullptr; + qmlContext.set(internalClass->engine, nullptr); incubator = new QQmlComponentIncubator(this, m); } @@ -1517,16 +1547,6 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o) } } -void QV4::QmlIncubatorObject::markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e) -{ - QmlIncubatorObject::Data *o = static_cast<QmlIncubatorObject::Data *>(that); - o->valuemap.mark(e); - o->statusChanged.mark(e); - if (o->qmlContext) - o->qmlContext->mark(e); - Object::markObjects(that, e); -} - void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) { QV4::Scope scope(engine()); diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 2a57f7b247..8a58a1ada0 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -88,6 +88,13 @@ public: void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate); static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v); + void incubateObject( + QQmlIncubator *incubationTask, + QQmlComponent *component, + QQmlEngine *engine, + QQmlContextData *context, + QQmlContextData *forContext); + QQmlTypeData *typeData; void typeDataReady(QQmlTypeData *) override; void typeDataProgress(QQmlTypeData *, qreal) override; diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index ecdaf41523..cc6e75a39c 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -121,13 +121,16 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const { Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer"); *ok = false; + + // we support one or two '.' in the enum phrase: + // * <TypeName>.<EnumValue> + // * <TypeName>.<ScopedEnumName>.<EnumValue> + int dot = script.indexOf('.'); - if (dot == -1) + if (dot == -1 || dot == script.length()-1) return -1; - QString scope = QString::fromUtf8(script.left(dot)); - QByteArray enumValue = script.mid(dot+1); if (scope != QLatin1String("Qt")) { if (imports.isNull()) @@ -142,9 +145,20 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const type = result.type; } - return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok); + if (!type.isValid()) + return -1; + + int dot2 = script.indexOf('.', dot+1); + const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1; + QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1); + QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray()); + if (!scopedEnumName.isEmpty()) + return type.scopedEnumValue(engine, scopedEnumName, enumValue, ok); + else + return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok); } + QByteArray enumValue = script.mid(dot + 1); const QMetaObject *mo = StaticQtMetaObject::get(); int i = mo->enumeratorCount(); while (i--) { diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index f4656bafd2..8e3b0a790f 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -453,6 +453,12 @@ The following functions are also on the Qt object. \li \c "windows" - Windows \li \c "winrt" - WinRT / UWP \endlist + + \row + \li \c platform.pluginName + \li This is the name of the platform set on the QGuiApplication instance + as returned by \l QGuiApplication::platformName() + \endtable */ @@ -778,7 +784,7 @@ class QQmlThreadNotifierProxyObject : public QObject public: QPointer<QObject> target; - virtual int qt_metacall(QMetaObject::Call, int methodIndex, void **a) { + int qt_metacall(QMetaObject::Call, int methodIndex, void **a) override { if (!target) return -1; @@ -1351,6 +1357,30 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled) } /*! + Refreshes all binding expressions that use strings marked for translation. + + Call this function after you have installed a new translator with + QCoreApplication::installTranslator, to ensure that your user-interface + shows up-to-date translations. + + \note Due to a limitation in the implementation, this function + refreshes all the engine's bindings, not only those that use strings + marked for translation. + This may be optimized in a future release. + + \since 5.10 +*/ +void QQmlEngine::retranslate() +{ + Q_D(QQmlEngine); + QQmlContextData *context = QQmlContextData::get(d->rootContext)->childContexts; + while (context) { + context->refreshExpressions(); + context = context->nextChild; + } +} + +/*! Returns the QQmlContext for the \a object, or 0 if no context has been set. @@ -1470,6 +1500,9 @@ bool QQmlEngine::event(QEvent *e) Q_D(QQmlEngine); if (e->type() == QEvent::User) d->doDeleteInEngineThread(); + else if (e->type() == QEvent::LanguageChange) { + retranslate(); + } return QJSEngine::event(e); } @@ -1519,9 +1552,9 @@ QQmlEngine *qmlEngine(const QObject *obj) QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) { - QQmlData *data = QQmlData::get(object); + QQmlData *data = QQmlData::get(object, create); if (!data) - return 0; // Attached properties are only on objects created by QML + return 0; // Attached properties are only on objects created by QML, unless explicitly requested (create==true) QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0; if (rv || !create) diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 8cada954fe..2bf4c0497b 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -144,6 +144,10 @@ public: bool outputWarningsToStandardError() const; void setOutputWarningsToStandardError(bool); +public Q_SLOTS: + void retranslate(); + +public: static QQmlContext *contextForObject(const QObject *); static void setContextForObject(QObject *, QQmlContext *); diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index 7939656107..6418812bae 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -343,6 +343,8 @@ QObject *QQmlGuiProvider::styleHints() return o; } +QString QQmlGuiProvider::pluginName() const { return QString(); } + static QQmlGuiProvider *guiProvider = 0; Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider) diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index 707814e781..5c46da0ea4 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -193,16 +193,6 @@ do { \ return QObjectPrivate::get(sender)->isSignalConnected(signalIdx); \ } while (0) -struct QQmlGraphics_DerivedObject : public QObject -{ - void setParent_noEvent(QObject *parent) { - bool sce = d_ptr->sendChildEvents; - d_ptr->sendChildEvents = false; - setParent(parent); - d_ptr->sendChildEvents = sce; - } -}; - /*! Returns true if the case of \a fileName is equivalent to the file case of \a fileName on disk, and false otherwise. @@ -230,7 +220,11 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int length = -1); */ inline void QQml_setParent_noEvent(QObject *object, QObject *parent) { - static_cast<QQmlGraphics_DerivedObject *>(object)->setParent_noEvent(parent); + QObjectPrivate *d_ptr = QObjectPrivate::get(object); + bool sce = d_ptr->sendChildEvents; + d_ptr->sendChildEvents = false; + object->setParent(parent); + d_ptr->sendChildEvents = sce; } class Q_QML_PRIVATE_EXPORT QQmlValueTypeProvider @@ -311,6 +305,7 @@ public: virtual QObject *styleHints(); virtual QStringList fontFamilies(); virtual bool openUrlExternally(QUrl &); + virtual QString pluginName() const; }; Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *); diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index f43ffb4c3c..b899e80470 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -296,7 +296,9 @@ public: bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor, QQmlType *type_return, QList<QQmlError> *errors, - QQmlType::RegistrationType registrationType); + QQmlType::RegistrationType registrationType, + QQmlImport::RecursionRestriction recursionRestriction + = QQmlImport::PreventRecursion); QUrl baseUrl; QString base; @@ -634,7 +636,8 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version) bool QQmlImports::resolveType(const QHashedStringRef &type, QQmlType *type_return, int *vmaj, int *vmin, QQmlImportNamespace** ns_return, QList<QQmlError> *errors, - QQmlType::RegistrationType registrationType) const + QQmlType::RegistrationType registrationType, + QQmlImport::RecursionRestriction recursionRestriction) const { QQmlImportNamespace* ns = d->findQualifiedNamespace(type); if (ns) { @@ -643,7 +646,8 @@ bool QQmlImports::resolveType(const QHashedStringRef &type, return true; } if (type_return) { - if (d->resolveType(type, vmaj, vmin, type_return, errors, registrationType)) { + if (d->resolveType(type, vmaj, vmin, type_return, errors, registrationType, + recursionRestriction)) { if (qmlImportTrace()) { #define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \ << ')' << "::resolveType: " << type.toString() << " => " @@ -728,9 +732,10 @@ bool QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &t } bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type, - int *vmajor, int *vminor, QQmlType* type_return, QString *base, + int *vmajor, int *vminor, QQmlType *type_return, QString *base, bool *typeRecursionDetected, - QQmlType::RegistrationType registrationType) const + QQmlType::RegistrationType registrationType, + QQmlImport::RecursionRestriction recursionRestriction) const { if (majversion >= 0 && minversion >= 0) { QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion); @@ -766,6 +771,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt // importing version -1 means import ALL versions if ((majversion == -1) || + (implicitlyImported && c.internal) || // allow the implicit import of internal types (c.majorVersion == majversion && c.minorVersion <= minversion)) { // Is this better than the previous candidate? if ((candidate == end) || @@ -777,7 +783,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt if (resolveLocalUrl(*base, c.fileName) != componentUrl) continue; // failed attempt to access an internal type } - if (*base == componentUrl) { + if (recursionRestriction == QQmlImport::PreventRecursion && *base == componentUrl) { if (typeRecursionDetected) *typeRecursionDetected = true; continue; // no recursion @@ -820,7 +826,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt } if (exists) { - if (base && (*base == qmlUrl)) { // no recursion + if (recursionRestriction == QQmlImport::PreventRecursion && base && (*base == qmlUrl)) { // no recursion if (typeRecursionDetected) *typeRecursionDetected = true; } else { @@ -838,7 +844,8 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor, QQmlType *type_return, QList<QQmlError> *errors, - QQmlType::RegistrationType registrationType) + QQmlType::RegistrationType registrationType, + QQmlImport::RecursionRestriction recursionRestriction) { QQmlImportNamespace *s = 0; int dot = type.indexOf(Dot); @@ -868,7 +875,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1); if (s) { if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors, - registrationType)) + registrationType, recursionRestriction)) return true; if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) { // qualified, and only 1 url @@ -892,13 +899,14 @@ QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, int *vmajor, int *vminor, QQmlType *type_return, QString *base, QList<QQmlError> *errors, - QQmlType::RegistrationType registrationType) + QQmlType::RegistrationType registrationType, + QQmlImport::RecursionRestriction recursionRestriction) { bool typeRecursionDetected = false; for (int i=0; i<imports.count(); ++i) { const QQmlImportInstance *import = imports.at(i); - if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, - base, &typeRecursionDetected, registrationType)) { + if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, base, + &typeRecursionDetected, registrationType, recursionRestriction)) { if (qmlCheckTypes()) { // check for type clashes for (int j = i+1; j<imports.count(); ++j) { @@ -1223,10 +1231,12 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba stableRelativePath.replace(Backslash, Slash); // remove optional versioning in dot notation from uri - int lastSlash = stableRelativePath.lastIndexOf(Slash); - if (lastSlash >= 0) { - int versionDot = stableRelativePath.indexOf(Dot, lastSlash); - if (versionDot >= 0) + int versionDot = stableRelativePath.lastIndexOf(Dot); + if (versionDot >= 0) { + int nextSlash = stableRelativePath.indexOf(Slash, versionDot); + if (nextSlash >= 0) + stableRelativePath.remove(versionDot, nextSlash - versionDot); + else stableRelativePath = stableRelativePath.left(versionDot); } @@ -1537,6 +1547,20 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix if (!url.endsWith(Slash) && !url.endsWith(Backslash)) url += Slash; + // ### For enum support, we are now adding the implicit import always (and earlier). Bail early + // if the implicit import has already been explicitly added, otherwise we can run into issues + // with duplicate imports. However remember that we attempted to add this as implicit import, to + // allow for the loading of internal types. + if (isImplicitImport) { + for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin(); + it != nameSpace->imports.constEnd(); ++it) { + if ((*it)->url == url) { + (*it)->implicitlyImported = true; + return true; + } + } + } + QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport); Q_ASSERT(inserted); @@ -1738,13 +1762,13 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e) // env import paths if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QML2_IMPORT_PATH"))) { - const QByteArray envImportPath = qgetenv("QML2_IMPORT_PATH"); + const QString envImportPath = qEnvironmentVariable("QML2_IMPORT_PATH"); #if defined(Q_OS_WIN) QLatin1Char pathSep(';'); #else QLatin1Char pathSep(':'); #endif - QStringList paths = QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts); + QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts); for (int ii = paths.count() - 1; ii >= 0; --ii) addImportPath(paths.at(ii)); } diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 9cb5340c68..6298dd9c22 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -70,6 +70,10 @@ class QQmlImportDatabase; class QQmlTypeLoader; class QQmlTypeLoaderQmldirContent; +namespace QQmlImport { + enum RecursionRestriction { PreventRecursion, AllowRecursion }; +} + struct QQmlImportInstance { QString uri; // e.g. QtQuick @@ -77,6 +81,7 @@ struct QQmlImportInstance int majversion; // the major version imported int minversion; // the minor version imported bool isLibrary; // true means that this is not a file import + bool implicitlyImported = false; QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir @@ -88,7 +93,8 @@ struct QQmlImportInstance bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type, int *vmajor, int *vminor, QQmlType* type_return, QString *base = 0, bool *typeRecursionDetected = 0, - QQmlType::RegistrationType = QQmlType::AnyRegistrationType) const; + QQmlType::RegistrationType = QQmlType::AnyRegistrationType, + QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const; }; class QQmlImportNamespace @@ -104,8 +110,8 @@ public: bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type, int *vmajor, int *vminor, QQmlType* type_return, QString *base = 0, QList<QQmlError> *errors = 0, - QQmlType::RegistrationType registrationType - = QQmlType::AnyRegistrationType); + QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType, + QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion); // Prefix when used as a qualified import. Otherwise empty. QHashedString prefix; @@ -132,8 +138,9 @@ public: int *version_major, int *version_minor, QQmlImportNamespace **ns_return, QList<QQmlError> *errors = 0, - QQmlType::RegistrationType registrationType - = QQmlType::AnyRegistrationType) const; + QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType, + QQmlImport::RecursionRestriction recursionRestriction + = QQmlImport::PreventRecursion) const; bool resolveType(QQmlImportNamespace *, const QHashedStringRef& type, QQmlType *type_return, int *version_major, int *version_minor, diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index eec5d1ae57..31c277d283 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -350,7 +350,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext()); QQmlContextData *qmlContext = context->qmlContext(); - const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); + const quint32_le *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) { Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount); @@ -359,7 +359,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct } Q_ASSERT(qmlContext->contextObject); - const QV4::CompiledData::LEUInt32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); + const quint32_le *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; for (int i = 0; i < contextPropertyDependencyCount; ++i) { const int propertyIndex = *contextPropertyDependency++; @@ -369,7 +369,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct } QObject *scopeObject = context->qmlScope(); - const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); + const quint32_le *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; for (int i = 0; i < scopePropertyDependencyCount; ++i) { const int propertyIndex = *scopePropertyDependency++; @@ -461,7 +461,12 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext, return; m_qmlScope.set(qmlContext->engine(), *qmlContext); m_v4Function = f; - m_compilationUnit = m_v4Function->compilationUnit; + setCompilationUnit(m_v4Function->compilationUnit); +} + +void QQmlJavaScriptExpression::setCompilationUnit(QV4::CompiledData::CompilationUnit *compilationUnit) +{ + m_compilationUnit = compilationUnit; } void QQmlJavaScriptExpression::clearActiveGuards() diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index eeed272793..e9a9f4feee 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -160,13 +160,7 @@ protected: } void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f); - -private: - friend class QQmlContextData; - friend class QQmlPropertyCapture; - friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); - - QQmlDelayedError *m_error; + void setCompilationUnit(QV4::CompiledData::CompilationUnit *compilationUnit); // We store some flag bits in the following flag pointers. // activeGuards:flag1 - notifyOnValueChanged @@ -175,6 +169,14 @@ private: QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards; QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards; +private: + friend class QQmlContextData; + friend class QQmlPropertyCapture; + friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); + friend class QQmlTranslationBinding; + + QQmlDelayedError *m_error; + QQmlContextData *m_context; QQmlJavaScriptExpression **m_prevExpression; QQmlJavaScriptExpression *m_nextExpression; diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index d94f7c56e4..43677e0d78 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -140,12 +140,13 @@ ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *has return Primitive::undefinedValue().asReturnedValue(); } -void QmlListWrapper::put(Managed *m, String *name, const Value &value) +bool QmlListWrapper::put(Managed *m, String *name, const Value &value) { // doesn't do anything. Should we throw? Q_UNUSED(m); Q_UNUSED(name); Q_UNUSED(value); + return false; } void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index b914c681f2..84dadba01a 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -95,7 +95,7 @@ struct Q_QML_EXPORT QmlListWrapper : Object static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); }; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 89f3ced2d6..f368e6dae6 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -170,8 +170,9 @@ public: ~QQmlTypePrivate(); void init() const; - void initEnums() const; + void initEnums(const QQmlPropertyCache *cache = 0) const; void insertEnums(const QMetaObject *metaObject) const; + void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const; QAtomicInt refCount; QQmlType::RegistrationType regType; @@ -227,6 +228,8 @@ public: mutable bool haveSuperType:1; mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects; mutable QStringHash<int> enums; + mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums + mutable QList<QStringHash<int>*> scopedEnums; static QHash<const QMetaObject *, int> attachedPropertyIds; @@ -271,8 +274,10 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) QQmlData::ensurePropertyCache(e, o); } else if (!url.isEmpty() && !qobjectApi(e)) { QQmlComponent component(e, url, QQmlComponent::PreferSynchronous); - QObject *o = component.create(); + QObject *o = component.beginCreate(e->rootContext()); setQObjectApi(e, o); + if (o) + component.completeCreate(); } v4->popContext(); } @@ -348,6 +353,7 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type) QQmlTypePrivate::~QQmlTypePrivate() { + qDeleteAll(scopedEnums); switch (regType) { case QQmlType::CppType: delete extraData.cd->customParser; @@ -578,14 +584,17 @@ QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const return QQmlMetaType::qmlType(mo); } -int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const +QQmlPropertyCache *QQmlType::compositePropertyCache(QQmlEnginePrivate *engine) const { + // similar logic to resolveCompositeBaseType Q_ASSERT(isComposite()); - if (!d) - return -1; - *ok = false; - QQmlType type = resolveCompositeBaseType(engine); - return type.enumValue(engine, name, ok); + if (!engine) + return 0; + QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt); + if (td.isNull() || !td->isComplete()) + return 0; + QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); + return compilationUnit->rootPropertyCache(); } static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo, @@ -754,7 +763,7 @@ void QQmlTypePrivate::init() const lock.unlock(); } -void QQmlTypePrivate::initEnums() const +void QQmlTypePrivate::initEnums(const QQmlPropertyCache *cache) const { if (isEnumSetup) return; @@ -763,6 +772,8 @@ void QQmlTypePrivate::initEnums() const QMutexLocker lock(metaTypeDataLock()); if (isEnumSetup) return; + if (cache) + insertEnumsFromPropertyCache(cache); if (baseMetaObject) // could be singleton type without metaobject insertEnums(baseMetaObject); @@ -783,11 +794,49 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const // Add any enum values defined by this class, overwriting any inherited values for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) { QMetaEnum e = metaObject->enumerator(ii); - for (int jj = 0; jj < e.keyCount(); ++jj) - enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj)); + const bool isScoped = e.isScoped(); + QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : 0; + + for (int jj = 0; jj < e.keyCount(); ++jj) { + const QString key = QString::fromUtf8(e.key(jj)); + const int value = e.value(jj); + enums.insert(key, value); + if (isScoped) + scoped->insert(key, value); + } + + if (isScoped) { + scopedEnums << scoped; + scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1); + } + } +} + +void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const +{ + const QMetaObject *cppMetaObject = cache->firstCppMetaObject(); + + while (cache && cache->metaObject() != cppMetaObject) { + + int count = cache->qmlEnumCount(); + for (int ii = 0; ii < count; ++ii) { + QStringHash<int> *scoped = new QStringHash<int>(); + QQmlEnumData *enumData = cache->qmlEnum(ii); + + for (int jj = 0; jj < enumData->values.count(); ++jj) { + const QQmlEnumValue &value = enumData->values.at(jj); + enums.insert(value.namedValue, value.value); + scoped->insert(value.namedValue, value.value); + } + scopedEnums << scoped; + scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1); + } + cache = cache->parent(); } + insertEnums(cppMetaObject); } + QQmlPropertyCache *QQmlTypePrivate::propertyCacheForMinorVersion(int minorVersion) const { for (int i = 0; i < propertyCaches.count(); ++i) @@ -1079,11 +1128,11 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, { Q_ASSERT(ok); if (d) { - if (isComposite()) - return resolveCompositeEnumValue(engine, name.toString(), ok); + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; - d->initEnums(); + d->initEnums(cache); int *rv = d->enums.value(name); if (rv) @@ -1098,11 +1147,11 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name { Q_ASSERT(ok); if (d) { - if (isComposite()) - return resolveCompositeEnumValue(engine, name.toUtf16(), ok); + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; - d->initEnums(); + d->initEnums(cache); int *rv = d->enums.value(name); if (rv) @@ -1117,11 +1166,10 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool { Q_ASSERT(ok); if (d) { - if (isComposite()) - return resolveCompositeEnumValue(engine, name->toQString(), ok); + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; *ok = true; - d->initEnums(); + d->initEnums(cache); int *rv = d->enums.value(name); if (rv) @@ -1132,6 +1180,122 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool return -1; } +int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const +{ + Q_ASSERT(ok); + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; + + d->initEnums(cache); + + int *rv = d->scopedEnumIndex.value(name); + if (rv) + return *rv; + } + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const +{ + Q_ASSERT(ok); + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; + + d->initEnums(cache); + + int *rv = d->scopedEnumIndex.value(name); + if (rv) + return *rv; + } + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const +{ + Q_UNUSED(engine) + Q_ASSERT(ok); + *ok = true; + + if (d) { + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + int *rv = d->scopedEnums.at(index)->value(name); + if (rv) + return *rv; + } + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const +{ + Q_UNUSED(engine) + Q_ASSERT(ok); + *ok = true; + + if (d) { + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + int *rv = d->scopedEnums.at(index)->value(name); + if (rv) + return *rv; + } + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const +{ + Q_ASSERT(ok); + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; + + d->initEnums(cache); + + int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length())); + if (rv) { + int index = *rv; + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length())); + if (rv) + return *rv; + } + } + + *ok = false; + return -1; +} + +int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const +{ + Q_ASSERT(ok); + if (d) { + const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0; + *ok = true; + + d->initEnums(cache); + + int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName)); + if (rv) { + int index = *rv; + Q_ASSERT(index > -1 && index < d->scopedEnums.count()); + rv = d->scopedEnums.at(index)->value(QHashedStringRef(name)); + if (rv) + return *rv; + } + } + + *ok = false; + return -1; +} + void QQmlType::refHandle(QQmlTypePrivate *priv) { if (priv) diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index f5b9beb905..f381b4a010 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -149,6 +149,7 @@ public: struct QQmlMetaTypeData; class QHashedCStringRef; +class QQmlPropertyCache; class Q_QML_PRIVATE_EXPORT QQmlType { public: @@ -244,6 +245,13 @@ public: int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const; int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const; + int scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const; + int scopedEnumIndex(QQmlEnginePrivate *engine, const QString &, bool *ok) const; + int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const; + int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const; + int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const; + int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const; + QQmlTypePrivate *priv() const { return d; } static void refHandle(QQmlTypePrivate *priv); static void derefHandle(QQmlTypePrivate *priv); @@ -262,6 +270,7 @@ private: QQmlType superType() const; QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const; int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const; + QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const; friend class QQmlTypePrivate; friend QString registrationTypeString(RegistrationType); diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h index 6e91369793..a99b13f155 100644 --- a/src/qml/qml/qqmlnotifier_p.h +++ b/src/qml/qml/qqmlnotifier_p.h @@ -109,6 +109,9 @@ public: inline int signalIndex() const { return sourceSignal; } + inline QObject *senderAsObject() const; + inline QQmlNotifier *senderAsNotifier() const; + private: friend class QQmlData; friend class QQmlNotifier; @@ -117,8 +120,6 @@ private: // endpoint is connected to. While the endpoint is notifying, the // senderPtr points to another qintptr that contains this value. qintptr senderPtr; - inline QObject *senderAsObject() const; - inline QQmlNotifier *senderAsNotifier() const; Callback callback:4; int needsConnectNotify:1; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 78d732d02c..9114fbb83a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -875,17 +875,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con && !_valueTypeProperty) QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex())); - if (binding->type == QV4::CompiledData::Binding::Type_Script) { - QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions.at(binding->value.compiledScriptIndex); - - QV4::Scope scope(v4); - QV4::Scoped<QV4::QmlContext> qmlContext(scope, currentQmlContext()); - + if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->containsTranslations()) { if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex()); QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine); QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex, - context, _scopeObject, runtimeFunction, qmlContext); + context, _scopeObject, runtimeFunction, currentQmlContext()); bs->takeExpression(expr); } else { @@ -901,7 +897,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con prop = _valueTypeProperty; subprop = property; } - qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, qmlContext); + if (binding->containsTranslations()) { + qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context); + } else { + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; + qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, currentQmlContext()); + } qmlBinding->setTarget(_bindingTarget, *prop, subprop); sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); @@ -1070,7 +1071,7 @@ void QQmlObjectCreator::setupFunctions() QV4::ScopedValue function(scope); QV4::ScopedContext qmlContext(scope, currentQmlContext()); - const QV4::CompiledData::LEUInt32 *functionIdx = _compiledObject->functionOffsetTable(); + const quint32_le *functionIdx = _compiledObject->functionOffsetTable(); for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) { QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx]; const QString name = runtimeFunction->name()->toQString(); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 21ee30acd0..bef58b8c9a 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -123,7 +123,7 @@ private: void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const; - inline QV4::Heap::QmlContext *currentQmlContext(); + inline QV4::QmlContext *currentQmlContext(); Q_NEVER_INLINE void createQmlContext(); enum Phase { @@ -174,12 +174,12 @@ private: QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher; }; -QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() +QV4::QmlContext *QQmlObjectCreator::currentQmlContext() { - if (Q_UNLIKELY(!_qmlContext->isManaged())) - createQmlContext(); // less common slow path + if (!_qmlContext->isManaged()) + _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject)); - return _qmlContext->d(); + return _qmlContext; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp index 0d6ab36066..0acf20bbb4 100644 --- a/src/qml/qml/qqmlplatform.cpp +++ b/src/qml/qml/qqmlplatform.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qqmlplatform_p.h" +#include "qqmlglobal_p.h" QT_BEGIN_NAMESPACE @@ -80,6 +81,11 @@ QString QQmlPlatform::os() #endif } +QString QQmlPlatform::pluginName() const +{ + return QQml_guiProvider()->pluginName(); +} + QT_END_NAMESPACE #include "moc_qqmlplatform_p.cpp" diff --git a/src/qml/qml/qqmlplatform_p.h b/src/qml/qml/qqmlplatform_p.h index 6887720adb..6246ca7105 100644 --- a/src/qml/qml/qqmlplatform_p.h +++ b/src/qml/qml/qqmlplatform_p.h @@ -61,12 +61,14 @@ class Q_QML_PRIVATE_EXPORT QQmlPlatform : public QObject { Q_OBJECT Q_PROPERTY(QString os READ os CONSTANT) + Q_PROPERTY(QString pluginName READ pluginName CONSTANT) public: explicit QQmlPlatform(QObject *parent = 0); virtual ~QQmlPlatform(); static QString os(); + QString pluginName() const; private: Q_DISABLE_COPY(QQmlPlatform) diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 019fa654d1..7178dffa8b 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -303,12 +303,13 @@ QQmlPropertyCache *QQmlPropertyCache::copy() } QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int methodCount, - int signalCount) + int signalCount, int enumCount) { QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount); rv->propertyIndexCache.reserve(propertyCount); rv->methodIndexCache.reserve(methodCount); rv->signalHandlerIndexCache.reserve(signalCount); + rv->enumCache.reserve(enumCount); rv->_metaObject = 0; return rv; @@ -403,6 +404,14 @@ void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flag setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); } +void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumValue> &values) +{ + QQmlEnumData data; + data.name = name; + data.values = values; + enumCache.append(data); +} + // Returns this property cache's metaObject, creating it if necessary. const QMetaObject *QQmlPropertyCache::createMetaObject() { @@ -1231,6 +1240,16 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) method.setReturnType(returnType); } + for (int ii = 0; ii < enumCache.count(); ++ii) { + const QQmlEnumData &enumData = enumCache.at(ii); + QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8()); + enumeration.setIsScoped(true); + for (int jj = 0; jj < enumData.values.count(); ++jj) { + const QQmlEnumValue &value = enumData.values.at(jj); + enumeration.addKey(value.namedValue.toUtf8(), value.value); + } + } + if (!_defaultPropertyName.isEmpty()) { QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0); if (dp && dp->coreIndex() >= propertyIndexCacheStart) { diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index a841570f1d..6cdb82bd46 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -349,6 +349,20 @@ private: bool notFullyResolved() const { return _flags.notFullyResolved; } }; +struct QQmlEnumValue +{ + QQmlEnumValue() : value(-1) {} + QQmlEnumValue(const QString &n, int v) : namedValue(n), value(v) {} + QString namedValue; + int value; +}; + +struct QQmlEnumData +{ + QString name; + QVector<QQmlEnumValue> values; +}; + class QQmlPropertyCacheMethodArguments; class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount { @@ -374,13 +388,14 @@ public: QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); QQmlPropertyCache *copyAndReserve(int propertyCount, - int methodCount, int signalCount); + int methodCount, int signalCount, int enumCount); void appendProperty(const QString &, QQmlPropertyRawData::Flags flags, int coreIndex, int propType, int notifyIndex); void appendSignal(const QString &, QQmlPropertyRawData::Flags, int coreIndex, const int *types = 0, const QList<QByteArray> &names = QList<QByteArray>()); void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, const QList<QByteArray> &names = QList<QByteArray>()); + void appendEnum(const QString &, const QVector<QQmlEnumValue> &); const QMetaObject *metaObject() const; const QMetaObject *createMetaObject(); @@ -395,6 +410,7 @@ public: QQmlPropertyData *property(int) const; QQmlPropertyData *method(int) const; QQmlPropertyData *signal(int index) const; + QQmlEnumData *qmlEnum(int) const; int methodIndexToSignalIndex(int) const; QString defaultPropertyName() const; @@ -434,6 +450,7 @@ public: inline int methodOffset() const; inline int signalCount() const; inline int signalOffset() const; + inline int qmlEnumCount() const; static bool isDynamicMetaObject(const QMetaObject *); @@ -500,6 +517,7 @@ private: IndexCache signalHandlerIndexCache; StringCache stringCache; AllowedRevisionCache allowedRevisionCache; + QVector<QQmlEnumData> enumCache; bool _hasPropertyOverrides : 1; bool _ownMetaObject : 1; @@ -742,6 +760,14 @@ inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const return ensureResolved(rv); } +inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const +{ + if (index < 0 || index >= enumCache.count()) + return 0; + + return const_cast<QQmlEnumData *>(&enumCache.at(index)); +} + inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const { if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) @@ -812,6 +838,11 @@ int QQmlPropertyCache::signalOffset() const return signalHandlerIndexCacheStart; } +int QQmlPropertyCache::qmlEnumCount() const +{ + return enumCache.count(); +} + bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const { if (_jsFactoryMethodIndex != -1) { diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 19e57fbdba..4b6e69e617 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2706,6 +2706,10 @@ void QQmlTypeData::resolveTypes() m_resolvedTypes.insert(unresolvedRef.key(), ref); } + + // ### this allows enums to work without explicit import or instantiation of the type + if (!m_implicitImportLoaded) + loadImplicitImport(); } QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp index 72307c2800..32b0fa16c4 100644 --- a/src/qml/qml/qqmltypenamecache.cpp +++ b/src/qml/qml/qqmltypenamecache.cpp @@ -138,7 +138,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name, return result; } -QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) const +QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQmlImport::RecursionRestriction recursionRestriction) const { Result result = query(m_namedImports, name); @@ -154,7 +154,8 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons QQmlImportNamespace *typeNamespace = 0; QList<QQmlError> errors; QQmlType t; - bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors); + bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors, + QQmlType::AnyRegistrationType, recursionRestriction); if (typeFound) { return Result(t); } diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h index 7e2cbec4b5..8ac25c4fbe 100644 --- a/src/qml/qml/qqmltypenamecache_p.h +++ b/src/qml/qml/qqmltypenamecache_p.h @@ -81,7 +81,7 @@ struct QQmlImportRef { class QQmlType; class QQmlEngine; -class QQmlTypeNameCache : public QQmlRefCount +class Q_QML_PRIVATE_EXPORT QQmlTypeNameCache : public QQmlRefCount { public: QQmlTypeNameCache(const QQmlImports &imports); @@ -107,7 +107,7 @@ public: }; Result query(const QHashedStringRef &) const; Result query(const QHashedStringRef &, const QQmlImportRef *importNamespace) const; - Result query(const QV4::String *) const; + Result query(const QV4::String *, QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const; Result query(const QV4::String *, const QQmlImportRef *importNamespace) const; private: diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 0fae76066d..8e067932bb 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -52,16 +52,17 @@ QT_BEGIN_NAMESPACE using namespace QV4; -DEFINE_OBJECT_VTABLE(QmlTypeWrapper); +DEFINE_OBJECT_VTABLE(QQmlTypeWrapper); +DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper); -void Heap::QmlTypeWrapper::init() +void Heap::QQmlTypeWrapper::init() { Object::init(); mode = IncludeEnums; object.init(); } -void Heap::QmlTypeWrapper::destroy() +void Heap::QQmlTypeWrapper::destroy() { QQmlType::derefHandle(typePrivate); typePrivate = nullptr; @@ -71,17 +72,17 @@ void Heap::QmlTypeWrapper::destroy() Object::destroy(); } -QQmlType Heap::QmlTypeWrapper::type() const +QQmlType Heap::QQmlTypeWrapper::type() const { return QQmlType(typePrivate); } -bool QmlTypeWrapper::isSingleton() const +bool QQmlTypeWrapper::isSingleton() const { return d()->type().isSingleton(); } -QObject* QmlTypeWrapper::singletonObject() const +QObject* QQmlTypeWrapper::singletonObject() const { if (!isSingleton()) return 0; @@ -92,7 +93,7 @@ QObject* QmlTypeWrapper::singletonObject() const return siinfo->qobjectApi(e); } -QVariant QmlTypeWrapper::toVariant() const +QVariant QQmlTypeWrapper::toVariant() const { QObject *qobjectSingleton = singletonObject(); if (qobjectSingleton) @@ -104,13 +105,13 @@ QVariant QmlTypeWrapper::toVariant() const // Returns a type wrapper for type t on o. This allows access of enums, and attached properties. -ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t, - Heap::QmlTypeWrapper::TypeNameMode mode) +ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t, + Heap::QQmlTypeWrapper::TypeNameMode mode) { Q_ASSERT(t.isValid()); Scope scope(engine); - Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QmlTypeWrapper>()); + Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>()); w->d()->mode = mode; w->d()->object = o; w->d()->typePrivate = t.priv(); QQmlType::refHandle(w->d()->typePrivate); @@ -119,14 +120,14 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, c // Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a // namespace. -ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const QQmlImportRef *importNamespace, - Heap::QmlTypeWrapper::TypeNameMode mode) +ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const QQmlImportRef *importNamespace, + Heap::QQmlTypeWrapper::TypeNameMode mode) { Q_ASSERT(t); Q_ASSERT(importNamespace); Scope scope(engine); - Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QmlTypeWrapper>()); + Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>()); w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t; w->d()->importNamespace = importNamespace; t->addref(); return w.asReturnedValue(); @@ -161,14 +162,14 @@ static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *n return v4->throwTypeError(message); } -ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) +ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { - Q_ASSERT(m->as<QmlTypeWrapper>()); + Q_ASSERT(m->as<QQmlTypeWrapper>()); - QV4::ExecutionEngine *v4 = static_cast<const QmlTypeWrapper *>(m)->engine(); + QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine(); QV4::Scope scope(v4); - Scoped<QmlTypeWrapper> w(scope, static_cast<const QmlTypeWrapper *>(m)); + Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(m)); if (hasProperty) *hasProperty = true; @@ -190,7 +191,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope if (qobjectSingleton) { // check for enum value - const bool includeEnums = w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums; + const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; if (includeEnums && name->startsWithUpper()) { bool ok = false; const int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok); @@ -229,6 +230,15 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope if (ok) return QV4::Primitive::fromInt32(value).asReturnedValue(); + value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + if (ok) { + Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocObject<QQmlScopedEnumWrapper>()); + enumWrapper->d()->typePrivate = type.priv(); + QQmlType::refHandle(enumWrapper->d()->typePrivate); + enumWrapper->d()->scopeEnumIndex = value; + return enumWrapper.asReturnedValue(); + } + // Fall through to base implementation } else if (w->d()->object) { @@ -285,13 +295,13 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope } -void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) +bool QQmlTypeWrapper::put(Managed *m, String *name, const Value &value) { - Q_ASSERT(m->as<QmlTypeWrapper>()); - QmlTypeWrapper *w = static_cast<QmlTypeWrapper *>(m); + Q_ASSERT(m->as<QQmlTypeWrapper>()); + QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); if (v4->hasException) - return; + return false; QV4::Scope scope(v4); QQmlContextData *context = v4->callingQmlContext(); @@ -302,7 +312,8 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) QQmlEngine *e = scope.engine->qmlEngine(); QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(e)), object); if (ao) - QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); + return QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); + return false; } else if (type.isSingleton()) { QQmlEngine *e = scope.engine->qmlEngine(); QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); @@ -310,21 +321,23 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) QObject *qobjectSingleton = siinfo->qobjectApi(e); if (qobjectSingleton) { - QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); + return QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); } else if (!siinfo->scriptApi(e).isUndefined()) { QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); if (!apiprivate) { QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); v4->throwError(error); - return; + return false; } else { - apiprivate->put(name, value); + return apiprivate->put(name, value); } } } + + return false; } -PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name) +PropertyAttributes QQmlTypeWrapper::query(const Managed *m, String *name) { // ### Implement more efficiently. bool hasProperty = false; @@ -332,11 +345,11 @@ PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name) return hasProperty ? Attr_Data : Attr_Invalid; } -bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b) +bool QQmlTypeWrapper::isEqualTo(Managed *a, Managed *b) { - Q_ASSERT(a->as<QV4::QmlTypeWrapper>()); - QV4::QmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QmlTypeWrapper *>(a); - if (QV4::QmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QmlTypeWrapper>()) + Q_ASSERT(a->as<QV4::QQmlTypeWrapper>()); + QV4::QQmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QQmlTypeWrapper *>(a); + if (QV4::QQmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QQmlTypeWrapper>()) return qmlTypeWrapperA->toVariant() == qmlTypeWrapperB->toVariant(); else if (QV4::QObjectWrapper *qobjectWrapper = b->as<QV4::QObjectWrapper>()) return qmlTypeWrapperA->toVariant().value<QObject*>() == qobjectWrapper->object(); @@ -344,4 +357,76 @@ bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b) return false; } +ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value &var) +{ + Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>()); + const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject); + QV4::ExecutionEngine *engine = typeObject->internalClass()->engine; + QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine()); + + // can only compare a QObject* against a QML type + const QObjectWrapper *wrapper = var.as<QObjectWrapper>(); + if (!wrapper) + return engine->throwTypeError(); + + // in case the wrapper outlived the QObject* + const QObject *wrapperObject = wrapper->object(); + if (!wrapperObject) + return engine->throwTypeError(); + + const int myTypeId = typeWrapper->d()->type().typeId(); + QQmlMetaObject myQmlType; + if (myTypeId == 0) { + // we're a composite type; a composite type cannot be equal to a + // non-composite object instance (Rectangle{} is never an instance of + // CustomRectangle) + QQmlData *theirDData = QQmlData::get(wrapperObject, /*create=*/false); + Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?! + if (!theirDData->compilationUnit) + return Encode(false); + + QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl()); + CompiledData::CompilationUnit *cu = td->compilationUnit(); + myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId); + } else { + myQmlType = qenginepriv->metaObjectForType(myTypeId); + } + + const QMetaObject *theirType = wrapperObject->metaObject(); + + return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType)); +} + +void Heap::QQmlScopedEnumWrapper::destroy() +{ + QQmlType::derefHandle(typePrivate); + typePrivate = nullptr; + Object::destroy(); +} + +QQmlType Heap::QQmlScopedEnumWrapper::type() const +{ + return QQmlType(typePrivate); +} + +ReturnedValue QQmlScopedEnumWrapper::get(const Managed *m, String *name, bool *hasProperty) +{ + Q_ASSERT(m->as<QQmlScopedEnumWrapper>()); + const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m); + QV4::ExecutionEngine *v4 = resource->engine(); + QV4::Scope scope(v4); + + QQmlType type = resource->d()->type(); + int index = resource->d()->scopeEnumIndex; + + bool ok = false; + int value = type.scopedEnumValue(QQmlEnginePrivate::get(v4->qmlEngine()), index, name, &ok); + if (hasProperty) + *hasProperty = ok; + if (ok) + return QV4::Primitive::fromInt32(value).asReturnedValue(); + + return Encode::undefined(); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index c06c485fb8..bb65093163 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -65,7 +65,7 @@ namespace QV4 { namespace Heap { -struct QmlTypeWrapper : Object { +struct QQmlTypeWrapper : Object { enum TypeNameMode { IncludeEnums, ExcludeEnums @@ -83,11 +83,19 @@ struct QmlTypeWrapper : Object { const QQmlImportRef *importNamespace; }; +struct QQmlScopedEnumWrapper : Object { + void init() { Object::init(); } + void destroy(); + int scopeEnumIndex; + QQmlTypePrivate *typePrivate; + QQmlType type() const; +}; + } -struct Q_QML_EXPORT QmlTypeWrapper : Object +struct Q_QML_EXPORT QQmlTypeWrapper : Object { - V4_OBJECT2(QmlTypeWrapper, Object) + V4_OBJECT2(QQmlTypeWrapper, Object) V4_NEEDS_DESTROY bool isSingleton() const; @@ -96,16 +104,24 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object QVariant toVariant() const; static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &, - Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); + Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums); static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const QQmlImportRef *, - Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums); + Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums); static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static bool isEqualTo(Managed *that, Managed *o); + static ReturnedValue instanceOf(const Object *typeObject, const Value &var); +}; +struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object +{ + V4_OBJECT2(QQmlScopedEnumWrapper, Object) + V4_NEEDS_DESTROY + + static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); }; } diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp index 4e2e7b06c7..7a3e4b2df4 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp +++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp @@ -72,6 +72,11 @@ bool QQmlValueTypeProxyBinding::isValueTypeProxy() const return true; } +QQmlAbstractBinding *QQmlValueTypeProxyBinding::subBindings() const +{ + return m_bindings.data(); +} + QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(QQmlPropertyIndex propertyIndex) const { QQmlAbstractBinding *binding = m_bindings.data(); diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h index 92b5470f39..ba0d305bd9 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h +++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h @@ -60,6 +60,7 @@ class QQmlValueTypeProxyBinding : public QQmlAbstractBinding public: QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex coreIndex); + QQmlAbstractBinding *subBindings() const; QQmlAbstractBinding *binding(QQmlPropertyIndex targetPropertyIndex) const; void removeBindings(quint32 mask); diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index b2b49f7909..18c0cb8b91 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -51,9 +51,11 @@ #include <private/qv4alloca_p.h> #include <private/qv4objectiterator_p.h> #include <private/qv4qobjectwrapper_p.h> +#include <QtCore/qloggingcategory.h> QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval) DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper); @@ -411,13 +413,13 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha #undef VALUE_TYPE_ACCESSOR } -void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) +bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) { Q_ASSERT(m->as<QQmlValueTypeWrapper>()); ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine(); Scope scope(v4); if (scope.hasException()) - return; + return false; Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m)); Scoped<QQmlValueTypeReference> reference(scope, m->d()); @@ -428,7 +430,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property); if (!writebackProperty.isWritable() || !reference->readReferenceValue()) - return; + return false; writeBackPropertyType = writebackProperty.userType(); } @@ -436,17 +438,20 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) const QMetaObject *metaObject = r->d()->propertyCache()->metaObject(); const QQmlPropertyData *pd = r->d()->propertyCache()->property(name, 0, 0); if (!pd) - return; + return false; if (reference) { QV4::ScopedFunctionObject f(scope, value); + const QQmlQPointer<QObject> &referenceObject = reference->d()->object; + const int referencePropertyIndex = reference->d()->property; + if (f) { if (!f->isBinding()) { // assigning a JS function to a non-var-property is not allowed. QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); ScopedString e(scope, v4->newString(error)); v4->throwError(e); - return; + return false; } QQmlContextData *context = v4->callingQmlContext(); @@ -454,18 +459,31 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QQmlPropertyData cacheData; cacheData.setWritable(true); cacheData.setPropType(writeBackPropertyType); - cacheData.setCoreIndex(reference->d()->property); + cacheData.setCoreIndex(referencePropertyIndex); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); QV4::ScopedContext ctx(scope, bindingFunction->scope()); - QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), reference->d()->object, context, ctx); + QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), referenceObject, context, ctx); newBinding->setSourceLocation(bindingFunction->currentLocation()); - newBinding->setTarget(reference->d()->object, cacheData, pd); + newBinding->setTarget(referenceObject, cacheData, pd); QQmlPropertyPrivate::setBinding(newBinding); - return; + return true; } else { - QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyIndex(reference->d()->property, pd->coreIndex())); + if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) { + if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()))) { + Q_ASSERT(!binding->isValueTypeProxy()); + const auto qmlBinding = static_cast<const QQmlBinding*>(binding); + const auto stackFrame = v4->currentStackFrame(); + qCInfo(lcBindingRemoval, + "Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d", + referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(), + qPrintable(qmlBinding->expressionIdentifier()), + metaObject->property(pd->coreIndex()).name(), + qPrintable(stackFrame.source), stackFrame.line); + } + } + QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex())); } } @@ -497,6 +515,8 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a); } } + + return true; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index 87f9116056..c8aac719ab 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -106,7 +106,7 @@ public: bool write(QObject *target, int propertyIndex) const; static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); static bool isEqualTo(Managed *m, Managed *other); static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 965b1fd3f2..dde8784eb1 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -104,8 +104,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *) if (v4) { QV4::Scope scope(v4); QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value()); - if (sp) - *(sp->data() + m_index) = QV4::Primitive::nullValue(); + if (sp) { + QV4::MemberData::Index index{ sp->d(), sp->d()->values.values + m_index }; + index.set(v4, QV4::Primitive::nullValue()); + } } m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0); @@ -330,7 +332,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine, if (size) { QV4::Heap::MemberData *data = QV4::MemberData::allocate(engine, size); propertyAndMethodStorage.set(engine, data); - std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); + std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined()); } // Need JS wrapper to ensure properties/methods are marked. @@ -365,77 +367,77 @@ void QQmlVMEMetaObject::writeProperty(int id, int v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromInt32(v); + md->set(engine, id, QV4::Primitive::fromInt32(v)); } void QQmlVMEMetaObject::writeProperty(int id, bool v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromBoolean(v); + md->set(engine, id, QV4::Primitive::fromBoolean(v)); } void QQmlVMEMetaObject::writeProperty(int id, double v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromDouble(v); + md->set(engine, id, QV4::Primitive::fromDouble(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QString& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = engine->newString(v); + md->set(engine, id, engine->newString(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QDate& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v)); + md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, QObject* v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::QObjectWrapper::wrap(engine, v); + md->set(engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, v))); QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id); if (v && !guard) { @@ -593,7 +595,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) { QVariant variant(qVariantFromValue(QList<QObject*>())); v = engine->newVariantObject(variant); - *(md->data() + id) = v; + md->set(engine, id, v); } return static_cast<QList<QObject *> *>(v->d()->data().data()); } @@ -742,7 +744,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { QVariant propertyAsVariant; - if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) + if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) propertyAsVariant = v->d()->data(); QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); } @@ -815,9 +817,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * case QV4::CompiledData::Property::Quaternion: Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { - QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); if (!v) { - *(md->data() + id) = engine->newVariantObject(QVariant()); + md->set(engine, id, engine->newVariantObject(QVariant())); v = (md->data() + id)->as<QV4::VariantObject>(); QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } @@ -1028,7 +1030,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) // 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::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>(); + const QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>(); if (oldVariant) oldVariant->removeVmePropertyReference(); @@ -1054,7 +1056,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) guard->setGuardedValue(valueObject, this, id); // Write the value and emit change signal as appropriate. - *(md->data() + id) = value; + md->set(engine, id, value); activate(object, methodOffset() + id, 0); } @@ -1067,7 +1069,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // 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::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>(); + const QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>(); if (oldv) oldv->removeVmePropertyReference(); @@ -1081,7 +1083,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // Write the value and emit change signal as appropriate. QVariant currentValue = readPropertyAsVariant(id); - *(md->data() + id) = newv; + md->set(engine, id, newv); if ((currentValue.userType() != value.userType() || currentValue != value)) activate(object, methodOffset() + id, 0); } else { @@ -1093,14 +1095,14 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) } else { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) { - QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + const 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) = engine->newVariantObject(value); - v = static_cast<QV4::VariantObject *>(md->data() + id); + md->set(engine, id, engine->newVariantObject(value)); + v = static_cast<const QV4::VariantObject *>(md->data() + id); v->addVmePropertyReference(); } } @@ -1139,7 +1141,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; - *(md->data() + methodIndex + compiledObject->nProperties) = function; + md->set(engine, methodIndex + compiledObject->nProperties, function); } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) const @@ -1167,15 +1169,15 @@ void QQmlVMEMetaObject::ensureQObjectWrapper() QV4::QObjectWrapper::wrap(engine, object); } -void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) +void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack) { - if (engine != e) + if (engine != markStack->engine) return; - propertyAndMethodStorage.markOnce(e); + propertyAndMethodStorage.markOnce(markStack); if (QQmlVMEMetaObject *parent = parentVMEMetaObject()) - parent->mark(e); + parent->mark(markStack); } 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 2dff2b7a01..891db5eb3f 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -206,7 +206,7 @@ public: void ensureQObjectWrapper(); - void mark(QV4::ExecutionEngine *e); + void mark(QV4::MarkStack *markStack); void connectAlias(int aliasId); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 58d8322675..08f3d35e46 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1597,10 +1597,12 @@ struct QQmlXMLHttpRequestWrapper : Object { QQmlXMLHttpRequest *request; }; -struct QQmlXMLHttpRequestCtor : FunctionObject { - void init(ExecutionEngine *engine); +#define QQmlXMLHttpRequestCtorMembers(class, Member) \ + Member(class, Pointer, Object *, proto) - Pointer<Object> proto; +DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) { + DECLARE_MARK_TABLE(QQmlXMLHttpRequestCtor); + void init(ExecutionEngine *engine); }; } @@ -1614,12 +1616,7 @@ struct QQmlXMLHttpRequestWrapper : public Object struct QQmlXMLHttpRequestCtor : public FunctionObject { V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject) - static void markObjects(Heap::Base *that, ExecutionEngine *e) { - QQmlXMLHttpRequestCtor::Data *c = static_cast<QQmlXMLHttpRequestCtor::Data *>(that); - if (c->proto) - c->proto->mark(e); - FunctionObject::markObjects(that, e); - } + static void construct(const Managed *that, Scope &scope, QV4::CallData *) { Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); @@ -1686,7 +1683,7 @@ void QQmlXMLHttpRequestCtor::setupProto() ExecutionEngine *v4 = engine(); Scope scope(v4); ScopedObject p(scope, v4->newObject()); - d()->proto = p->d(); + d()->proto.set(scope.engine, p->d()); // Methods p->defineDefaultProperty(QStringLiteral("open"), method_open); @@ -1826,8 +1823,13 @@ void QQmlXMLHttpRequestCtor::method_send(const QV4::BuiltinFunction *, QV4::Scop THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); QByteArray data; - if (callData->argc > 0) - data = callData->args[0].toQStringNoThrow().toUtf8(); + if (callData->argc > 0) { + if (const ArrayBuffer *buffer = callData->args[0].as<ArrayBuffer>()) { + data = buffer->asByteArray(); + } else { + data = callData->args[0].toQStringNoThrow().toUtf8(); + } + } scope.result = r->send(w, scope.engine->callingQmlContext(), data); } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 96d83b9870..1630efe081 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -851,6 +851,8 @@ In addition the following expressions can be used to specify the time: \li use AM/PM display. \e AP will be replaced by either "AM" or "PM". \row \li ap \li use am/pm display. \e ap will be replaced by either "am" or "pm". + \row \li t + \li include a time-zone indicator. \endtable All other input characters will be ignored. Any sequence of characters that |