aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qv4codegen.cpp5
-rw-r--r--src/qml/compiler/qv4codegen_p.h19
-rw-r--r--src/qml/doc/snippets/qml/componentCreation.js4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp9
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp1
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h3
-rw-r--r--src/qml/jsruntime/qv4value_p.h17
-rw-r--r--src/qml/parser/qqmljs.g49
-rw-r--r--src/qml/qml/qqml.h9
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp9
-rw-r--r--src/qml/qml/qqmlcomponent.cpp2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp4
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp43
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h2
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h24
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc588
-rw-r--r--src/quick/items/qquickgridview.cpp9
-rw-r--r--src/quick/items/qquickitemview.cpp15
-rw-r--r--src/quick/items/qquickitemview_p_p.h4
-rw-r--r--src/quick/items/qquicklistview.cpp17
-rw-r--r--src/quick/items/qquickopenglshadereffect.cpp7
-rw-r--r--src/quick/items/qquickopenglshadereffect_p.h2
-rw-r--r--src/quick/items/qquickopenglshadereffectnode.cpp2
-rw-r--r--src/quick/items/qquickopenglshadereffectnode_p.h2
-rw-r--r--src/quick/items/qquickrepeater.cpp9
-rw-r--r--src/quick/items/qquickshadereffect.cpp14
-rw-r--r--src/quick/items/qquickshadereffect_p.h1
-rw-r--r--src/quick/items/qquicktableview.cpp3
-rw-r--r--src/quick/items/qquicktextcontrol.cpp2
-rw-r--r--src/quick/scenegraph/qsgbasicinternalimagenode.cpp4
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp10
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h3
-rw-r--r--src/quickwidgets/qquickwidget.cpp9
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp2
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations2
-rw-r--r--tests/auto/qml/qqmlapplicationengine/data/i18n/qml.qmbin0 -> 102 bytes
-rw-r--r--tests/auto/qml/qqmlapplicationengine/data/i18n/qml.ts11
-rw-r--r--tests/auto/qml/qqmlapplicationengine/data/loadTranslation.qml5
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp27
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.pro3
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.qrc6
-rw-r--r--tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp50
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp10
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp8
-rw-r--r--tests/auto/quick/scenegraph/tst_scenegraph.cpp5
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp3
49 files changed, 661 insertions, 390 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index b7e3e20fd0..04e6efb1e9 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1073,6 +1073,7 @@ bool Codegen::visit(Expression *ast)
TailCallBlocker blockTailCalls(this);
statement(ast->left);
blockTailCalls.unblock();
+ clearExprResultName(); // The name only holds for the left part
accept(ast->right);
return false;
}
@@ -2537,7 +2538,7 @@ bool Codegen::visit(ObjectPattern *ast)
{
RegisterScope innerScope(this);
- Reference value = expression(p->initializer);
+ Reference value = expression(p->initializer, name);
if (hasError)
return false;
value.loadInAccumulator();
@@ -2979,7 +2980,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
// already defined
return leaveContext();
- _context->name = name;
+ _context->name = name.isEmpty() ? currentExpr().result().name : name;
_module->functions.append(_context);
_context->functionIndex = _module->functions.count() - 1;
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 6d5f8c0951..65dc4b97b5 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -199,8 +199,9 @@ public:
codegen = cg;
}
- Reference() :
+ Reference(const QString &name = QString()) :
constant(0),
+ name(name),
isArgOrEval(false),
isReadonly(false),
isReferenceToConst(false),
@@ -418,6 +419,11 @@ protected:
bool _trueBlockFollowsCondition = false;
public:
+ explicit Result(const QString &name)
+ : _result(name)
+ , _requested(ex)
+ {}
+
explicit Result(const Reference &lrvalue)
: _result(lrvalue)
, _requested(ex)
@@ -476,6 +482,10 @@ protected:
void setResult(Reference &&result) {
_result = std::move(result);
}
+
+ void clearResultName() {
+ _result.name.clear();
+ }
};
void enterContext(AST::Node *node);
@@ -523,12 +533,12 @@ protected:
const BytecodeGenerator::Label *iffalse,
bool trueBlockFollowsCondition);
- inline Reference expression(AST::ExpressionNode *ast)
+ inline Reference expression(AST::ExpressionNode *ast, const QString &name = QString())
{
if (!ast || hasError)
return Reference();
- pushExpr();
+ pushExpr(name);
ast->accept(this);
return popResult();
}
@@ -716,6 +726,7 @@ protected:
inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); }
inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); }
inline Reference exprResult() const { return m_expressions.back().result(); }
+ inline void clearExprResultName() { m_expressions.back().clearResultName(); }
inline bool exprAccept(Format f) { return m_expressions.back().accept(f); }
@@ -723,7 +734,7 @@ protected:
inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(expr)); }
inline void pushExpr(const Result &expr) { m_expressions.push_back(expr); }
- inline void pushExpr() { m_expressions.emplace_back(); }
+ inline void pushExpr(const QString &name = QString()) { m_expressions.emplace_back(name); }
inline Result popExpr()
{
diff --git a/src/qml/doc/snippets/qml/componentCreation.js b/src/qml/doc/snippets/qml/componentCreation.js
index 7364139d3d..ea45f18c37 100644
--- a/src/qml/doc/snippets/qml/componentCreation.js
+++ b/src/qml/doc/snippets/qml/componentCreation.js
@@ -17,7 +17,7 @@ function createSpriteObjects() {
//![local]
component = Qt.createComponent("Sprite.qml");
- sprite = component.createObject(appWindow, {"x": 100, "y": 100});
+ sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
@@ -32,7 +32,7 @@ function createSpriteObjects() {
//![finishCreation]
function finishCreation() {
if (component.status == Component.Ready) {
- sprite = component.createObject(appWindow, {"x": 100, "y": 100});
+ sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 99f425293e..0cda6b864a 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -77,8 +77,13 @@ ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Valu
primitiveLookup.type = object.type();
switch (primitiveLookup.type) {
case Value::Undefined_Type:
- case Value::Null_Type:
- return engine->throwTypeError();
+ case Value::Null_Type: {
+ Scope scope(engine);
+ ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
+ const QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString())
+ .arg(QLatin1String(primitiveLookup.type == Value::Undefined_Type ? "undefined" : "null"));
+ return engine->throwTypeError(message);
+ }
case Value::Boolean_Type:
primitiveLookup.proto = engine->booleanPrototype()->d();
break;
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 94bf1a98ae..7578de4d14 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -120,7 +120,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
} indexedLookup;
struct {
Heap::InternalClass *ic;
- Heap::QObjectWrapper *staticQObject;
+ Heap::InternalClass *qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper
QQmlPropertyCache *propertyCache;
QQmlPropertyData *propertyData;
} qobjectLookup;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index f3351f6da0..7b885a9e9e 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -292,7 +292,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject)));
const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
lookup->qobjectLookup.ic = That->internalClass();
- lookup->qobjectLookup.staticQObject = nullptr;
lookup->qobjectLookup.propertyCache = ddata->propertyCache;
lookup->qobjectLookup.propertyCache->addref();
lookup->qobjectLookup.propertyData = propertyData;
@@ -325,7 +324,6 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject)));
const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
lookup->qobjectLookup.ic = That->internalClass();
- lookup->qobjectLookup.staticQObject = nullptr;
lookup->qobjectLookup.propertyCache = ddata->propertyCache;
lookup->qobjectLookup.propertyCache->addref();
lookup->qobjectLookup.propertyData = propertyData;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 8b7de89d5b..8a4adfe69a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -872,7 +872,6 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
}
lookup->qobjectLookup.ic = This->internalClass();
- lookup->qobjectLookup.staticQObject = nullptr;
lookup->qobjectLookup.propertyCache = ddata->propertyCache;
lookup->qobjectLookup.propertyCache->addref();
lookup->qobjectLookup.propertyData = property;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 795bf241f2..ac9cad2bdb 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -231,8 +231,7 @@ inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionE
if (!o || o->internalClass != lookup->qobjectLookup.ic)
return revertLookup();
- const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject :
- static_cast<const Heap::QObjectWrapper *>(o);
+ const Heap::QObjectWrapper *This = static_cast<const Heap::QObjectWrapper *>(o);
QObject *qobj = This->object();
if (QQmlData::wasDeleted(qobj))
return QV4::Encode::undefined();
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index a9c8ac66bd..4e901721cb 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -87,12 +87,29 @@ struct Q_QML_PRIVATE_EXPORT Value : public StaticValue
QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
{
HeapBasePtr b;
+#ifdef __ia64
+// Restore bits 49-47 to bits 63-61, undoing the workaround explained in
+// setM below.
+ quint64 _tmp;
+
+ _tmp = _val & (7L << 47); // 0x3800000000000
+ _tmp = (_tmp << 14) | (_val ^ _tmp);
+ memcpy(&b, &_tmp, 8);
+#else
memcpy(&b, &_val, 8);
+#endif
return b;
}
QML_NEARLY_ALWAYS_INLINE void setM(HeapBasePtr b)
{
memcpy(&_val, &b, 8);
+#ifdef __ia64
+// On ia64, bits 63-61 in a 64-bit pointer are used to store the virtual region
+// number. Since this implementation is not 64-bit clean, we move bits 63-61
+// to bits 49-47 and hope for the best. This is undone in *m(), above.
+ _val |= ((_val & (7L << 61)) >> 14);
+ _val &= ((1L << 50)-1);
+#endif
}
#elif QT_POINTER_SIZE == 4
QML_NEARLY_ALWAYS_INLINE HeapBasePtr m() const
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 0c947b541b..4ad9057ced 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -1110,6 +1110,23 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_AUTOMATIC_SEMICOLON;
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_SEMICOLON;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->typeModifier = stringRef(3);
+ node->propertyToken = loc(2);
+ node->typeModifierToken = loc(3);
+ node->typeToken = loc(5);
+ node->identifierToken = loc(7);
+ node->semicolonToken = loc(8);
+ sym(1).Node = node;
+ } break;
+./
+
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_AUTOMATIC_SEMICOLON;
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_SEMICOLON;
/.
@@ -1221,6 +1238,34 @@ UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T
} break;
./
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
+/.
+ case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->typeModifier = stringRef(3);
+ node->propertyToken = loc(2);
+ node->typeModifierToken = loc(3);
+ node->typeToken = loc(5);
+ node->identifierToken = loc(7);
+ node->semicolonToken = loc(8); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(7));
+ propertyName->identifierToken = loc(7);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(propertyName, sym(10).UiArrayMemberList->finish());
+ binding->colonToken = loc(8);
+ binding->lbracketToken = loc(9);
+ binding->rbracketToken = loc(11);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+ } break;
+./
+
UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
/.
case $rule_number: {
@@ -1773,10 +1818,6 @@ PropertyDefinition: PropertyName T_COLON AssignmentExpression_In;
/.
case $rule_number: {
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, sym(3).Expression);
- if (auto *f = asAnonymousFunctionDefinition(sym(3).Expression)) {
- if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName))
- f->name = driver->newStringRef(sym(1).PropertyName->asString());
- }
if (auto *c = asAnonymousClassDefinition(sym(3).Expression)) {
if (!AST::cast<AST::ComputedPropertyName *>(sym(1).PropertyName))
c->name = driver->newStringRef(sym(1).PropertyName->asString());
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index 7b3f89e943..f84a1b2109 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -608,9 +608,12 @@ Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versi
template<typename T>
QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
{
- QObject *mutableObj = const_cast<QObject *>(obj);
- return qmlAttachedPropertiesObject(
- mutableObj, qmlAttachedPropertiesFunction(mutableObj, &T::staticMetaObject), create);
+ // We don't need a concrete object to resolve the function. As T is a C++ type, it and all its
+ // super types should be registered as CppType (or not at all). We only need the object and its
+ // QML engine to resolve composite types. Therefore, the function is actually a static property
+ // of the C++ type system and we can cache it here for improved performance on further lookups.
+ static const auto func = qmlAttachedPropertiesFunction(nullptr, &T::staticMetaObject);
+ return qmlAttachedPropertiesObject(const_cast<QObject *>(obj), func, create);
}
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 1b7a433a84..facd79d211 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -76,7 +76,7 @@ void QQmlApplicationEnginePrivate::init()
&QCoreApplication::exit, Qt::QueuedConnection);
#if QT_CONFIG(translation)
QTranslator* qtTranslator = new QTranslator;
- if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
+ if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
QCoreApplication::installTranslator(qtTranslator);
translators << qtTranslator;
#endif
@@ -90,10 +90,10 @@ void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile)
if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc"))
return;
- QFileInfo fi(rootFile.toLocalFile());
+ QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile));
QTranslator *translator = new QTranslator;
- if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"))) {
+ if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm"))) {
QCoreApplication::installTranslator(translator);
translators << translator;
} else {
@@ -180,6 +180,9 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
\list
\li Connecting Qt.quit() to QCoreApplication::quit()
\li Automatically loads translation files from an i18n directory adjacent to the main QML file.
+ \list
+ \li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm.
+ \endlist
\li Automatically sets an incubation controller if the scene contains a QQuickWindow.
\li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all
QML files and assets.
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 04debc0615..89b632f87b 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1206,7 +1206,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
\js
var component = Qt.createComponent("Button.qml");
if (component.status == Component.Ready)
- component.createObject(parent, {"x": 100, "y": 100});
+ component.createObject(parent, {x: 100, y: 100});
\endjs
Dynamically created instances can be deleted with the \c destroy() method.
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index a5b92d14f7..c6858780a1 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -1193,7 +1193,8 @@ QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVe
void QQmlMetaType::unregisterType(int typeIndex)
{
QQmlMetaTypeDataPtr data;
- if (const QQmlTypePrivate *d = data->types.value(typeIndex).priv()) {
+ const QQmlType type = data->types.value(typeIndex);
+ if (const QQmlTypePrivate *d = type.priv()) {
removeQQmlTypePrivate(data->idToType, d);
removeQQmlTypePrivate(data->nameToType, d);
removeQQmlTypePrivate(data->urlToType, d);
@@ -1203,6 +1204,7 @@ void QQmlMetaType::unregisterType(int typeIndex)
module->remove(d);
data->clearPropertyCachesForMinorVersion(typeIndex);
data->types[typeIndex] = QQmlType();
+ data->undeletableTypes.remove(type);
}
}
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 9db089c330..57c4eec879 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -454,16 +454,16 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
if (!includeEnums || !name->startsWithUpper()) {
QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
if (ddata && ddata->propertyCache) {
- ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
if (property) {
- lookup->qobjectLookup.ic = This->internalClass();
- lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject());
+ ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
+ lookup->qobjectLookup.qmlTypeIc = This->internalClass();
+ lookup->qobjectLookup.ic = val->objectValue()->internalClass();
lookup->qobjectLookup.propertyCache = ddata->propertyCache;
lookup->qobjectLookup.propertyCache->addref();
lookup->qobjectLookup.propertyData = property;
- lookup->getter = QV4::QObjectWrapper::lookupGetter;
- return lookup->getter(lookup, engine, *This);
+ lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
+ return lookup->getter(lookup, engine, *object);
}
// Fall through to base implementation
}
@@ -485,6 +485,39 @@ bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine
return Object::virtualResolveLookupSetter(object, engine, lookup, value);
}
+ReturnedValue QQmlTypeWrapper::lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [l, engine, &object]() {
+ l->qobjectLookup.propertyCache->release();
+ l->qobjectLookup.propertyCache = nullptr;
+ l->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(l, engine, object);
+ };
+
+ // we can safely cast to a QV4::Object here. If object is something else,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (!o || o->internalClass != l->qobjectLookup.qmlTypeIc)
+ return revertLookup();
+
+ Heap::QQmlTypeWrapper *This = static_cast<Heap::QQmlTypeWrapper *>(o);
+
+ QQmlType type = This->type();
+ if (!type.isValid())
+ return revertLookup();
+
+ if (!type.isQObjectSingleton() && !type.isCompositeSingleton())
+ return revertLookup();
+
+ QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
+ QObject *qobjectSingleton = e->singletonInstance<QObject *>(type);
+ Q_ASSERT(qobjectSingleton);
+
+ Scope scope(engine);
+ ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, qobjectSingleton));
+ return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
+}
+
void Heap::QQmlScopedEnumWrapper::destroy()
{
QQmlType::derefHandle(typePrivate);
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index c797a4ac10..6b51f421b3 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -114,6 +114,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
+ static ReturnedValue lookupSingletonProperty(Lookup *l, ExecutionEngine *engine, const Value &base);
+
protected:
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index cff9cb11a4..f7a91c8b81 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -76,12 +76,24 @@ public:
QString typeNamespace() const;
void setTypeNamespace(const QString &s);
+ static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName)
+ {
+ if (fileName.startsWith(QLatin1Char('/')) || fileName.contains(QLatin1Char(':'))) {
+ qWarning() << item << typeName
+ << "is specified with non-relative URL" << fileName << "in a qmldir file."
+ << "URLs in qmldir files should be relative to the qmldir file's directory.";
+ }
+ }
+
struct Plugin
{
Plugin() {}
Plugin(const QString &name, const QString &path)
- : name(name), path(path) {}
+ : name(name), path(path)
+ {
+ checkNonRelative("Plugin", name, path);
+ }
QString name;
QString path;
@@ -93,7 +105,10 @@ public:
Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
: typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
- internal(false), singleton(false) {}
+ internal(false), singleton(false)
+ {
+ checkNonRelative("Component", typeName, fileName);
+ }
QString typeName;
QString fileName;
@@ -108,7 +123,10 @@ public:
Script() {}
Script(const QString &nameSpace, const QString &fileName, int majorVersion, int minorVersion)
- : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion) {}
+ : nameSpace(nameSpace), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion)
+ {
+ checkNonRelative("Script", nameSpace, fileName);
+ }
QString nameSpace;
QString fileName;
diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
index b0e45fadae..8edc5cb0b6 100644
--- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc
@@ -31,72 +31,68 @@
\section1 Scene Graph Adaptations in Qt Quick
-Originally Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) for parsing
-the scene graph and rendering the results to a render target. From Qt 5.8 onwards
-Qt Quick also supports rendering in software and with Direct3D 12.
+Originally, Qt Quick always relied on OpenGL (OpenGL ES 2.0 or OpenGL 2.0) to parse the scene graph
+and render the results to a render target. From Qt 5.8 onwards, Qt Quick also supports rendering in
+software and with Direct3D 12.
-\section1 Switching Between the Adaptation Used by the Application
+\target Switching Between the Adaptation Used by the Application
+\section1 Switch Between Adaptations in Your Application
-The default rendering backend is still OpenGL, or - in Qt builds with disabled OpenGL support -
-the software renderer. This can be overridden either by using an environment variable
-or a C++ API. The former consists of setting the \c{QT_QUICK_BACKEND} or the
-legacy \c{QMLSCENE_DEVICE} environment variable before launching applications.
-The latter is done by calling QQuickWindow::setSceneGraphBackend() early in the
-application's main() function.
-
-The supported backends are the following
+The default rendering backend is still OpenGL, but in Qt builds with OpenGL support disabled, the
+default is the software renderer. You can override this in one of two ways:
\list
+ \li Use an environment variable - Set the \c{QT_QUICK_BACKEND} or the legacy
+ \c{QMLSCENE_DEVICE} environment variable before launching applications.
+ \li Use a C++ API - Call QQuickWindow::setSceneGraphBackend() early on in the application's
+ main() function.
+\endlist
-\li OpenGL - Requested by the string \c{""} or the enum value QSGRendererInterface::OpenGL.
-
-\li Software - Requested by the string \c{"software"} or the enum value QSGRendererInterface::Software.
-
-\li Direct3D 12 - Requested by the string \c{"d3d12"} or the enum value QSGRendererInterface::Direct3D12.
-
-\li OpenVG - Requested by the string \c{"openvg"} or the enum value QSGRendererInterface::OpenVG.
+The following backends are supported:
+\list
+ \li OpenGL - Request with the \c{""} string or the QSGRendererInterface::OpenGL enum value.
+ \li Software - Request with the \c{"software"} string or the QSGRendererInterface::Software
+ enum value.
+ \li Direct3D 12 - Request with the \c{"d3d12"} string or the QSGRendererInterface::Direct3D12
+ enum value.
+ \li OpenVG - Request with the \c{"openvg"} string or the QSGRendererInterface::OpenVG enum
+ value.
\endlist
-When in doubt which backend is in use, enable basic scenegraph information
-logging via the \c{QSG_INFO} environment variable or the
-\c{qt.scenegraph.general} logging category. This will result in printing some
-information during application startup onto the debug output.
+To find out which backend is in use, you can enable basic scene graph information logging via the
+\c{QSG_INFO} environment variable or the \c{qt.scenegraph.general} logging category. This results
+in some information being printed onto the debug output, during application startup.
-\note Adaptations other than OpenGL will typically come with a set of
-limitations since they are unlikely to provide a feature set 100% compatible
-with OpenGL. However, they may provide their own specific advantages in certain
-areas. Refer to the sections below for more information on the various
-adaptations.
+\note Typically, adaptations other than OpenGL come with a set of limitations as they are unlikely
+ to provide a feature set that's 100% compatible with OpenGL. However, these adaptations may
+ provide their own specific advantages in certain areas. For more information on the various
+ adaptations, refer to the sections below.
\section1 OpenGL ES 2.0 and OpenGL 2.0 Adaptation
-The default adaptation capable of providing the full Qt Quick 2 feature
-set is the OpenGL adaptation. All of the details of the OpenGL
-adaptation can are available here:
-\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}
+The OpenGL adaptation is the default adaptation, which is capable of providing the full Qt Quick 2
+feature set. For more details, see
+\l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation}.
\section1 Software Adaptation
-The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that
-uses the raster paint engine to render the contents of the scene graph. The
-details for this adaptation are available here:
-\l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation}
+The Software adaptation is an alternative renderer for \l{Qt Quick} 2 that uses the raster paint
+engine to render the contents of the scene graph. For more details, see
+\l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation}.
\section1 Direct3D 12 (experimental)
-The Direct3D 12 adaptation is an alternative renderer for \l {Qt Quick} 2 when
-running on Windows 10, both for Win32 and UWP applications. The details for
-this adaptation are available here:
-\l{qtquick-visualcanvas-adaptations-d3d12.html}{Direct3D 12 Adaptation}
+The Direct3D 12 adaptation is an alternative renderer for \l{Qt Quick} 2 when running on Windows
+10, both for Win32 and UWP applications. For more details, see
+\l{qtquick-visualcanvas-adaptations-d3d12.html}{Direct3D 12 Adaptation}.
\section1 OpenVG
-The OpenVG adaptation is an alternative renderer for \l {Qt Quick} 2 that will
-renderer the contents of the scene graph using OpenVG commands to provide
-hardware-acclerated 2D vector and raster graphics. The details for this
-adaptation are available here:
-\l{qtquick-visualcanvas-adaptations-openvg.html}{OpenVG Adaptation}
+The OpenVG adaptation is an alternative renderer for \l{Qt Quick} 2 that renders the contents of
+the scene graph using OpenVG commands to provide hardware-accelerated 2D vector and raster
+graphics. For more details, see
+\l{qtquick-visualcanvas-adaptations-openvg.html}{OpenVG Adaptation}.
*/
@@ -104,47 +100,44 @@ adaptation are available here:
\title Qt Quick Software Adaptation
\page qtquick-visualcanvas-adaptations-software.html
-The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that
-uses the Raster paint engine to render the contents of the scene graph instead
-of OpenGL. As a result of not using OpenGL to render the scene graph, some
-features and optimizations are no longer available. Most Qt Quick 2
-applications will run without modification though any attempts to use
-unsupported features will be ignored. By using the Software adaptation it is
-possible to run Qt Quick 2 applications on hardware and platforms that do not
-have OpenGL support.
-
-The Software adaptation was previously known as the Qt Quick 2D Renderer.
-However, unlike the 2D Renderer, the new, integrated version supports partial
-updates. This means that the full update of the window or screen contents is
-now avoided, and only the changed areas get flushed. This can significantly
-improve performance for many applications.
+The Software adaptation is an alternative renderer for \l {Qt Quick} 2 that uses the Raster paint
+engine to render the contents of the scene graph, instead of OpenGL. Consequently, some features
+and optimizations are not available. Most Qt Quick 2 applications can run without any modification,
+but any attempts to use unsupported features are ignored. By using the Software adaptation, it is
+possible to run Qt Quick 2 applications on hardware and platforms that do not have OpenGL support.
+
+The Software adaptation was previously known as the Qt Quick 2D Renderer. However, unlike the 2D
+Renderer, this new, integrated version supports partial updates. This means that a full update
+of the window or screen contents is now avoided; only the changed areas are flushed. Partial
+updates can significantly improve performance for many applications.
\section2 Shader Effects
-ShaderEffect components in QtQuick 2 can not be rendered by the Software adptation.
+
+ShaderEffect components in QtQuick 2 cannot be rendered by the Software adaptation.
\section2 Qt Graphical Effects Module
-\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use
-graphical effects from this module, then you should not hide the source
-item so that the original item can still be rendered.
+
+\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use graphical effects
+from this module, then you should not hide the source item so that the original item can still be
+rendered.
\section2 Particle Effects
-It is not possible to render particle effects with the Software adaptation. Whenever
-possible, remove particles completely from the scene. Otherwise they will still
-require some processing, even though they are not visible.
+
+It is not possible to render particle effects with the Software adaptation. Whenever possible,
+remove particles completely from the scene. Otherwise, they will still require some processing,
+even though they are not visible.
\section2 Rendering Text
-The text rendering with the Software adaptation is based on software
-rasterization and does not respond as well to transformations such as scaling
-as when using OpenGL. The quality is similar to choosing \l [QML] {Text::renderType}
-{Text.NativeRendering} with \l [QML] {Text} items.
-\section2 Qt Multimedia VideoOutput
-The VideoOutput item of the Qt Multimedia module is not supported with the software
-adaptation. This is because VideoOutput uses the QVideoRendererControl item which
-requires custom QSGGeometryNode behavior that is only present in the default OpenGL
-adaptation.
+The text rendering with the Software adaptation is based on software rasterization and does not
+respond as well to transformations such as scaling, compared to when using OpenGL. The quality is
+similar to choosing \l [QML] {Text::renderType}{Text.NativeRendering} with \l [QML] {Text} items.
+\section2 Qt Multimedia VideoOutput
+The Qt Multimedia module's VideoOutput item is not supported with the Software adaptation. This
+is because VideoOutput uses the QVideoRendererControl item which requires custom QSGGeometryNode
+behavior, which is only present in the default OpenGL adaptation.
*/
@@ -152,251 +145,228 @@ adaptation.
\title Qt Quick Direct3D 12 Adaptation
\page qtquick-visualcanvas-adaptations-d3d12.html
-The Direct3D 12 adaptation for Windows 10 (both Win32 (\c windows platform
-plugin) and UWP (\c winrt platform plugin)) is shipped as a dynamically loaded
-plugin. It will not be functional on earlier Windows versions. The building of
-the plugin is enabled automatically whenever the necessary D3D and DXGI
-develpoment files are present. In practice this currently means Visual Studio
-2015 and newer.
+The Direct3D 12 adaptation for Windows 10, both in Win32 (\c windows platform plugin) and in UWP
+(\c winrt platform plugin), is shipped as a dynamically loaded plugin. This adaptation doesn't work
+on earlier Windows versions. Building this plugin is enabled automatically, whenever the necessary
+D3D and DXGI develpoment files are present. In practice, this currently means Visual Studio 2015
+and newer.
-The adaptation is available both in normal, OpenGL-enabled Qt builds and also
-when Qt was configured with \c{-no-opengl}. However, it is never the default,
-meaning the user or the application has to explicitly request it by setting the
-\c{QT_QUICK_BACKEND} environment variable to \c{d3d12} or by calling
-QQuickWindow::setSceneGraphBackend().
+The adaptation is available both in normal, OpenGL-enabled Qt builds, and also when Qt is
+configured with \c{-no-opengl}. However, it's never the default, meaning that the user or the
+application has to explicitly request it by setting the \c{QT_QUICK_BACKEND} environment variable
+to \c{d3d12} or by calling QQuickWindow::setSceneGraphBackend().
\section2 Motivation
-This experimental adaptation is the first Qt Quick backend focusing on a
-modern, lower-level graphics API in combination with a windowing system
-interface different from the traditional approaches used in combination with
-OpenGL.
-
-It also allows better integration with Windows, Direct3D being the primary
-vendor-supported solution. This means that there are fewer problems anticipated
-with drivers, operations like window resizes, and special events like graphics
-device loss caused by device resets or graphics driver updates.
-
-Performance-wise the general expectation is a somewhat lower CPU usage compared
-to OpenGL due to lower driver overhead, and a higher GPU utilization with less
-wasted idle time. The backend does not heavily utilize threads yet, which means
-there are opportunities for further improvements in the future, for example to
-further optimize image loading.
-
-The D3D12 backend also introduces support for pre-compiled shaders. All the
-backend's own shaders (used by the built-in materials on which the Rectangle,
-Image, Text, etc. QML types are built) are compiled to D3D shader bytecode when
-compiling Qt. Applications using ShaderEffect items can chose to ship bytecode
-either in regular files or via the Qt resource system, or use HLSL source
-strings. Unlike OpenGL, the compilation for the latter is properly threaded,
-meaning shader compilation will not block the application and its user
+This experimental adaptation is the first Qt Quick backend that focuses on a modern, lower-level
+graphics API in combination with a windowing system interface that's different from the traditional
+approaches used in combination with OpenGL.
+
+This adaptation also allows better integration with Windows, as Direct3D is the primary
+vendor-supported solution. Consequently, there are fewer problems anticipated with drivers,
+operations like window resizes, and special events like graphics device loss caused by device
+resets or graphics driver updates.
+
+Performance-wise, the general expectation is a somewhat lower CPU usage compared to OpenGL, due to
+lower driver overhead, and a higher GPU utilization with less idle time wastage. The backend
+doesn't heavily utilize threads yet, which means there are opportunities for further improvements
+in the future, for example to further optimize image loading.
+
+The D3D12 backend also introduces support for pre-compiled shaders. All the backend's own shaders
+(used by the built-in materials on which the Rectangle, Image, Text, and other QML types are built
+with) are compiled to D3D shader bytecode when you compile Qt. Applications using ShaderEffect
+items can choose to ship bytecode either in regular files, via the Qt resource system, or use
+High Level Shading Language for DirectX (HLSL) source strings. Unlike OpenGL, the compilation for
+HLSL is properly threaded, meaning shader compilation won't block the application and its user
interface.
\section2 Graphics Adapters
-The plugin does not necessarily require hardware acceleration. Using WARP, the
-Direct3D software rasterizer, is also an option. By default the first adapter
-providing hardware acceleration is chosen. To override this, in order to use
-another graphics adapter or to force the usage of the software rasterizer, set
-the environment variable \c{QT_D3D_ADAPTER_INDEX} to the index of the adapter.
-The discovered adapters are printed at startup when \c{QSG_INFO} or the logging
-category \c{qt.scenegraph.general} is enabled.
+The plugin does not necessarily require hardware acceleration. You can also use WARP, the Direct3D
+software rasterizer. By default, the first adapter providing hardware acceleration is chosen. To
+override this and use another graphics adapter or to force the use of the software rasterizer, set
+the \c{QT_D3D_ADAPTER_INDEX} environment variable to the index of the adapter. The adapters
+discovered are printed at startup when \c{QSG_INFO} or the \c{qt.scenegraph.general} logging
+category is enabled.
\section2 Troubleshooting
-When encountering issues, always set the \c{QSG_INFO} and \c{QT_D3D_DEBUG}
-environment variables to 1 in order to get debug and warning messages printed
-on the debug output. The latter enables the Direct3D debug layer. Note that the
-debug layer should not be enabled in production use since it can significantly
-impact performance (CPU load) due to increased API overhead.
+If you encounter issues, always set the \c{QSG_INFO} and \c{QT_D3D_DEBUG} environment variables
+to \c 1, to get debug and warning messages printed on the debug output. \c{QT_D3D_DEBUG} enables
+the Direct3D debug layer.
+
+\note The debug layer shouldn't be enabled in production use, since it can significantly impact
+performance (CPU load) due to increased API overhead.
\section2 Render Loops
-By default the D3D12 adaptation uses a single-threaded render loop similar to
-OpenGL's \c windows render loop. There is also a threaded variant available, that
-can be requested by setting the \c{QSG_RENDER_LOOP} environment variable to \c
-threaded. However, due to conceptual limitations in DXGI, the windowing system
-interface, the threaded loop is prone to deadlocks when multiple QQuickWindow
-or QQuickView instances are shown. Therefore the default is the single-threaded
-loop for the time being. This means that with the D3D12 backend applications
-are expected to move their work from the main (GUI) thread out to worker
-threads, instead of expecting Qt to keep the GUI thread responsive and suitable
-for heavy, blocking operations.
-
-See the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph page} for more
-information on render loops and
-\l{https://msdn.microsoft.com/en-us/library/windows/desktop/ee417025(v=vs.85).aspx#multithreading_and_dxgi}{the
-MSDN page for DXGI} regarding the issues with multithreading.
+By default, the D3D12 adaptation uses a single-threaded render loop similar to OpenGL's \c windows
+render loop. A threaded variant is also available, that you can request by setting the
+\c{QSG_RENDER_LOOP} environment variable to \c threaded. However, due to conceptual limitations in
+DXGI, the windowing system interface, the threaded loop is prone to deadlocks when multiple
+QQuickWindow or QQuickView instances are shown. Consequently, for the time being, the default is
+the single-threaded loop. This means that with the D3D12 backend, applications are expected to move
+their work from the main (GUI) thread out to worker threads, instead of expecting Qt to keep the
+GUI thread responsive and suitable for heavy, blocking operations.
+
+For more information see \l{qtquick-visualcanvas-scenegraph.html}{Qt Quick Scene Graph} for
+details on render loops and
+\l{https://docs.microsoft.com/en-us/windows/desktop/direct3darticles/dxgi-best-practices#multithreading-and-dxgi}{Multithreading and DXGI}
+regarding the issues with multithreading.
\section2 Renderer
-The scenegraph renderer in the D3D12 adaptation does not currently perform any
-batching. This is less of an issue, unlike OpenGL, because state changes are
-not presenting any problems in the first place. The simpler renderer logic can
-also lead to lower CPU overhead in some cases. The trade-offs between the
-various approaches are currently under research.
+The scene graph renderer in the D3D12 adaptation currently doesn't perform any batching. This is
+less of an issue, unlike OpenGL, because state changes don't present any problems in the first
+place. The simpler renderer logic can also lead to lower CPU overhead in some cases. The trade-offs
+between the various approaches are currently under research.
\section2 Shader Effects
-The ShaderEffect QML type is fully functional with the D3D12 adaptation as well.
-However, the interpretation of the fragmentShader and vertexShader properties is
-different than with OpenGL.
+The ShaderEffect QML type is fully functional with the D3D12 adaptation as well. However, the
+interpretation of the fragmentShader and vertexShader properties is different than with OpenGL.
-With D3D12, these strings can either be an URL for a local file or a file in
-the resource system, or a HLSL source string. The former indicates that the
-file in question contains pre-compiled D3D shader bytecode generated by the
-\c fxc tool, or, alternatively, HLSL source code. The type of the file is detected
-automatically. This means that the D3D12 backend supports all options from
-GraphicsInfo.shaderCompilationType and GraphicsInfo.shaderSourceType.
+With D3D12, these strings can either be a URL for a local file, a file in the resource system,
+or an HLSL source string. Using a URL for a local file or a file in the resource system
+indicates that the file in question contains pre-compiled D3D shader bytecode generated by the
+\c fxc tool, or, alternatively, HLSL source code. The type of file is detected automatically.
+This means that the D3D12 backend supports all options from GraphicsInfo.shaderCompilationType
+and GraphicsInfo.shaderSourceType.
-Unlike OpenGL, there is a QFileSelector with the extra selector \c hlsl used
-whenever opening a file. This allows easy creation of ShaderEffect items that
-are functional across both backends, for example by placing the GLSL source
-code into \c{shaders/effect.frag}, the HLSL source code or - preferably -
-pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing
-\c{fragmentShader: "qrc:shaders/effect.frag"} in QML.
-
-See the ShaderEffect documentation for more details.
+Unlike OpenGL, whenever you open a file, there is a QFileSelector with the extra \c hlsl selector
+used. This provides easy creation of ShaderEffect items that are functional across both backends,
+for example by placing the GLSL source code into \c{shaders/effect.frag}, the HLSL source code or
+- preferably - pre-compiled bytecode into \c{shaders/+hlsl/effect.frag}, while simply writing
+\c{fragmentShader: "qrc:shaders/effect.frag"} in QML. For more details, see ShaderEffect.
\section2 Multisample Render Targets
-The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow
-or QQuickView (or set via QSurfaceFormat::setDefaultFormat()), with two
-exceptions: QSurfaceFormat::samples() and QSurfaceFormat::alphaBufferSize() are
-still taken into account. When the samples value is greater than 1, multisample
-offscreen render targets will be created with the specified sample count and a
-quality of the maximum supported quality level. The backend automatically
-performs resolving into the non-multisample swapchain buffers after each frame.
+The Direct3D 12 adaptation ignores the QSurfaceFormat set on the QQuickWindow or QQuickView, or
+set via QSurfaceFormat::setDefaultFormat(), with two exceptions: QSurfaceFormat::samples() and
+QSurfaceFormat::alphaBufferSize() are still taken into account. When the sample value is greater
+than 1, multisample offscreen render targets will be created with the specified sample count at
+the maximum supported quality level. The backend automatically performs resolving into the
+non-multisample swapchain buffers after each frame.
\section2 Semi-transparent Windows
-When the alpha channel is enabled either via
-QQuickWindow::setDefaultAlphaBuffer() or by setting alphaBufferSize to a
-non-zero value in the window's QSurfaceFormat or in the global format managed
-by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a
-swapchain for composition and go through DirectComposition since the flip model
-swapchain (which is mandatory) would not support transparency otherwise.
+When the alpha channel is enabled either via QQuickWindow::setDefaultAlphaBuffer() or by setting
+alphaBufferSize to a non-zero value in the window's QSurfaceFormat or in the global format managed
+by QSurfaceFormat::setDefaultFormat(), the D3D12 backend will create a swapchain for composition
+and go through DirectComposition. This is necessary, because the mandatory flip model swapchain
+wouldn't support transparency otherwise.
-It is therefore important not to unneccessarily request an alpha channel. When
-the alphaBufferSize is 0 or the default -1, all these extra steps can be
-avoided and the traditional window-based swapchain is sufficient.
+Therefore, it's important not to unneccessarily request an alpha channel. When the alphaBufferSize
+is 0 or the default -1, all these extra steps can be avoided and the traditional window-based
+swapchain is sufficient.
-This is not relevant on WinRT because there the backend always uses a
-composition swapchain which is associated with the ISwapChainPanel that backs
-QWindow on that platform.
+On WinRT, this isn't relevant because the backend there always uses a composition swapchain which
+is associated with the ISwapChainPanel that backs QWindow on that platform.
\section2 Mipmaps
-Mipmap generation is supported and handled transparently to the applications
-via a built-in compute shader, but is experimental and only supports
-power-of-two images at the moment. Textures of other size will work too, but
-this involves a QImage-based scaling on the CPU first. Therefore avoid enabling
-mipmapping for NPOT images whenever possible.
+Mipmap generation is supported and handled transparently to the applications via a built-in compute
+shader. However, at the moment, this feature is experimental and only supports power-of-two images.
+Textures of other size will work too, but this involves a QImage-based scaling on the CPU first.
+Therefore, avoid enabling mipmapping for Non-Power-Of-Two (NPOT) images whenever possible.
\section2 Image Formats
-When creating textures via the C++ scenegraph APIs like
-QQuickWindow::createTextureFromImage(), 32-bit formats will not involve any
-conversion, they will map directly to the corresponding \c{R8G8B8A8_UNORM} or
-\c{B8G8R8A8_UNORM} format. Everything else will trigger a QImage-based format
-conversion on the CPU first.
+When creating textures via C++ scene graph APIs like QQuickWindow::createTextureFromImage(), 32-bit
+formats won't involve any conversion, they'll map directly to the corresponding \c{R8G8B8A8_UNORM}
+or \c{B8G8R8A8_UNORM} format. Everything else will trigger a QImage-based format conversion on the
+CPU first.
\section2 Unsupported Features
-Particles and some other OpenGL-dependent utilities, like
-QQuickFramebufferObject, are not currently supported.
+Particles and some other OpenGL-dependent utilities, like QQuickFramebufferObject, are currently
+not supported.
-Like with the \l{qtquick-visualcanvas-adaptations-software.html}{Software
-adaptation}, text is always rendered using the native method. Distance
-field-based text rendering is not currently implemented.
+Like with \l{qtquick-visualcanvas-adaptations-software.html}{Software adaptation}, text is always
+rendered using the native method. Distance field-based text rendering is currently not implemented.
-The shader sources in the \l {Qt Graphical Effects} module have not been ported
-to any format other than the OpenGL 2.0 compatible one, meaning the QML types
-provided by that module are not currently functional with the D3D12 backend.
+The shader sources in the \l {Qt Graphical Effects} module have not been ported to any format other
+than the OpenGL 2.0 compatible one, meaning that the QML types provided by that module are currently
+not functional with the D3D12 backend.
-Texture atlases are not currently in use.
+Texture atlases are currently not in use.
-The renderer may lack support for certain minor features, for example drawing
-points and lines with a width other than 1.
+The renderer may lack support for certain minor features, such as drawing points and lines with a
+width other than 1.
-Custom Qt Quick items using custom scenegraph nodes can be problematic.
-Materials are inherently tied to the graphics API. Therefore only items using
-the utility rectangle and image nodes are functional across all adaptations.
+Custom Qt Quick items using custom scene graph nodes can be problematic because materials are
+inherently tied to the graphics API. Therefore, only items that use the utility rectangle and image
+nodes are functional across all adaptations.
-QQuickWidget and its underlying OpenGL-based compositing architecture is not
-supported. If mixing with QWidget-based user interfaces is desired, use
-QWidget::createWindowContainer() to embed the native window of the QQuickWindow
-or QQuickView.
+QQuickWidget and its underlying OpenGL-based compositing architecture is not supported. If you need
+to mix with QWidget-based user interfaces, use QWidget::createWindowContainer() to embed the native
+window of the QQuickWindow or QQuickView.
-Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with
-the D3D12 adaptation at the moment.
+Finally, rendering via QSGEngine and QSGAbstractRenderer is not feasible with the D3D12 adaptation
+at the moment.
\section2 Related APIs
-To integrate custom Direct3D 12 rendering, use QSGRenderNode in combination
-with QSGRendererInterface. This approach does not rely on OpenGL contexts or
-API specifics like framebuffers, and allows exposing the graphics device and
-command buffer from the adaptation. It is not necessarily suitable for easy
-integration of all types of content, in particular true 3D, so it will likely
-get complemented by an alternative to QQuickFramebufferObject in future
-releases.
+To integrate custom Direct3D 12 rendering, use QSGRenderNode in combination with
+QSGRendererInterface. This approach doesn't rely on OpenGL contexts or API specifics like
+framebuffers, and allows exposing the graphics device and command buffer from the adaptation. It's
+not necessarily suitable for easy integration of all types of content, in particular true 3D, so
+it'll likely get complemented by an alternative to QQuickFramebufferObject in future releases.
-To perform runtime decisions based on the adaptation in use, use
-QSGRendererInterface from C++ and GraphicsInfo from QML. They can also be used
-to check the level of shader support (shading language, compilation approach).
+To perform runtime decisions based on the adaptation, use QSGRendererInterface from C++ and
+GraphicsInfo from QML. They can also be used to check the level of shader support: shading
+language, compilation approach, and so on.
-When creating custom items, use the new QSGRectangleNode and QSGImageNode
-classes. These replace the now deprecated QSGSimpleRectNode and
-QSGSimpleTextureNode. Unlike their predecessors, the new classes are
-interfaces, and implementations are created via the factory functions
-QQuickWindow::createRectangleNode() and QQuickWindow::createImageNode().
+When creating custom items, use the new QSGRectangleNode and QSGImageNode classes. These replace
+the now deprecated QSGSimpleRectNode and QSGSimpleTextureNode. Unlike their predecessors, these new
+classes are interfaces, and implementations are created via the QQuickWindow::createRectangleNode()
+and QQuickWindow::createImageNode() factory functions.
\section2 Advanced Configuration
-The D3D12 adaptation can keep multiple frames in flight, similarly to modern
-game engines. This is somewhat different from the traditional render - swap -
-wait for vsync model and allows better GPU utilization at the expense of higher
-resource usage. This means that the renderer will be a number of frames ahead
-of what is displayed on the screen.
+The D3D12 adaptation can keep multiple frames in flight, similar to modern game engines. This is
+somewhat different from the traditional "render - swap - wait for vsync" model and allows for
+better GPU utilization at the expense of higher resource use. This means that the renderer will
+be a number of frames ahead of what is displayed on the screen.
-For a discussion of flip model swap chains and the typical configuration
-parameters, refer to
-\l{https://software.intel.com/en-us/articles/sample-application-for-direct3d-12-flip-model-swap-chains}{this
-article}.
+For a discussion of flip model swap chains and the typical configuration parameters, refer to
+\l{https://software.intel.com/en-us/articles/sample-application-for-direct3d-12-flip-model-swap-chains}
+{Sample Application for Direct3D 12 Flip Model Swap Chains}.
-Vertical synchronization is always enabled, meaning Present() is invoked with
-an interval of 1.
+Vertical synchronization is always enabled, meaning Present() is invoked with an interval of 1.
The configuration can be changed by setting the following environment variables:
-\list
-
-\li \c{QT_D3D_BUFFER_COUNT} - The number of swap chain buffers in range 2 - 4.
-The default value is 3.
-
-\li \c{QT_D3D_FRAME_COUNT} - The number of frames prepared without blocking in
-range 1 - 4. Note that Present will start blocking after queuing 3 frames
-(regardless of \c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use.
-Note that every additional frame increases GPU resource usage since geometry
-and constant buffer data will have to be duplicated, and involves more
-bookkeeping on the CPU side. The default value is 2.
-
-\li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY} - When set to a value between 1
-and 16, the frame latency is set to the specified value. This changes the limit
-for Present() and will trigger a wait for an available swap chain buffer when
-beginning each frame. Refer to the article above for a detailed discussion.
-This is considered experimental for now and the default value is 0 (disabled).
-
-\li \c{QT_D3D_BLOCKING_PRESENT} - When set to a non-zero value, there will be
-CPU-side wait for the GPU to finish its work after each call to Present. This
-effectively kills all parallelism but makes the behavior resemble the
-traditional swap-blocks-for-vsync model, and can therefore be useful in some
-special cases. This is not the same as setting the frame count to 1 because
-that still avoids blocking after Present, and may block only when starting to
-prepare the next frame (or may not block at all depending on the time gap
-between the frames). By default blocking present is disabled.
-
-\endlist
+\table
+ \header
+ \li Environment variable
+ \li Description
+ \row
+ \li \c{QT_D3D_BUFFER_COUNT}
+ \li The number of swap chain buffers in range 2 - 4. The default value is 3.
+ \row
+ \li \c{QT_D3D_FRAME_COUNT}
+ \li The number of frames prepared without blocking in range 1 - 4. The default value is 2.
+ Present() starts blocking after queuing 3 frames (regardless of
+ \c{QT_D3D_BUFFER_COUNT}), unless the waitable object is in use. Every additional frame
+ increases GPU resource usage since geometry and constant buffer data needs to be
+ duplicated, and involves more bookkeeping on the CPU side.
+ \row
+ \li \c{QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY}
+ \li The frame latency in range 1 - 16. The default value is 0 (disabled).
+ Changes the limit for Present() and triggers a wait for an available swap chain buffer
+ when beginning each frame. For a detailed discussion, see the article linked above.
+ \note Currently, this behavior is experimental.
+ \row
+ \li \c{QT_D3D_BLOCKING_PRESENT}
+ \li The time the CPU should wait, a non-zero value, for the GPU to finish its work after
+ each call to Present(). The default value is 0 (disabled). This behavior effectively
+ kills all parallelism but makes the behavior resemble the traditional
+ swap-blocks-for-vsync model, which can be useful in some special cases. However, this
+ behavior is not the same as setting the frame count to 1 because that still avoids
+ blocking after Present(), and may only block when starting to prepare the next frame
+ (or may not block at all depending on the time gap between the frames).
+\endtable
*/
@@ -404,68 +374,72 @@ between the frames). By default blocking present is disabled.
\title Qt Quick OpenVG Adaptation
\page qtquick-visualcanvas-adaptations-openvg.html
-The OpenVG adaptation is an alternative renderer for \l {Qt Quick} 2 that will
-renderer the contents of the scene graph using OpenVG commands to provide
-hardware-acclerated 2D vector and raster graphics. Much like the Software
-adaptation, some features and optimizations are no longer available. Most
-Qt Quick 2 applications will run without modification though any attempts to
-use unsupported features will be ignored.
+The OpenVG adaptation is an alternative renderer for \l{Qt Quick} 2 that renders the contents of
+the scene graph using OpenVG commands to provide hardware accelerated 2D vector and raster
+graphics. Much like the \l{qtquick-visualcanvas-adaptations-software.html}{Software Adaptation},
+some features and optimizations are no longer available. Most Qt Quick 2 applications will run
+without modification though any attempts to use unsupported features will be ignored.
\section2 EGL Requirement
-Unlike the defualt OpenGL Renderer, there is no built in support for acquiring
-an OpenVG context. This means that the renderer has the responsbility of
-requesting and managing the the current context. To do this EGL has to be used
-directly in the OpenVG renderer. This means that the OpenVG renderer is only
-usable with platform plugins that support creating QWindows with support for
-QSurfaceFormat::OpenVG. From this window, the renderer can get an EGLSurface
-which can be used with an EGLContext to render OpenVG content.
+
+Unlike the default OpenGL Renderer, there is no built-in support to acquire an OpenVG context.
+This means that the renderer is responsible for requesting and managing the the current context.
+To do this, you use EGL directly in the OpenVG renderer. Consequently, the OpenVG renderer can only
+be used with platform plugins that support creating QWindows with support for
+QSurfaceFormat::OpenVG. From this window, the renderer can get an EGLSurface which can then be used
+with an EGLContext to render OpenVG content.
\section2 Renderer
-The OpenVG Renderer works by using the OpenVG API to send commands and data to
-a Vector GPU which will render the scenegraph in an accelerated manner, offloading
-graphics rendering from the CPU. Many operations like the rendering of rectangles
-and fonts glyphs ideal for OpenVG because these can be represented as paths which
-are stroked and filled. Rendering scenegraph items that would typically involve
-textures are handled in the OpenVG renderer by using VGImage. In addition when
-rendering to offscreen surfaces (like when using Layers), the scene subtree is
-rendered to a VGImage which can be reused in the scene.
+
+The OpenVG Renderer uses the OpenVG API to send commands and data to a Vector GPU that renders the
+scene graph in an accelerated manner, offloading graphics rendering from the CPU. Many operations
+like the rendering of rectangles and font glyphs are ideal for OpenVG because they can be
+represented as paths which are stroked and filled. Rendering scene graph items that would typically
+involve textures are handled in the OpenVG renderer using VGImage. Additionally, when you render
+to offscreen surfaces (like with Layers), the scene subtree is rendered to a VGImage which can be
+reused in the scene.
\section2 Render Loop
-The OpenVG Renderer mirrors the behavior of the Basic render loop and will execute
-all OpenVG commands in a single thread.
-See the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph page} for more
-information on render loops
+The OpenVG Renderer mirrors the behavior of the Basic render loop and it runs all OpenVG commands
+in a single thread.
+
+For more information on render loops, see
+\l{qtquick-visualcanvas-scenegraph.html}{Qt Quick Scene Graph}.
\section2 Shader Effects
-ShaderEffect components in QtQuick 2 can not be rendered by the OpenVG adaptation.
-While it is possible to user ShaderEffectSource and QML Item Layers (which are both
-offscreen surfaces), it is not actually possible to apply shader effects to them
-via the ShaderEffect item. This is because OpenVG lacks an API for applying per
-vertex and per fragment shader operations. It may be possible however to take
-advantage of Image Filter operations in the OpenVG API to get similar effects to
-what is provided by ShaderEffects in custom items. To integrate custom OpenVG
-rendering, use QSGRenderNode in combination with QSGRendererInterface.
+
+ShaderEffect components in QtQuick 2 can't be rendered by the OpenVG adaptation. While it's
+possible to use ShaderEffectSource and QML Item Layers (which are both offscreen surfaces), it's
+not possible to apply shader effects to them via the ShaderEffect item. This is because OpenVG
+lacks an API for applying per vertex and per fragment shader operations. However, you may be able
+to take advantage of Image Filter operations in the OpenVG API to get effects that are similar to
+what ShaderEffects provides in custom items. To integrate custom OpenVG rendering, use
+QSGRenderNode in combination with QSGRendererInterface.
\section2 Qt Graphical Effects Module
-\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use
-graphical effects from this module, then you should not hide the source
-item so that the original item can still be rendered.
+
+\l {Qt Graphical Effects} uses ShaderEffect items to render effects. If you use graphical effects
+from this module, then you shouldn't hide the source item so that the original item can still be
+rendered.
\section2 Particle Effects
-It is not possible to render particle effects with the OpenVG adaptation. Whenever
-possible, remove particles completely from the scene. Otherwise they will still
-require some processing, even though they are not visible.
+
+It's not possible to render particle effects with the OpenVG adaptation. Whenever possible, remove
+particles completely from the scene. Otherwise they'll still require some processing, even though
+they are not visible.
\section2 Rendering Text
-The text rendering with the OpenVG adaptation is based on rendering the glpyh
-paths, and does not use the distance fields technique used by the OpenGL backend.
+
+Text rendering with the OpenVG adaptation is based on rendering the glyph paths, and doesn't use
+the distance fields technique, unlike with the OpenGL backend.
\section2 Perspective Transforms
-The OpenVG API does not allow paths to be transformed with non-affine transforms,
-while it is possible with Qt Quick. This means that rendering components using
-paths like Rectangles and Text, when applying perspective transforms the OpenVG
-backend will first render to a VGImage before applying transformations. This uses
-more memory at runtime and is a slower path so avoid doing this if necessary.
+
+The OpenVG API doesn't allow paths to be transformed with non-affine transforms, but it's
+possible with Qt Quick. Consquently, when you render components using paths like Rectangles and
+Text while applying perspective transforms, the OpenVG backend first renders to a VGImage before
+applying transformations. This behavior uses more memory at runtime and takes more time; avoid it
+if possible.
*/
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 6638fbd3e8..fecfa5fd2d 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -191,7 +191,7 @@ public:
void resetFirstItemPosition(qreal pos = 0.0) override;
void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) override;
- void createHighlight() override;
+ void createHighlight(bool onDestruction = false) override;
void updateHighlight() override;
void resetHighlightPosition() override;
@@ -696,9 +696,8 @@ void QQuickGridViewPrivate::adjustFirstItem(qreal forwards, qreal backwards, int
gridItem->setPosition(gridItem->colPos(), gridItem->rowPos() + ((moveCount / columns) * rowSize()));
}
-void QQuickGridViewPrivate::createHighlight()
+void QQuickGridViewPrivate::createHighlight(bool onDestruction)
{
- Q_Q(QQuickGridView);
bool changed = false;
if (highlight) {
if (trackedItem == highlight)
@@ -714,6 +713,10 @@ void QQuickGridViewPrivate::createHighlight()
changed = true;
}
+ if (onDestruction)
+ return;
+
+ Q_Q(QQuickGridView);
if (currentItem) {
QQuickItem *item = createHighlightItem();
if (item) {
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 1f8a0de72b..431cb80a75 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -162,7 +162,7 @@ QQuickItemView::QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent)
QQuickItemView::~QQuickItemView()
{
Q_D(QQuickItemView);
- d->clear();
+ d->clear(true);
if (d->ownModel)
delete d->model;
delete d->header;
@@ -1662,7 +1662,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
releaseItem(oldCurrentItem);
}
-void QQuickItemViewPrivate::clear()
+void QQuickItemViewPrivate::clear(bool onDestruction)
{
Q_Q(QQuickItemView);
currentChanges.reset();
@@ -1683,7 +1683,7 @@ void QQuickItemViewPrivate::clear()
currentItem = nullptr;
if (oldCurrentItem)
emit q->currentItemChanged();
- createHighlight();
+ createHighlight(onDestruction);
trackedItem = nullptr;
if (requestedIndex >= 0) {
@@ -2352,15 +2352,16 @@ void QQuickItemView::destroyingItem(QObject *object)
bool QQuickItemViewPrivate::releaseItem(FxViewItem *item)
{
Q_Q(QQuickItemView);
- if (!item || !model)
+ if (!item)
return true;
if (trackedItem == item)
trackedItem = nullptr;
item->trackGeometry(false);
- QQmlInstanceModel::ReleaseFlags flags = model->release(item->item);
- if (item->item) {
- if (flags == 0) {
+ QQmlInstanceModel::ReleaseFlags flags = {};
+ if (model && item->item) {
+ flags = model->release(item->item);
+ if (!flags) {
// item was not destroyed, and we no longer reference it.
QQuickItemPrivate::get(item->item)->setCulled(true);
unrequestedItems.insert(item->item, model->indexOf(item->item, q));
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 0f1594f904..860605991b 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -163,7 +163,7 @@ public:
int mapFromModel(int modelIndex) const;
virtual void init();
- virtual void clear();
+ virtual void clear(bool onDestruction=false);
virtual void updateViewport();
void regenerate(bool orientationChanged=false);
@@ -327,7 +327,7 @@ protected:
virtual bool hasStickyHeader() const { return false; }
virtual bool hasStickyFooter() const { return false; }
- virtual void createHighlight() = 0;
+ virtual void createHighlight(bool onDestruction = false) = 0;
virtual void updateHighlight() = 0;
virtual void resetHighlightPosition() = 0;
virtual bool movingFromHighlight() { return false; }
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 81d019a26d..146917c679 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -81,7 +81,7 @@ public:
FxViewItem *snapItemAt(qreal pos);
void init() override;
- void clear() override;
+ void clear(bool onDestruction) override;
bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) override;
bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) override;
@@ -98,7 +98,7 @@ public:
void adjustFirstItem(qreal forwards, qreal backwards, int) override;
void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult) override;
- void createHighlight() override;
+ void createHighlight(bool onDestruction = false) override;
void updateHighlight() override;
void resetHighlightPosition() override;
bool movingFromHighlight() override;
@@ -575,7 +575,7 @@ void QQuickListViewPrivate::init()
::memset(sectionCache, 0, sizeof(QQuickItem*) * sectionCacheSize);
}
-void QQuickListViewPrivate::clear()
+void QQuickListViewPrivate::clear(bool onDestruction)
{
for (int i = 0; i < sectionCacheSize; ++i) {
delete sectionCache[i];
@@ -587,7 +587,7 @@ void QQuickListViewPrivate::clear()
releaseSectionItem(nextSectionItem);
nextSectionItem = nullptr;
lastVisibleSection = QString();
- QQuickItemViewPrivate::clear();
+ QQuickItemViewPrivate::clear(onDestruction);
}
FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
@@ -634,7 +634,7 @@ void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
{
if (!item || !model)
- return true;
+ return QQuickItemViewPrivate::releaseItem(item);
QPointer<QQuickItem> it = item->item;
QQuickListViewAttached *att = static_cast<QQuickListViewAttached*>(item->attached);
@@ -876,9 +876,8 @@ void QQuickListViewPrivate::updateSizeChangesBeforeVisiblePos(FxViewItem *item,
QQuickItemViewPrivate::updateSizeChangesBeforeVisiblePos(item, removeResult);
}
-void QQuickListViewPrivate::createHighlight()
+void QQuickListViewPrivate::createHighlight(bool onDestruction)
{
- Q_Q(QQuickListView);
bool changed = false;
if (highlight) {
if (trackedItem == highlight)
@@ -896,6 +895,10 @@ void QQuickListViewPrivate::createHighlight()
changed = true;
}
+ if (onDestruction)
+ return;
+
+ Q_Q(QQuickListView);
if (currentItem) {
QQuickItem *item = createHighlightItem();
if (item) {
diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp
index 0cbabaa170..bc1f787b81 100644
--- a/src/quick/items/qquickopenglshadereffect.cpp
+++ b/src/quick/items/qquickopenglshadereffect.cpp
@@ -221,7 +221,7 @@ QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon()
clearSignalMappers(shaderType);
}
-void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key::ShaderType shaderType)
+void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
{
for (int i = 0; i < uniformData[shaderType].size(); ++i) {
if (signalMappers[shaderType].at(i) == 0)
@@ -229,11 +229,12 @@ void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QObject *obj, Key
const UniformData &d = uniformData[shaderType].at(i);
auto mapper = signalMappers[shaderType].at(i);
void *a = mapper;
- QObjectPrivate::disconnect(obj, mapper->signalIndex(), &a);
+ QObjectPrivate::disconnect(item, mapper->signalIndex(), &a);
if (d.specialType == UniformData::Sampler || d.specialType == UniformData::SamplerExternal) {
QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
if (source) {
- QQuickItemPrivate::get(source)->derefWindow();
+ if (item->window())
+ QQuickItemPrivate::get(source)->derefWindow();
QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
}
}
diff --git a/src/quick/items/qquickopenglshadereffect_p.h b/src/quick/items/qquickopenglshadereffect_p.h
index 3087c1eb0b..0c2adadc62 100644
--- a/src/quick/items/qquickopenglshadereffect_p.h
+++ b/src/quick/items/qquickopenglshadereffect_p.h
@@ -89,7 +89,7 @@ struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
~QQuickOpenGLShaderEffectCommon();
- void disconnectPropertySignals(QObject *item, Key::ShaderType shaderType);
+ void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
void connectPropertySignals(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType);
void updateParseLog(bool ignoreAttributes);
void lookThroughShaderCode(QQuickItem *item, const QMetaObject *itemMetaObject, Key::ShaderType shaderType, const QByteArray &code);
diff --git a/src/quick/items/qquickopenglshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp
index f96ebebcd6..3ccd2a76f7 100644
--- a/src/quick/items/qquickopenglshadereffectnode.cpp
+++ b/src/quick/items/qquickopenglshadereffectnode.cpp
@@ -505,7 +505,7 @@ void QQuickOpenGLShaderEffectNode::markDirtyTexture()
Q_EMIT dirtyTexture();
}
-void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(const QObject *object)
+void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(QObject *object)
{
Q_ASSERT(material());
static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->invalidateTextureProvider(object);
diff --git a/src/quick/items/qquickopenglshadereffectnode_p.h b/src/quick/items/qquickopenglshadereffectnode_p.h
index 6d68ba87b9..705b8d4f47 100644
--- a/src/quick/items/qquickopenglshadereffectnode_p.h
+++ b/src/quick/items/qquickopenglshadereffectnode_p.h
@@ -159,7 +159,7 @@ Q_SIGNALS:
private Q_SLOTS:
void markDirtyTexture();
- void textureProviderDestroyed(const QObject *object);
+ void textureProviderDestroyed(QObject *object);
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickrepeater.cpp b/src/quick/items/qquickrepeater.cpp
index c8a03aff33..c8c5281089 100644
--- a/src/quick/items/qquickrepeater.cpp
+++ b/src/quick/items/qquickrepeater.cpp
@@ -120,16 +120,17 @@ QQuickRepeaterPrivate::~QQuickRepeaterPrivate()
Also, note that Repeater is \l {Item}-based, and can only repeat \l {Item}-derived objects.
For example, it cannot be used to repeat QtObjects:
- \code
- //bad code
+
+ \qml
+ // bad code:
Item {
- Can't repeat QtObject as it doesn't derive from Item.
+ // Can't repeat QtObject as it doesn't derive from Item.
Repeater {
model: 10
QtObject {}
}
}
- \endcode
+ \endqml
*/
/*!
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 05d9e5e36d..3721731f68 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -515,6 +515,20 @@ QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
m_impl = new QQuickGenericShaderEffect(this, this);
}
+QQuickShaderEffect::~QQuickShaderEffect()
+{
+ // Delete the implementations now, while they still have have
+ // valid references back to us.
+#if QT_CONFIG(opengl)
+ auto *glImpl = m_glImpl;
+ m_glImpl = nullptr;
+ delete glImpl;
+#endif
+ auto *impl = m_impl;
+ m_impl = nullptr;
+ delete impl;
+}
+
/*!
\qmlproperty string QtQuick::ShaderEffect::fragmentShader
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index cabad930fc..c5bddc40d2 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -92,6 +92,7 @@ public:
Q_ENUM(Status)
QQuickShaderEffect(QQuickItem *parent = nullptr);
+ ~QQuickShaderEffect() override;
QByteArray fragmentShader() const;
void setFragmentShader(const QByteArray &code);
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 9583ef4231..30f6350a30 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -868,6 +868,9 @@ void QQuickTableViewPrivate::syncLoadedTableRectFromLoadedTable()
void QQuickTableViewPrivate::forceLayout()
{
+ if (loadedItems.isEmpty())
+ return;
+
clearEdgeSizeCache();
RebuildOptions rebuildOptions = RebuildOption::LayoutOnly;
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index caef24293a..ac8093e10b 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -1403,7 +1403,7 @@ QVariant QQuickTextControl::inputMethodQuery(Qt::InputMethodQuery property, QVar
case Qt::ImAnchorPosition:
return QVariant(d->cursor.anchor() - block.position());
case Qt::ImAbsolutePosition:
- return QVariant(d->cursor.anchor());
+ return QVariant(d->cursor.position());
case Qt::ImTextAfterCursor:
{
int maxLength = argument.isValid() ? argument.toInt() : 1024;
diff --git a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp
index c434563c90..d8efda1ecc 100644
--- a/src/quick/scenegraph/qsgbasicinternalimagenode.cpp
+++ b/src/quick/scenegraph/qsgbasicinternalimagenode.cpp
@@ -258,7 +258,7 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect,
xs[1].tx = innerSourceRect.left();
xs += 2;
}
- if (innerTargetRect.width() != 0) {
+ if (innerTargetRect.width() != 0 && hTiles > 0) {
xs[0].x = innerTargetRect.left();
xs[0].tx = innerSourceRect.x() + (subSourceRect.left() - floorLeft) * innerSourceRect.width();
++xs;
@@ -299,7 +299,7 @@ QSGGeometry *QSGBasicInternalImageNode::updateGeometry(const QRectF &targetRect,
ys[1].ty = innerSourceRect.top();
ys += 2;
}
- if (innerTargetRect.height() != 0) {
+ if (innerTargetRect.height() != 0 && vTiles > 0) {
ys[0].y = innerTargetRect.top();
ys[0].ty = innerSourceRect.y() + (subSourceRect.top() - floorTop) * innerSourceRect.height();
++ys;
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index c18ba4226c..232ef77324 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -770,12 +770,15 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop()
QSGThreadedRenderLoop::~QSGThreadedRenderLoop()
{
+ qDeleteAll(pendingRenderContexts);
delete sg;
}
QSGRenderContext *QSGThreadedRenderLoop::createRenderContext(QSGContext *sg) const
{
- return sg->createRenderContext();
+ auto context = sg->createRenderContext();
+ pendingRenderContexts.insert(context);
+ return context;
}
void QSGThreadedRenderLoop::maybePostPolishRequest(Window *w)
@@ -935,7 +938,10 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
Window win;
win.window = window;
win.actualWindowFormat = window->format();
- win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
+ auto renderContext = QQuickWindowPrivate::get(window)->context;
+ // The thread assumes ownership, so we don't need to delete it later.
+ pendingRenderContexts.remove(renderContext);
+ win.thread = new QSGRenderThread(this, renderContext);
win.updateDuringSync = false;
win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt
m_windows << win;
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index 32bfcb7148..b8fae8e8da 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -124,6 +124,9 @@ private:
QSGContext *sg;
+ // Set of contexts that have been created but are now owned by
+ // a rendering thread yet, as the window has never been exposed.
+ mutable QSet<QSGRenderContext*> pendingRenderContexts;
QAnimationDriver *m_animation_driver;
QList<Window> m_windows;
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 6970553fc6..e96f71a551 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -1314,9 +1314,13 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
void QQuickWidget::showEvent(QShowEvent *)
{
Q_D(QQuickWidget);
+ bool shouldTriggerUpdate = true;
+
if (!d->useSoftwareRenderer) {
d->createContext();
+
if (d->offscreenWindow->openglContext()) {
+ shouldTriggerUpdate = false;
d->render(true);
// render() may have led to a QQuickWindow::update() call (for
// example, having a scene with a QQuickFramebufferObject::Renderer
@@ -1329,11 +1333,12 @@ void QQuickWidget::showEvent(QShowEvent *)
d->updatePending = false;
update();
}
- } else {
- triggerUpdate();
}
}
+ if (shouldTriggerUpdate)
+ triggerUpdate();
+
// note offscreenWindow is "QQuickOffScreenWindow" instance
d->offscreenWindow->setVisible(true);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
index c7f8ec1118..f08f3c1da7 100644
--- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
+++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
@@ -322,7 +322,7 @@ void tst_QQmlPreview::zoom()
for (auto testZoomFactor : {2.0f, 1.5f, 0.5f}) {
m_client->triggerZoom(testZoomFactor);
- verifyZoomFactor(m_process, baseZoomFactor * testZoomFactor);
+ verifyZoomFactor(m_process, testZoomFactor);
}
m_client->triggerZoom(-1.0f);
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 0e0d70845b..4c04afe886 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -712,8 +712,6 @@ language/statements/generators/yield-identifier-non-strict.js sloppyFails
language/statements/let/block-local-closure-set-before-initialization.js fails
language/statements/let/function-local-closure-set-before-initialization.js fails
language/statements/let/global-closure-set-before-initialization.js fails
-language/statements/throw/S12.13_A2_T6.js strictFails
-language/statements/try/S12.14_A18_T6.js strictFails
language/statements/try/scope-catch-block-lex-open.js fails
language/statements/variable/binding-resolution.js sloppyFails
language/statements/with/unscopables-inc-dec.js sloppyFails
diff --git a/tests/auto/qml/qqmlapplicationengine/data/i18n/qml.qm b/tests/auto/qml/qqmlapplicationengine/data/i18n/qml.qm
new file mode 100644
index 0000000000..8e3c4967c2
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/data/i18n/qml.qm
Binary files differ
diff --git a/tests/auto/qml/qqmlapplicationengine/data/i18n/qml.ts b/tests/auto/qml/qqmlapplicationengine/data/i18n/qml.ts
new file mode 100644
index 0000000000..51a204be3e
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/data/i18n/qml.ts
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="" sourcelanguage="en">
+<context>
+ <name>loadTranslation</name>
+ <message>
+ <source>translate it</source>
+ <translation>translated</translation>
+ </message>
+</context>
+</TS>
diff --git a/tests/auto/qml/qqmlapplicationengine/data/loadTranslation.qml b/tests/auto/qml/qqmlapplicationengine/data/loadTranslation.qml
new file mode 100644
index 0000000000..bba4cab8d6
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/data/loadTranslation.qml
@@ -0,0 +1,5 @@
+import QtQml 2.0
+
+QtObject {
+ property string translation: qsTr('translate it')
+}
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
index ce654dc45e..a9c28a0911 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
@@ -50,6 +50,9 @@ private slots:
void application();
void applicationProperties();
void removeObjectsWhenDestroyed();
+ void loadTranslation_data();
+ void loadTranslation();
+
private:
QString buildDir;
QString srcDir;
@@ -241,6 +244,30 @@ void tst_qqmlapplicationengine::removeObjectsWhenDestroyed()
QCOMPARE(test->rootObjects().size(), 0);
}
+void tst_qqmlapplicationengine::loadTranslation_data()
+{
+ QTest::addColumn<QUrl>("qmlUrl");
+ QTest::addColumn<QString>("translation");
+
+ QTest::newRow("local file") << testFileUrl("loadTranslation.qml")
+ << QStringLiteral("translated");
+ QTest::newRow("qrc") << QUrl(QLatin1String("qrc:///data/loadTranslation.qml"))
+ << QStringLiteral("translated");
+}
+
+void tst_qqmlapplicationengine::loadTranslation()
+{
+ QFETCH(QUrl, qmlUrl);
+ QFETCH(QString, translation);
+
+ QQmlApplicationEngine test(qmlUrl);
+ QVERIFY(!test.rootObjects().isEmpty());
+
+ QObject *rootObject = test.rootObjects().first();
+ QVERIFY(rootObject);
+
+ QCOMPARE(rootObject->property("translation").toString(), translation);
+}
QTEST_MAIN(tst_qqmlapplicationengine)
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.pro b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.pro
index 18c38a80b6..88d07f2b62 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.pro
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.pro
@@ -5,6 +5,9 @@ macx:CONFIG -= app_bundle
SOURCES += tst_qqmlapplicationengine.cpp
TESTDATA += data/*
+RESOURCES += tst_qqmlapplicationengine.qrc
include (../../shared/util.pri)
QT += core-private gui-private qml-private network testlib
+
+TRANSLATIONS = data/i18n/qml_ja.ts
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.qrc b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.qrc
new file mode 100644
index 0000000000..de79d665a3
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>data/loadTranslation.qml</file>
+ <file>data/i18n/qml.qm</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml b/tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml
new file mode 100644
index 0000000000..3166ab647d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/SingletonLookupTest.qml
@@ -0,0 +1,14 @@
+import QtQml 2.0
+import Test.Singletons 1.0
+
+QtObject {
+ property Component singletonAccessor : Component {
+ QtObject {
+ property var singletonHolder;
+ property int result: singletonHolder.testVar
+ }
+ }
+
+ property int firstLookup: singletonAccessor.createObject(this, { singletonHolder: CppSingleton1 }).result;
+ property int secondLookup: singletonAccessor.createObject(this, { singletonHolder: CppSingleton2 }).result;
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 5ae9a6b038..5b73ffbe1d 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -369,6 +369,7 @@ private slots:
void intMinDividedByMinusOne();
void undefinedPropertiesInObjectWrapper();
void hugeRegexpQuantifiers();
+ void singletonTypeWrapperLookup();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -9007,6 +9008,55 @@ void tst_qqmlecmascript::hugeRegexpQuantifiers()
QVERIFY(value.isRegExp());
}
+struct CppSingleton1 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int testVar MEMBER testVar CONSTANT)
+public:
+ const int testVar = 0;
+};
+
+struct CppSingleton2 : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int testVar MEMBER testVar CONSTANT)
+public:
+ const int testVar = 1;
+};
+
+void tst_qqmlecmascript::singletonTypeWrapperLookup()
+{
+ QQmlEngine engine;
+
+ auto singletonTypeId1 = qmlRegisterSingletonType<CppSingleton1>("Test.Singletons", 1, 0, "CppSingleton1",
+ [](QQmlEngine *, QJSEngine *) -> QObject * {
+ return new CppSingleton1;
+ });
+
+ auto singletonTypeId2 = qmlRegisterSingletonType<CppSingleton2>("Test.Singletons", 1, 0, "CppSingleton2",
+ [](QQmlEngine *, QJSEngine *) -> QObject * {
+ return new CppSingleton2;
+ });
+
+ auto cleanup = qScopeGuard([&]() {
+ QQmlMetaType::unregisterType(singletonTypeId1);
+ QQmlMetaType::unregisterType(singletonTypeId2);
+ });
+
+ QQmlComponent component(&engine, testFileUrl("SingletonLookupTest.qml"));
+ QScopedPointer<QObject> test(component.create());
+ QVERIFY2(!test.isNull(), qPrintable(component.errorString()));
+
+ auto singleton1 = engine.singletonInstance<CppSingleton1*>(singletonTypeId1);
+ QVERIFY(singleton1);
+
+ auto singleton2 = engine.singletonInstance<CppSingleton2*>(singletonTypeId2);
+ QVERIFY(singleton2);
+
+ QCOMPARE(test->property("firstLookup").toInt(), singleton1->testVar);
+ QCOMPARE(test->property("secondLookup").toInt(), singleton2->testVar);
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index fead8c4ebc..f16e96a385 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -54,6 +54,7 @@ private slots:
void noSubstitutionTemplateLiteral();
void templateLiteral();
void leadingSemicolonInClass();
+ void templatedReadonlyProperty();
private:
QStringList excludedDirs;
@@ -289,6 +290,15 @@ void tst_qqmlparser::leadingSemicolonInClass()
QVERIFY(parser.parseProgram());
}
+void tst_qqmlparser::templatedReadonlyProperty()
+{
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ lexer.setCode(QLatin1String("A { readonly property list<B> listfoo: [ C{} ] }"), 1);
+ QQmlJS::Parser parser(&engine);
+ QVERIFY(parser.parse());
+}
+
QTEST_MAIN(tst_qqmlparser)
#include "tst_qqmlparser.moc"
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index a1b2b64ae2..9f7ede44cf 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -1491,11 +1491,11 @@ void tst_QQuickPathView::undefinedPath()
// QPainterPath warnings are only received if QT_NO_DEBUG is not defined
if (QLibraryInfo::isDebugBuild()) {
- QString warning1("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
- QTest::ignoreMessage(QtWarningMsg,qPrintable(warning1));
+ QRegularExpression warning1("^QPainterPath::moveTo:.*ignoring call$");
+ QTest::ignoreMessage(QtWarningMsg, warning1);
- QString warning2("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
- QTest::ignoreMessage(QtWarningMsg,qPrintable(warning2));
+ QRegularExpression warning2("^QPainterPath::lineTo:.*ignoring call$");
+ QTest::ignoreMessage(QtWarningMsg, warning2);
}
QQmlComponent c(&engine, testFileUrl("undefinedpath.qml"));
diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
index 063358c795..b4abdd6fe2 100644
--- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp
+++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
@@ -564,7 +564,10 @@ bool tst_SceneGraph::isRunningOnOpenGL()
bool retval = false;
QQuickView dummy;
dummy.show();
- QTest::qWaitForWindowExposed(&dummy);
+ if (!QTest::qWaitForWindowExposed(&dummy)) {
+ [](){ QFAIL("Could not show a QQuickView"); }();
+ return false;
+ }
if (dummy.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL)
retval = true;
dummy.hide();
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index fd5c3653ad..691dfd1bc6 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -449,9 +449,6 @@ void tst_qquickwidget::reparentToNewWindow()
qqw->setParent(&window2);
qqw->show();
- if (QGuiApplication::platformName() == QLatin1String("offscreen"))
- QEXPECT_FAIL("", "afterRendering not emitted after reparenting on offscreen", Continue);
-
QTRY_VERIFY(afterRenderingSpy.size() > 0);
QImage img = qqw->grabFramebuffer();