aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-09-05 08:58:55 +0200
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2019-09-05 08:58:55 +0200
commit7d96bae85e30f1897ff7a56ecb44196a6df77eb6 (patch)
tree7c6fd968ae55f93f7bd0889e132e1b8fc2b14f04
parent4ba86a97011dda2d8792ee23f0e86015715a592e (diff)
parentf862b3edeb8a96a49a5d12620506d33d5a5aadca (diff)
Merge remote-tracking branch 'origin/5.14' into 5.15
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp20
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp7
-rw-r--r--src/qml/parser/qqmljs.g19
-rw-r--r--src/qml/parser/qqmljsast.cpp73
-rw-r--r--src/qml/qml/qml.pri2
-rw-r--r--src/qml/qml/qqmlimport.cpp10
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp73
-rw-r--r--src/qml/qml/qqmltype.cpp17
-rw-r--r--src/qml/qml/qqmltype_p.h1
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp51
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h3
-rw-r--r--src/qml/types/qqmlbind.cpp2
-rw-r--r--src/qml/types/qqmlconnections.cpp3
-rw-r--r--src/quick/doc/snippets/cmake-macros/examples.cmake6
-rw-r--r--src/quick/doc/src/cmake-macros.qdoc56
-rw-r--r--src/quick/handlers/qquickdraghandler_p.h4
-rw-r--r--src/quick/items/qquickframebufferobject.cpp4
-rw-r--r--src/quick/items/qquickframebufferobject.h3
-rw-r--r--src/quick/items/qquickimage.cpp5
-rw-r--r--src/quick/items/qquickitemsmodule.cpp3
-rw-r--r--src/quick/items/qquickwindow.cpp116
-rw-r--r--src/quick/items/qquickwindow.h10
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.cpp38
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture_p.h3
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp4
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/qsgrhisupport.cpp13
-rw-r--r--src/quick/scenegraph/qsgrhisupport_p.h2
-rw-r--r--src/quick/scenegraph/scenegraph.pri2
-rw-r--r--src/quick/scenegraph/shaders_ng/visualization.vert4
-rw-r--r--src/quick/scenegraph/shaders_ng/visualization.vert.qsbbin2030 -> 2099 bytes
-rw-r--r--src/quick/scenegraph/util/qsgengine.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgengine.h2
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture.cpp19
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture_p.h4
-rw-r--r--src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp104
-rw-r--r--src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h70
-rw-r--r--src/quick/util/qquickpath.cpp118
-rw-r--r--src/quick/util/qquickpath_p.h12
-rw-r--r--src/src.pro7
-rw-r--r--tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml10
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp11
-rw-r--r--tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt1
-rw-r--r--tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp1
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h13
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp3
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp11
-rw-r--r--tests/auto/quick/qquickshape/data/multiline.pngbin0 -> 1244 bytes
-rw-r--r--tests/auto/quick/qquickshape/data/multiline.qml52
-rw-r--r--tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml59
-rw-r--r--tests/auto/quick/qquickshape/data/polyline.pngbin0 -> 757 bytes
-rw-r--r--tests/auto/quick/qquickshape/data/polyline.qml52
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp334
59 files changed, 1237 insertions, 221 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index d0f9833c2e..be83f63bfc 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -191,22 +191,18 @@ QQmlEngineDebugServiceImpl::propertyData(QObject *obj, int propIdx)
if (binding)
rv.binding = binding->expression();
- if (QQmlValueTypeFactory::isValueType(prop.userType())) {
- rv.type = QQmlObjectProperty::Basic;
- } else if (QQmlMetaType::isQObject(prop.userType())) {
+ rv.value = valueContents(prop.read(obj));
+
+ if (QQmlMetaType::isQObject(prop.userType())) {
rv.type = QQmlObjectProperty::Object;
} else if (QQmlMetaType::isList(prop.userType())) {
rv.type = QQmlObjectProperty::List;
} else if (prop.userType() == QMetaType::QVariant) {
rv.type = QQmlObjectProperty::Variant;
+ } else if (rv.value.isValid()) {
+ rv.type = QQmlObjectProperty::Basic;
}
- QVariant value;
- if (rv.type != QQmlObjectProperty::Unknown && prop.userType() != 0) {
- value = prop.read(obj);
- }
- rv.value = valueContents(value);
-
return rv;
}
@@ -269,10 +265,10 @@ QVariant QQmlEngineDebugServiceImpl::valueContents(QVariant value) const
return s;
}
}
-
- if (isSaveable(value))
- return value;
}
+
+ if (isSaveable(value))
+ return value;
}
if (QQmlMetaType::isQObject(userType)) {
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
index 86571e6cbe..8caa5ac23e 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp
@@ -109,12 +109,7 @@ QQmlWatchProxy::QQmlWatchProxy(int id,
void QQmlWatchProxy::notifyValueChanged()
{
- QVariant v;
- if (m_expr)
- v = m_expr->evaluate();
- else if (QQmlValueTypeFactory::isValueType(m_property.userType()))
- v = m_property.read(m_object);
-
+ const QVariant v = m_expr ? m_expr->evaluate() : m_property.read(m_object);
emit m_watch->propertyChanged(m_id, m_debugId, m_property, v);
}
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 6efe19eb21..28dbb53ff5 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -1248,8 +1248,13 @@ UiObjectMember: T_DEFAULT T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlId
sym(1).Node = node;
} break;
./
+OptionalSemicolon: | Semicolon;
+/.
+/* we need OptionalSemicolon because UiScriptStatement might already parse the last semicolon
+ and then we would miss a semicolon (see tests/auto/quick/qquickvisualdatamodel/data/objectlist.qml)*/
+ ./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3), sym(5).Statement);
@@ -1261,7 +1266,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatemen
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
@@ -1275,7 +1280,7 @@ UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScr
} break;
./
-UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScriptStatement OptionalSemicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4), sym(6).Statement);
@@ -1289,7 +1294,7 @@ UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType QmlIdentifier T_COLON UiScri
} break;
./
-UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(4).UiQualifiedId->finish(), stringRef(6));
@@ -1315,7 +1320,7 @@ 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;
+UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(5).UiQualifiedId->finish(), stringRef(7));
@@ -1343,7 +1348,7 @@ UiObjectMember: T_READONLY T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT QmlI
} break;
./
-UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
+UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(2).UiQualifiedId->finish(), stringRef(3));
@@ -1366,7 +1371,7 @@ UiObjectMember: T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatem
} break;
./
-UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer;
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType QmlIdentifier T_COLON ExpressionStatementLookahead UiQualifiedId UiObjectInitializer Semicolon;
/.
case $rule_number: {
AST::UiPublicMember *node = new (pool) AST::UiPublicMember(sym(3).UiQualifiedId->finish(), stringRef(4));
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 700c191499..b63b2191b9 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -238,12 +238,11 @@ void StringLiteral::accept0(Visitor *visitor)
void TemplateLiteral::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (TemplateLiteral *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void NumericLiteral::accept0(Visitor *visitor)
@@ -1015,13 +1014,13 @@ BoundNames FormalParameterList::boundNames() const
void FormalParameterList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(element, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (FormalParameterList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->element, visitor);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
FormalParameterList *FormalParameterList::finish(QQmlJS::MemoryPool *pool)
@@ -1321,12 +1320,14 @@ void UiPragma::accept0(Visitor *visitor)
void UiHeaderItemList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(headerItem, visitor);
- accept(next, visitor);
- }
+ bool accepted = true;
+ for (UiHeaderItemList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->headerItem, visitor);
- visitor->endVisit(this);
+ visitor->endVisit(it);
+ }
}
@@ -1391,14 +1392,15 @@ void PatternElement::boundNames(BoundNames *names)
void PatternElementList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(elision, visitor);
- accept(element, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (PatternElementList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted) {
+ accept(it->elision, visitor);
+ accept(it->element, visitor);
+ }
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void PatternElementList::boundNames(BoundNames *names)
@@ -1428,13 +1430,13 @@ void PatternProperty::boundNames(BoundNames *names)
void PatternPropertyList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(property, visitor);
- if (next)
- accept(next, visitor);
+ bool accepted = true;
+ for (PatternPropertyList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->property, visitor);
+ visitor->endVisit(it);
}
-
- visitor->endVisit(this);
}
void PatternPropertyList::boundNames(BoundNames *names)
@@ -1479,13 +1481,14 @@ void ClassDeclaration::accept0(Visitor *visitor)
void ClassElementList::accept0(Visitor *visitor)
{
- if (visitor->visit(this)) {
- accept(property, visitor);
- if (next)
- accept(next, visitor);
- }
+ bool accepted = true;
+ for (ClassElementList *it = this; it && accepted; it = it->next) {
+ accepted = visitor->visit(it);
+ if (accepted)
+ accept(it->property, visitor);
- visitor->endVisit(this);
+ visitor->endVisit(it);
+ }
}
ClassElementList *ClassElementList::finish()
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 08591b5237..2e9c6f3de6 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -186,5 +186,7 @@ qtConfig(qml-network) {
$$PWD/qqmltypeloadernetworkreplyproxy.cpp
}
+android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"'
+
include(ftw/ftw.pri)
include(v8/v8.pri)
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 7c9c0da01a..31a7004407 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1852,9 +1852,15 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
QLatin1String(".so"),
QLatin1String(".bundle")
};
-# else // Unix
+#else // Unix
static const QString prefix = QLatin1String("lib");
- static const QStringList suffixes = { QLatin1String(".so") };
+ static const QStringList suffixes = {
+# if defined(Q_OS_ANDROID)
+ QStringLiteral(LIBS_SUFFIX),
+# endif
+ QLatin1String(".so")
+
+ };
#endif
return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix);
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 71964aca64..6959b05105 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -49,6 +49,19 @@
QT_BEGIN_NAMESPACE
+static bool isPrimitiveType(int typeId)
+{
+ switch (typeId) {
+#define HANDLE_PRIMITIVE(Type, id, T) \
+ case QMetaType::Type:
+QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(HANDLE_PRIMITIVE);
+#undef HANDLE_PRIMITIVE
+ return true;
+ default:
+ return false;
+ }
+}
+
QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
: enginePrivate(enginePrivate)
, compilationUnit(compilationUnit)
@@ -281,11 +294,21 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
return recordError(binding->location, tr("Invalid grouped property access"));
}
} else {
- if (!enginePrivate->propertyCacheForType(pd->propType())) {
+ const int typeId = pd->propType();
+ if (isPrimitiveType(typeId)) {
+ return recordError(
+ binding->location,
+ tr("Invalid grouped property access: Property \"%1\" with primitive type \"%2\".")
+ .arg(name)
+ .arg(QString::fromLatin1(QMetaType::typeName(typeId)))
+ );
+ }
+
+ if (!enginePrivate->propertyCacheForType(typeId)) {
return recordError(binding->location,
tr("Invalid grouped property access: Property \"%1\" with type \"%2\", which is not a value type")
.arg(name)
- .arg(QString::fromLatin1(QMetaType::typeName(pd->propType())))
+ .arg(QString::fromLatin1(QMetaType::typeName(typeId)))
);
}
}
@@ -679,15 +702,21 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
return noError;
}
- if (QQmlMetaType::isInterface(property->propType())) {
+ const int propType = property->propType();
+ const auto rhsType = [&]() {
+ return stringAt(compilationUnit->objectAt(binding->value.objectIndex)
+ ->inheritedTypeNameIndex);
+ };
+
+ if (QQmlMetaType::isInterface(propType)) {
// Can only check at instantiation time if the created sub-object successfully casts to the
// target interface.
return noError;
- } else if (property->propType() == QMetaType::QVariant || property->propType() == qMetaTypeId<QJSValue>()) {
+ } else if (propType == QMetaType::QVariant || propType == qMetaTypeId<QJSValue>()) {
// We can convert everything to QVariant :)
return noError;
} else if (property->isQList()) {
- const int listType = enginePrivate->listType(property->propType());
+ const int listType = enginePrivate->listType(propType);
if (!QQmlMetaType::isInterface(listType)) {
QQmlPropertyCache *source = propertyCaches.at(binding->value.objectIndex);
if (!canCoerce(listType, source)) {
@@ -697,35 +726,43 @@ QQmlJS::DiagnosticMessage QQmlPropertyValidator::validateObjectBinding(QQmlPrope
return noError;
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
return noError;
- } else if (QQmlValueTypeFactory::isValueType(property->propType())) {
- auto typeName = QMetaType::typeName(property->propType());
+ } else if (isPrimitiveType(propType)) {
+ auto typeName = QMetaType::typeName(propType);
+ return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting \"%3\"")
+ .arg(rhsType())
+ .arg(propertyName)
+ .arg(typeName));
+ } else if (QQmlValueTypeFactory::isValueType(propType)) {
return qQmlCompileError(binding->location, tr("Can not assign value of type \"%1\" to property \"%2\", expecting an object")
- .arg(typeName ? QString::fromLatin1(typeName) : QString::fromLatin1("<unknown type>"))
- .arg(propertyName));
- } else if (property->propType() == qMetaTypeId<QQmlScriptString>()) {
+ .arg(rhsType()).arg(propertyName));
+ } else if (propType == qMetaTypeId<QQmlScriptString>()) {
return qQmlCompileError(binding->valueLocation, tr("Invalid property assignment: script expected"));
} else {
// We want to use the raw metaObject here as the raw metaobject is the
// actual property type before we applied any extensions that might
// effect the properties on the type, but don't effect assignability
// Using -1 for the minor version ensures that we get the raw metaObject.
- QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(property->propType(), -1);
+ QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(propType, -1);
- // Will be true if the assigned type inherits propertyMetaObject
- bool isAssignable = false;
- // Determine isAssignable value
if (propertyMetaObject) {
+ // Will be true if the assigned type inherits propertyMetaObject
+ // Determine isAssignable value
+ bool isAssignable = false;
QQmlPropertyCache *c = propertyCaches.at(binding->value.objectIndex);
while (c && !isAssignable) {
isAssignable |= c == propertyMetaObject;
c = c->parent();
}
- }
- if (!isAssignable) {
- return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
- .arg(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex)).arg(QLatin1String(QMetaType::typeName(property->propType()))));
+ if (!isAssignable) {
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign object of type \"%1\" to property of type \"%2\" as the former is neither the same as the latter nor a sub-class of it.")
+ .arg(rhsType()).arg(QLatin1String(QMetaType::typeName(propType))));
+ }
+ } else {
+ return qQmlCompileError(binding->valueLocation, tr("Cannot assign to property of unknown type \"%1\".")
+ .arg(QLatin1String(QMetaType::typeName(propType))));
}
+
}
return noError;
}
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 2a6831d898..252ff26a64 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -154,23 +154,6 @@ bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, in
return module == d->module && vmajor == d->version_maj && vminor >= d->version_min;
}
-// returns the nearest _registered_ super class
-QQmlType QQmlType::superType() const
-{
- if (!d)
- return QQmlType();
- if (!d->haveSuperType && d->baseMetaObject) {
- const QMetaObject *mo = d->baseMetaObject->superClass();
- while (mo && !d->superType.isValid()) {
- d->superType = QQmlMetaType::qmlType(mo, d->module, d->version_maj, d->version_min);
- mo = mo->superClass();
- }
- d->haveSuperType = true;
- }
-
- return d->superType;
-}
-
QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
{
Q_ASSERT(isComposite());
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
index 158fefad2c..4dec20600b 100644
--- a/src/qml/qml/qqmltype_p.h
+++ b/src/qml/qml/qqmltype_p.h
@@ -182,7 +182,6 @@ public:
};
private:
- QQmlType superType() const;
QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const;
QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const;
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index 88f7b69dc2..a4737b3da9 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -65,11 +65,13 @@ struct QQmlValueTypeFactoryImpl
QQmlValueType *valueTypes[QVariant::UserType];
QHash<int, QQmlValueType *> userTypes;
QMutex mutex;
+
+ QQmlValueType invalidValueType;
};
QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
{
- std::fill_n(valueTypes, int(QVariant::UserType), nullptr);
+ std::fill_n(valueTypes, int(QVariant::UserType), &invalidValueType);
#if QT_CONFIG(qml_itemmodel)
// See types wrapped in qqmlmodelindexvaluetype_p.h
@@ -79,20 +81,18 @@ QQmlValueTypeFactoryImpl::QQmlValueTypeFactoryImpl()
QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl()
{
- qDeleteAll(valueTypes, valueTypes + QVariant::UserType);
+ for (QQmlValueType *type : valueTypes) {
+ if (type != &invalidValueType)
+ delete type;
+ }
qDeleteAll(userTypes);
}
-bool QQmlValueTypeFactoryImpl::isValueType(int idx)
+bool isInternalType(int idx)
{
- if (idx >= QMetaType::User)
- return valueType(idx) != nullptr;
-
- if (idx < 0)
- return false;
-
// Qt internal types
switch (idx) {
+ case QMetaType::UnknownType:
case QMetaType::QStringList:
case QMetaType::QObjectStar:
case QMetaType::VoidStar:
@@ -101,12 +101,20 @@ bool QQmlValueTypeFactoryImpl::isValueType(int idx)
case QMetaType::QLocale:
case QMetaType::QImage: // scarce type, keep as QVariant
case QMetaType::QPixmap: // scarce type, keep as QVariant
- return false;
- default:
return true;
+ default:
+ return false;
}
}
+bool QQmlValueTypeFactoryImpl::isValueType(int idx)
+{
+ if (idx < 0 || isInternalType(idx))
+ return false;
+
+ return valueType(idx) != nullptr;
+}
+
const QMetaObject *QQmlValueTypeFactoryImpl::metaObjectForMetaType(int t)
{
switch (t) {
@@ -166,15 +174,17 @@ QQmlValueType *QQmlValueTypeFactoryImpl::valueType(int idx)
}
QQmlValueType *rv = valueTypes[idx];
- if (!rv) {
+ if (rv == &invalidValueType) {
// No need for mutex protection - the most we can lose is a valueType instance
// TODO: Investigate the performance/memory characteristics of
// removing the preallocated array
- if (const QMetaObject *mo = metaObjectForMetaType(idx)) {
- rv = new QQmlValueType(idx, mo);
- valueTypes[idx] = rv;
- }
+ if (isInternalType(idx))
+ rv = valueTypes[idx] = nullptr;
+ else if (const QMetaObject *mo = metaObjectForMetaType(idx))
+ rv = valueTypes[idx] = new QQmlValueType(idx, mo);
+ else
+ rv = valueTypes[idx] = nullptr;
}
return rv;
@@ -204,6 +214,13 @@ void QQmlValueTypeFactory::registerValueTypes(const char *uri, int versionMajor,
qmlRegisterValueTypeEnums<QQmlEasingValueType>(uri, versionMajor, versionMinor, "Easing");
}
+QQmlValueType::QQmlValueType() :
+ _metaObject(nullptr),
+ gadgetPtr(nullptr),
+ metaType(QMetaType::UnknownType)
+{
+}
+
QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
: gadgetPtr(QMetaType::create(typeId))
, metaType(typeId)
@@ -221,7 +238,7 @@ QQmlValueType::QQmlValueType(int typeId, const QMetaObject *gadgetMetaObject)
QQmlValueType::~QQmlValueType()
{
QObjectPrivate *op = QObjectPrivate::get(this);
- Q_ASSERT(op->metaObject == this);
+ Q_ASSERT(op->metaObject == nullptr || op->metaObject == this);
op->metaObject = nullptr;
::free(const_cast<QMetaObject *>(_metaObject));
metaType.destroy(gadgetPtr);
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 89f1b71d61..cf53b8cb4a 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -66,6 +66,7 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlValueType : public QObject, public QAbstractDynamicMetaObject
{
public:
+ QQmlValueType();
QQmlValueType(int userType, const QMetaObject *metaObject);
~QQmlValueType() override;
void read(QObject *, int);
@@ -90,7 +91,7 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlValueTypeFactory
{
public:
- static bool isValueType(int);
+ static bool isValueType(int idx);
static QQmlValueType *valueType(int idx);
static const QMetaObject *metaObjectForMetaType(int type);
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 4b60108597..861243987f 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -357,7 +357,7 @@ void QQmlBind::setDelayed(bool delayed)
\li Binding.RestoreValue The original value is restored if it was a plain
value rather than a binding.
\li Binding.RestoreBindingOrValue The original value is always restored.
- \list
+ \endlist
The default value is Binding.RestoreBinding.
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 25f95d6c93..1e801641e5 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -327,7 +327,8 @@ void QQmlConnections::connectSignalsToMethods()
signal->takeExpression(expression);
d->boundsignals += signal;
- } else if (!d->ignoreUnknownSignals && propName.startsWith("on") && propName.length() > 2
+ } else if (!d->ignoreUnknownSignals
+ && propName.startsWith(QLatin1String("on")) && propName.length() > 2
&& propName.at(2).isUpper()) {
qmlWarning(this) << tr("Detected function \"%1\" in Connections element. "
"This is probably intended to be a signal handler but no "
diff --git a/src/quick/doc/snippets/cmake-macros/examples.cmake b/src/quick/doc/snippets/cmake-macros/examples.cmake
new file mode 100644
index 0000000000..8ca6180f9b
--- /dev/null
+++ b/src/quick/doc/snippets/cmake-macros/examples.cmake
@@ -0,0 +1,6 @@
+#! [qt5_import_qml_plugins]
+find_package(Qt5 COMPONENTS Quick QmlImportScanner)
+add_executable(myapp main.cpp)
+target_link_libraries(myapp Qt5::Quick)
+qt5_import_qml_plugins(myapp)
+#! [qt5_import_plugins]
diff --git a/src/quick/doc/src/cmake-macros.qdoc b/src/quick/doc/src/cmake-macros.qdoc
new file mode 100644
index 0000000000..b643a9e4e4
--- /dev/null
+++ b/src/quick/doc/src/cmake-macros.qdoc
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtqml-cmake-qt5-import-qml-plugins.html
+\ingroup cmake-macros-qtqml
+
+\title qt5_import_qml_plugins
+
+\brief Scans \c{.qml} files and imports required QML static plugins
+
+\section1 Overview
+
+\badcode
+find_package(Qt5QmlImportScanner REQUIRED)
+qt5_import_qml_plugins(<TARGET>)
+\endcode
+
+\section1 Description
+
+Runs \c{qmlimportscanner} at configure time to find the static QML plugins
+used and links them to the given target.
+
+\note When used with a non-static Qt build, this function does nothing.
+
+This CMake command was introduced in Qt 5.14.
+
+\section1 Example
+
+\snippet cmake-macros/examples.cmake qt5_import_qml_plugins
+
+*/
diff --git a/src/quick/handlers/qquickdraghandler_p.h b/src/quick/handlers/qquickdraghandler_p.h
index 18c1fd841d..e8f47163ed 100644
--- a/src/quick/handlers/qquickdraghandler_p.h
+++ b/src/quick/handlers/qquickdraghandler_p.h
@@ -62,7 +62,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickDragHandler : public QQuickMultiPointHandler
Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT)
Q_PROPERTY(QQuickDragAxis * yAxis READ yAxis CONSTANT)
Q_PROPERTY(QVector2D translation READ translation NOTIFY translationChanged)
- Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged)
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged REVISION 14)
public:
enum SnapMode {
@@ -89,7 +89,7 @@ public:
Q_SIGNALS:
void translationChanged();
- void snapModeChanged();
+ Q_REVISION(14) void snapModeChanged();
protected:
void onActiveChanged() override;
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 48f8b8db5c..190bc6853c 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -109,6 +109,10 @@ public:
* and can be used directly in \l {ShaderEffect}{ShaderEffects} and other
* classes that consume texture providers.
*
+ * \warning This class is only suitable when working directly with OpenGL. It
+ * is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering
+ * path}.
+ *
* \sa {Scene Graph - Rendering FBOs}, {Scene Graph and Rendering}
*/
diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h
index d66ca40b3a..db143e48cf 100644
--- a/src/quick/items/qquickframebufferobject.h
+++ b/src/quick/items/qquickframebufferobject.h
@@ -44,11 +44,12 @@
QT_BEGIN_NAMESPACE
-
class QOpenGLFramebufferObject;
class QQuickFramebufferObjectPrivate;
class QSGFramebufferObjectNode;
+// ### Qt 6: To be removed. To be seen if an alternative will need to be introduced.
+
class Q_QUICK_EXPORT QQuickFramebufferObject : public QQuickItem
{
Q_OBJECT
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 87b848b21b..c7e7ccea55 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -687,7 +687,6 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
yOffset = qCeil(height() - pixHeight);
switch (d->fillMode) {
- default:
case Stretch:
targetRect = QRectF(0, 0, width(), height());
sourceRect = d->pix.rect();
@@ -699,7 +698,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
break;
case PreserveAspectCrop: {
- targetRect = QRect(0, 0, width(), height());
+ targetRect = QRectF(0, 0, width(), height());
qreal wscale = width() / qreal(d->pix.width());
qreal hscale = height() / qreal(d->pix.height());
@@ -751,7 +750,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
targetRect = QRectF(x + xOffset, y + yOffset, w, h);
sourceRect = QRectF(x, y, w, h);
break;
- };
+ }
qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 70a8b08822..f2098f6732 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -480,6 +480,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#if QT_CONFIG(quick_itemview)
qmlRegisterUncreatableType<QQuickItemView, 13>(uri, 2, 13, itemViewName, itemViewMessage);
+#endif
+#if QT_CONFIG(quick_pathview)
qmlRegisterType<QQuickPathView, 13>(uri, 2, 13, "PathView");
#endif
#if QT_CONFIG(quick_gridview)
@@ -494,6 +496,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterUncreatableType<QQuickImageBase, 14>(uri, 2, 14, "ImageBase",
QQuickPointerHandler::tr("ImageBase is an abstract base class"));
qmlRegisterType<QQuickImage, 14>(uri, 2, 14, "Image");
+ qmlRegisterType<QQuickDragHandler, 14>(uri, 2, 14, "DragHandler");
}
static void initResources()
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 8b5e2a012a..27e2a4572e 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -4450,7 +4450,8 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
\note This function only has an effect when using the default OpenGL scene graph
adaptation.
- \note This function has no effect when running on the RHI graphics abstraction.
+ \note This function has no effect when running on the RHI graphics
+ abstraction. Use createTextureFromNativeObject() instead.
\sa sceneGraphInitialized(), QSGTexture
*/
@@ -4458,19 +4459,120 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create
{
#if QT_CONFIG(opengl)
Q_D(const QQuickWindow);
- if (!d->rhi && openglContext()) {
- QSGPlainTexture *texture = new QSGPlainTexture();
- texture->setTextureId(id);
+ if (!d->rhi) {
+ if (openglContext()) {
+ QSGPlainTexture *texture = new QSGPlainTexture();
+ texture->setTextureId(id);
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ texture->setOwnsTexture(options & TextureOwnsGLTexture);
+ texture->setTextureSize(size);
+ return texture;
+ }
+ } else {
+ qWarning("createTextureFromId() must not be called when running on the RHI. "
+ "Use createTextureFromNativeObject() instead.");
+ }
+#else
+ Q_UNUSED(id)
+ Q_UNUSED(size)
+ Q_UNUSED(options)
+#endif
+ return nullptr;
+}
+
+/*!
+ \enum QQuickWindow::NativeObjectType
+ \since 5.14
+
+ Specifies the type of the native object passed to functions such as
+ createTextureFromNativeObject().
+
+ \value NativeObjectTexture The native object is a 2D texture (OpenGL,
+ Direct3D 11, Metal) or image (Vulkan).
+ */
+
+/*!
+ Creates a new QSGTexture object from an existing native object.
+
+ The native object is wrapped, but not owned, by the resulting QSGTexture.
+ The caller of the function is responsible for deleting the returned
+ QSGTexture, but that will not destroy the underlying native object.
+
+ \a type specifies the type of the object. In practice the type is
+ NativeObjectTexture, indicating that the native object is a texture or
+ image of the underlying graphics API. Other types may be introduced in the
+ future.
+
+ This function is currently suitable for 2D RGBA textures only.
+
+ Unlike createTextureFromId(), this function supports both direct OpenGL
+ usage and the RHI abstracted rendering path.
+
+ \warning This function will return null if the scenegraph has not yet been
+ initialized.
+
+ Use \a options to customize the texture attributes. Only the
+ TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
+
+ \warning Unlike createTextureFromId(), this function never takes ownership
+ of the native object, and the TextureOwnsGLTexture flag is ignored.
+
+ \a size specifies the size in pixels.
+
+ \a nativeObjectPtr is a pointer to the native object handle. With OpenGL,
+ the native handle is a GLuint value, so \a nativeObjectPtr is then a
+ pointer to a GLuint. With Vulkan, the native handle is a VkImage, so \a
+ nativeObjectPtr is a pointer to a VkImage. With Direct3D 11 and Metal \a
+ nativeObjectPtr is a pointer to a ID3D11Texture2D or MTLTexture pointer.
+
+ \note Pay attention to the fact that \a nativeObjectPtr is always a pointer
+ to the native texture handle type, even if the native type itself is a
+ pointer.
+
+ \a nativeLayout is only used for APIs like Vulkan. When applicable, it must
+ specify the current image layout, such as, a VkImageLayout value.
+
+ \sa sceneGraphInitialized(), QSGTextures
+
+ \since 5.14
+ */
+QSGTexture *QQuickWindow::createTextureFromNativeObject(NativeObjectType type,
+ const void *nativeObjectPtr,
+ int nativeLayout,
+ const QSize &size,
+ CreateTextureOptions options) const
+{
+ if (type != NativeObjectTexture) {
+ qWarning("createTextureFromNativeObject: only textures are supported");
+ return nullptr;
+ }
+
+#if QT_CONFIG(opengl) /* || QT_CONFIG(vulkan) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) */
+ Q_D(const QQuickWindow);
+ if (d->rhi) {
+ QSGPlainTexture *texture = new QSGPlainTexture;
+ texture->setTextureFromNativeObject(d->rhi, type, nativeObjectPtr, nativeLayout,
+ size, options.testFlag(TextureHasMipmaps));
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ // note that the QRhiTexture does not (and cannot) own the native object
+ texture->setOwnsTexture(true); // texture meaning the QRhiTexture here, not the native object
+ texture->setTextureSize(size);
+ return texture;
+ } else if (openglContext()) {
+ QSGPlainTexture *texture = new QSGPlainTexture;
+ texture->setTextureId(*reinterpret_cast<const uint *>(nativeObjectPtr));
texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
texture->setOwnsTexture(options & TextureOwnsGLTexture);
texture->setTextureSize(size);
return texture;
}
#else
- Q_UNUSED(id)
- Q_UNUSED(size)
- Q_UNUSED(options)
+ Q_UNUSED(nativeObjectPtr);
+ Q_UNUSED(nativeLayout);
+ Q_UNUSED(size);
+ Q_UNUSED(options);
#endif
+
return nullptr;
}
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index ab3046611f..9dbff88f0d 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -109,6 +109,11 @@ public:
};
Q_ENUM(TextRenderType)
+ enum NativeObjectType {
+ NativeObjectTexture
+ };
+ Q_ENUM(NativeObjectType)
+
explicit QQuickWindow(QWindow *parent = nullptr);
explicit QQuickWindow(QQuickRenderControl *renderControl);
@@ -153,6 +158,11 @@ public:
QSGTexture *createTextureFromImage(const QImage &image) const;
QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options) const;
QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const;
+ QSGTexture *createTextureFromNativeObject(NativeObjectType type,
+ const void *nativeObjectPtr,
+ int nativeLayout,
+ const QSize &size,
+ CreateTextureOptions options = CreateTextureOption()) const;
void setClearBeforeRendering(bool enabled);
bool clearBeforeRendering() const;
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 2441e14fda..336107a61d 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -3492,7 +3492,7 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms,
}
if (pd->textureBindingTable[binding] && pd->samplerBindingTable[binding]) {
- QRhiTexture *texture = pd->textureBindingTable[binding]->rhiTexture();
+ QRhiTexture *texture = QSGTexturePrivate::get(pd->textureBindingTable[binding])->rhiTexture();
// texture may be null if the update above failed for any reason,
// or if the QSGTexture chose to return null intentionally. This is
// valid and we still need to provide something to the shader.
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.cpp b/src/quick/scenegraph/coreapi/qsgtexture.cpp
index cfd0cb9f06..c47401e5c0 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.cpp
+++ b/src/quick/scenegraph/coreapi/qsgtexture.cpp
@@ -696,27 +696,6 @@ void QSGTexture::updateBindOptions(bool force) // legacy (GL-only)
}
/*!
- \return the QRhiTexture for this QSGTexture or null if there is none.
-
- Unlike textureId(), this function is not expected to create a new
- QRhiTexture in case there is none. Just return null in that case. The
- expectation towards the renderer is that a null texture leads to using a
- transparent, dummy texture instead.
-
- \note This function is only used when running the graphics API independent
- rendering path of the scene graph.
-
- \warning This function can only be called from the rendering thread.
-
- \since 5.14
- */
-QRhiTexture *QSGTexture::rhiTexture() const
-{
- Q_D(const QSGTexture);
- return d->rhiTexture();
-}
-
-/*!
Call this function to enqueue image upload operations to \a
resourceUpdates, in case there are any pending ones. When there is no new
data (for example, because there was no setImage() since the last call to
@@ -762,6 +741,23 @@ int QSGTexturePrivate::comparisonKey() const
return q->textureId(); // this is semantically wrong but at least compatible with existing, non-RHI-aware subclasses
}
+/*!
+ \internal
+
+ \return the QRhiTexture for this QSGTexture or null if there is none.
+
+ Unlike textureId(), this function is not expected to create a new
+ QRhiTexture in case there is none. Just return null in that case. The
+ expectation towards the renderer is that a null texture leads to using a
+ transparent, dummy texture instead.
+
+ \note This function is only used when running the graphics API independent
+ rendering path of the scene graph.
+
+ \warning This function can only be called from the rendering thread.
+
+ \since 5.14
+ */
QRhiTexture *QSGTexturePrivate::rhiTexture() const
{
return nullptr;
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.h b/src/quick/scenegraph/coreapi/qsgtexture.h
index f2b0e902f3..4cd2a5cddd 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.h
+++ b/src/quick/scenegraph/coreapi/qsgtexture.h
@@ -113,7 +113,6 @@ public:
// ### Qt 6: make these virtual
int comparisonKey() const;
- QRhiTexture *rhiTexture() const;
void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates);
// ### Qt 6: make this an argument for removedFromAtlas()
diff --git a/src/quick/scenegraph/coreapi/qsgtexture_p.h b/src/quick/scenegraph/coreapi/qsgtexture_p.h
index 1d248b0305..cb59d32012 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture_p.h
+++ b/src/quick/scenegraph/coreapi/qsgtexture_p.h
@@ -83,9 +83,10 @@ public:
void resetDirtySamplerOptions();
bool hasDirtySamplerOptions() const;
+ virtual QRhiTexture *rhiTexture() const;
+
// ### Qt 6: these should be virtuals in the public class instead
virtual int comparisonKey() const; // ### Qt 6: pure virtual
- virtual QRhiTexture *rhiTexture() const;
virtual void updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates);
QRhiResourceUpdateBatch *workResourceUpdateBatch = nullptr; // ### Qt 6: remove
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index db889c3102..8fc8c711c6 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -451,7 +451,9 @@ bool QSGTextMaskRhiShader::updateUniformData(const RenderState &state,
changed = true;
}
- if (updated || !oldMat || oldMat->texture()->rhiTexture() != mat->texture()->rhiTexture()) {
+ QRhiTexture *oldRtex = oldMat ? QSGTexturePrivate::get(oldMat->texture())->rhiTexture() : nullptr;
+ QRhiTexture *newRtex = QSGTexturePrivate::get(mat->texture())->rhiTexture();
+ if (updated || !oldMat || oldRtex != newRtex) {
const QVector2D textureScale = QVector2D(1.0f / mat->rhiGlyphCache()->width(),
1.0f / mat->rhiGlyphCache()->height());
memcpy(buf->data() + 64 + 16, &textureScale, 8);
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 58dfd97e03..08d1c726ab 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -214,9 +214,7 @@ QSGRenderLoop *QSGRenderLoop::instance()
{
if (!s_instance) {
- // For compatibility with 5.3 and earlier's QSG_INFO environment variables
- if (qEnvironmentVariableIsSet("QSG_INFO"))
- const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true);
+ QSGRhiSupport::checkEnvQSgInfo();
s_instance = QSGContext::createWindowManager();
#ifdef ENABLE_DEFAULT_BACKEND
diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp
index 8bae24dc76..a92b6b0c84 100644
--- a/src/quick/scenegraph/qsgrhisupport.cpp
+++ b/src/quick/scenegraph/qsgrhisupport.cpp
@@ -109,6 +109,12 @@ void QSGRhiSupport::applySettings()
{
m_set = true;
+ // This is also done when creating the renderloop but we may be before that
+ // in case we get here due to a setScenegraphBackend() -> configure() early
+ // on in main(). Avoid losing info logs since troubleshooting gets
+ // confusing otherwise.
+ QSGRhiSupport::checkEnvQSgInfo();
+
if (m_requested.valid) {
// explicit rhi backend request from C++ (e.g. via QQuickWindow)
m_enableRhi = m_requested.rhi;
@@ -203,6 +209,13 @@ QSGRhiSupport *QSGRhiSupport::staticInst()
return &inst;
}
+void QSGRhiSupport::checkEnvQSgInfo()
+{
+ // For compatibility with 5.3 and earlier's QSG_INFO environment variables
+ if (qEnvironmentVariableIsSet("QSG_INFO"))
+ const_cast<QLoggingCategory &>(QSG_LOG_INFO()).setEnabled(QtDebugMsg, true);
+}
+
void QSGRhiSupport::configure(QSGRendererInterface::GraphicsApi api)
{
Q_ASSERT(QSGRendererInterface::isApiRhiBased(api));
diff --git a/src/quick/scenegraph/qsgrhisupport_p.h b/src/quick/scenegraph/qsgrhisupport_p.h
index 0e1881aa00..f2d5837bba 100644
--- a/src/quick/scenegraph/qsgrhisupport_p.h
+++ b/src/quick/scenegraph/qsgrhisupport_p.h
@@ -126,6 +126,8 @@ public:
QImage grabAndBlockInCurrentFrame(QRhi *rhi, QRhiSwapChain *swapchain);
+ static void checkEnvQSgInfo();
+
private:
QSGRhiSupport();
void applySettings();
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index ee9ea0f5ed..c345f3b16d 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -53,6 +53,7 @@ HEADERS += \
$$PWD/util/qsgengine.h \
$$PWD/util/qsgengine_p.h \
$$PWD/util/qsgplaintexture_p.h \
+ $$PWD/util/qsgrhinativetextureimporter_p.h \
$$PWD/util/qsgsimplerectnode.h \
$$PWD/util/qsgsimpletexturenode.h \
$$PWD/util/qsgtextureprovider.h \
@@ -69,6 +70,7 @@ SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
$$PWD/util/qsgengine.cpp \
$$PWD/util/qsgplaintexture.cpp \
+ $$PWD/util/qsgrhinativetextureimporter.cpp \
$$PWD/util/qsgsimplerectnode.cpp \
$$PWD/util/qsgsimpletexturenode.cpp \
$$PWD/util/qsgtextureprovider.cpp \
diff --git a/src/quick/scenegraph/shaders_ng/visualization.vert b/src/quick/scenegraph/shaders_ng/visualization.vert
index c29492417a..e2447948c2 100644
--- a/src/quick/scenegraph/shaders_ng/visualization.vert
+++ b/src/quick/scenegraph/shaders_ng/visualization.vert
@@ -11,7 +11,7 @@ layout(std140, binding = 0) uniform buf {
int projection;
} ubuf;
-out gl_PerVertex { vec4 gl_Position; };
+out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };
void main()
{
@@ -25,4 +25,6 @@ void main()
}
pos = v.xy * 1.37;
+
+ gl_PointSize = 1.0;
}
diff --git a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
index bd89847dd3..7ba27cb4b5 100644
--- a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp
index c05005c467..4880d98871 100644
--- a/src/quick/scenegraph/util/qsgengine.cpp
+++ b/src/quick/scenegraph/util/qsgengine.cpp
@@ -69,6 +69,10 @@ QT_BEGIN_NAMESPACE
Most of the time you will instead want to subclass QQuickItem and insert
your QSGNode in a normal QtQuick scene by overriding QQuickItem::updatePaintNode().
+ \warning This class is only suitable when working directly with OpenGL. It
+ is not compatible with the \l{Scene Graph Adaptations}{RHI-based rendering
+ path}.
+
\sa QSGAbstractRenderer
*/
diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h
index e48b7784ae..c5a59b47e7 100644
--- a/src/quick/scenegraph/util/qsgengine.h
+++ b/src/quick/scenegraph/util/qsgengine.h
@@ -54,6 +54,8 @@ class QSGRectangleNode;
class QSGImageNode;
class QSGNinePatchNode;
+// ### Qt 6: Remove or redesign.
+
class Q_QUICK_EXPORT QSGEngine : public QObject
{
Q_OBJECT
diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp
index 72313db836..fdebe03494 100644
--- a/src/quick/scenegraph/util/qsgplaintexture.cpp
+++ b/src/quick/scenegraph/util/qsgplaintexture.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qsgplaintexture_p.h"
+#include "qsgrhinativetextureimporter_p.h"
#include <QtQuick/private/qsgcontext_p.h>
#include <qmath.h>
#include <private/qquickprofiler_p.h>
@@ -274,6 +275,24 @@ void QSGPlainTexture::setTexture(QRhiTexture *texture) // RHI only
m_mipmaps_generated = false;
}
+void QSGPlainTexture::setTextureFromNativeObject(QRhi *rhi, QQuickWindow::NativeObjectType type,
+ const void *nativeObjectPtr, int nativeLayout,
+ const QSize &size, bool mipmap)
+{
+ Q_UNUSED(type);
+
+ QRhiTexture::Flags flags = 0;
+ if (mipmap)
+ flags |= QRhiTexture::MipMapped | QRhiTexture::UsedWithGenerateMips;
+
+ QRhiTexture *t = rhi->newTexture(QRhiTexture::RGBA8, size, 1, flags);
+
+ // ownership of the native object is never taken
+ QSGRhiNativeTextureImporter::buildWrapper(rhi, t, nativeObjectPtr, nativeLayout);
+
+ setTexture(t);
+}
+
int QSGPlainTexturePrivate::comparisonKey() const
{
Q_Q(const QSGPlainTexture);
diff --git a/src/quick/scenegraph/util/qsgplaintexture_p.h b/src/quick/scenegraph/util/qsgplaintexture_p.h
index 69c0153f9a..1eb0b59d2e 100644
--- a/src/quick/scenegraph/util/qsgplaintexture_p.h
+++ b/src/quick/scenegraph/util/qsgplaintexture_p.h
@@ -53,6 +53,7 @@
#include <QtQuick/private/qtquickglobal_p.h>
#include <QtQuick/private/qsgtexture_p.h>
+#include <QtQuick/qquickwindow.h>
QT_BEGIN_NAMESPACE
@@ -85,6 +86,9 @@ public:
void bind() override;
void setTexture(QRhiTexture *texture);
+ void setTextureFromNativeObject(QRhi *rhi, QQuickWindow::NativeObjectType type,
+ const void *nativeObjectPtr, int nativeLayout,
+ const QSize &size, bool mipmap);
static QSGPlainTexture *fromImage(const QImage &image) {
QSGPlainTexture *t = new QSGPlainTexture();
diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp b/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp
new file mode 100644
index 0000000000..7a7c19f587
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrhinativetextureimporter.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrhinativetextureimporter_p.h"
+#include <private/qsgrhisupport_p.h> // to get all the relevant qrhi headers
+
+QT_BEGIN_NAMESPACE
+
+void QSGRhiNativeTextureImporter::buildWrapper(QRhi *rhi, QRhiTexture *t,
+ const void *nativeObjectPtr, int nativeLayout)
+{
+#if !QT_CONFIG(vulkan)
+ Q_UNUSED(nativeLayout);
+#endif
+#if !QT_CONFIG(opengl) && !QT_CONFIG(vulkan) && !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN)
+ Q_UNUSED(nativeObjectPtr);
+#endif
+
+ switch (rhi->backend()) {
+ case QRhi::OpenGLES2:
+ {
+#if QT_CONFIG(opengl)
+ QRhiGles2TextureNativeHandles h;
+ h.texture = *reinterpret_cast<const uint *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Vulkan:
+ {
+#if QT_CONFIG(vulkan)
+ QRhiVulkanTextureNativeHandles h;
+ h.image = *reinterpret_cast<const VkImage *>(nativeObjectPtr);
+ h.layout = VkImageLayout(nativeLayout);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::D3D11:
+ {
+#ifdef Q_OS_WIN
+ QRhiD3D11TextureNativeHandles h;
+ h.texture = *reinterpret_cast<void * const *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Metal:
+ {
+#ifdef Q_OS_DARWIN
+ QRhiMetalTextureNativeHandles h;
+ h.texture = *reinterpret_cast<void * const *>(nativeObjectPtr);
+ t->buildFrom(&h);
+#endif
+ }
+ break;
+ case QRhi::Null:
+ t->build();
+ break;
+ default:
+ qWarning("QSGRhiNativeTextureImporter: encountered an unsupported QRhi backend (%d)",
+ int(rhi->backend()));
+ t->build();
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h b/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h
new file mode 100644
index 0000000000..e811109a94
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgrhinativetextureimporter_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGRHINATIVETEXTUREIMPORTER_P_H
+#define QSGRHINATIVETEXTUREIMPORTER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qtquickglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRhi;
+class QRhiTexture;
+
+class QSGRhiNativeTextureImporter
+{
+public:
+ static void buildWrapper(QRhi *rhi, QRhiTexture *t,
+ const void *nativeObjectPtr, int nativeLayout);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGRHINATIVETEXTUREIMPORTER_P_H
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index d246ee7910..61319c388c 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -2397,32 +2397,42 @@ void QQuickPathPercent::setValue(qreal value)
\qmlproperty list<point> QtQuick::PathPolyline::path
This property defines the vertices of the polyline.
+
+ It can be a JS array of points constructed with \c Qt.point(),
+ a QList or QVector of QPointF, or QPolygonF.
+ If you are binding this to a custom property in some C++ object,
+ QPolygonF is the most appropriate type to use.
*/
QQuickPathPolyline::QQuickPathPolyline(QObject *parent) : QQuickCurve(parent)
{
}
-QVariantList QQuickPathPolyline::path() const
+QVariant QQuickPathPolyline::path() const
{
- QVariantList res;
- for (int i = 0; i < m_path.length(); ++i) {
- const QPointF &c = m_path.at(i);
- res.append(QVariant::fromValue(c));
- }
-
- return res;
+ return QVariant::fromValue(m_path);
}
-void QQuickPathPolyline::setPath(const QVariantList &path)
+void QQuickPathPolyline::setPath(const QVariant &path)
{
- QVector<QPointF> pathList;
- for (int i = 0; i < path.length(); ++i) {
- const QPointF c = path.at(i).toPointF();
- pathList.append(c);
+ if (path.type() == QVariant::PolygonF) {
+ setPath(path.value<QPolygonF>());
+ } else if (path.canConvert<QVector<QPointF>>()) {
+ setPath(path.value<QVector<QPointF>>());
+ } else if (path.canConvert<QVariantList>()) {
+ // This handles cases other than QPolygonF or QVector<QPointF>, such as
+ // QList<QPointF>, QVector<QPoint>, QVariantList of QPointF, QVariantList of QPoint.
+ QVector<QPointF> pathList;
+ QVariantList vl = path.value<QVariantList>();
+ // If path is a QJSValue, e.g. coming from a JS array of Qt.point() in QML,
+ // then path.value<QVariantList>() is inefficient.
+ // TODO We should be able to iterate over path.value<QSequentialIterable>() eventually
+ for (const QVariant &v : vl)
+ pathList.append(v.toPointF());
+ setPath(pathList);
+ } else {
+ qWarning() << "PathPolyline: path of type" << path.type() << "not supported";
}
-
- setPath(pathList);
}
void QQuickPathPolyline::setPath(const QVector<QPointF> &path)
@@ -2522,48 +2532,60 @@ void QQuickPathPolyline::addToPath(QPainterPath &path, const QQuickPathData &/*d
\qmlproperty list<list<point>> QtQuick::PathMultiline::paths
This property defines the vertices of the polylines.
+
+ It can be a JS array of JS arrays of points constructed with \c Qt.point(),
+ a QList or QVector of QPolygonF, or QVector<QVector<QPointF>>.
+ If you are binding this to a custom property in some C++ object,
+ QVector<QPolygonF> or QVector<QVector<QPointF>> is the most
+ appropriate type to use.
*/
QQuickPathMultiline::QQuickPathMultiline(QObject *parent) : QQuickCurve(parent)
{
}
-QVariantList QQuickPathMultiline::paths() const
-{
- QVariantList res;
- for (int j = 0; j < m_paths.length(); ++j) {
- const QVector<QPointF> &path = m_paths.at(j);
- QVariantList p;
- for (int i = 0; i < path.length(); ++i) {
- const QPointF &c = path.at(i);
- p.append(QVariant::fromValue(c));
- }
- res.append(p);
- }
- return res;
-}
-
-void QQuickPathMultiline::setPaths(const QVariantList &paths)
-{
- QVector<QVector<QPointF>> pathsList;
- for (int j = 0; j < paths.length(); ++j) {
- if (paths.at(j).type() != QVariant::List)
- qWarning() << "QQuickPathMultiLine::setPaths: elements in argument not of type List";
- QVariantList path = paths.at(j).toList();
- QVector<QPointF> l;
- for (int i = 0; i < path.length(); ++i) {
- const QVariant &element = path.at(i);
- const QVariant::Type elementType = element.type();
- if (elementType == QVariant::PointF || elementType == QVariant::Point) {
- const QPointF c = element.toPointF();
- l.append(c);
+QVariant QQuickPathMultiline::paths() const
+{
+ return QVariant::fromValue(m_paths);
+}
+
+void QQuickPathMultiline::setPaths(const QVariant &paths)
+{
+ if (paths.canConvert<QVector<QPolygonF>>()) {
+ const QVector<QPolygonF> pathPolygons = paths.value<QVector<QPolygonF>>();
+ QVector<QVector<QPointF>> pathVectors;
+ for (const QPolygonF &p : pathPolygons)
+ pathVectors << p;
+ setPaths(pathVectors);
+ } else if (paths.canConvert<QVector<QVector<QPointF>>>()) {
+ setPaths(paths.value<QVector<QVector<QPointF>>>());
+ } else if (paths.canConvert<QVariantList>()) {
+ // This handles cases other than QVector<QPolygonF> or QVector<QVector<QPointF>>, such as
+ // QList<QVector<QPointF>>, QList<QList<QPointF>>, QVariantList of QVector<QPointF>,
+ // QVariantList of QVariantList of QPointF, QVector<QList<QPoint>> etc.
+ QVector<QVector<QPointF>> pathsList;
+ QVariantList vll = paths.value<QVariantList>();
+ for (const QVariant &v : vll) {
+ // If we bind a QVector<QPolygonF> property directly, rather than via QVariant,
+ // it will come through as QJSValue that can be converted to QVariantList of QPolygonF.
+ if (v.canConvert<QPolygonF>()) {
+ pathsList.append(v.value<QPolygonF>());
+ } else {
+ QVariantList vl = v.value<QVariantList>();
+ QVector<QPointF> l;
+ for (const QVariant &point : vl) {
+ if (point.canConvert<QPointF>())
+ l.append(point.toPointF());
+ }
+ if (l.size() >= 2)
+ pathsList.append(l);
}
}
- if (l.size() >= 2)
- pathsList.append(l);
+ setPaths(pathsList);
+ } else {
+ qWarning() << "PathMultiline: paths of type" << paths.type() << "not supported";
+ setPaths(QVector<QVector<QPointF>>());
}
-
- setPaths(pathsList);
}
void QQuickPathMultiline::setPaths(const QVector<QVector<QPointF>> &paths)
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index 92607a6c1e..5987ae8f35 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -428,12 +428,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathPolyline : public QQuickCurve
{
Q_OBJECT
Q_PROPERTY(QPointF start READ start NOTIFY startChanged)
- Q_PROPERTY(QVariantList path READ path WRITE setPath NOTIFY pathChanged)
+ Q_PROPERTY(QVariant path READ path WRITE setPath NOTIFY pathChanged)
public:
QQuickPathPolyline(QObject *parent=nullptr);
- QVariantList path() const;
- void setPath(const QVariantList &path);
+ QVariant path() const;
+ void setPath(const QVariant &path);
void setPath(const QVector<QPointF> &path);
QPointF start() const;
void addToPath(QPainterPath &path, const QQuickPathData &data) override;
@@ -450,12 +450,12 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathMultiline : public QQuickCurve
{
Q_OBJECT
Q_PROPERTY(QPointF start READ start NOTIFY startChanged)
- Q_PROPERTY(QVariantList paths READ paths WRITE setPaths NOTIFY pathsChanged)
+ Q_PROPERTY(QVariant paths READ paths WRITE setPaths NOTIFY pathsChanged)
public:
QQuickPathMultiline(QObject *parent=nullptr);
- QVariantList paths() const;
- void setPaths(const QVariantList &paths);
+ QVariant paths() const;
+ void setPaths(const QVariant &paths);
void setPaths(const QVector<QVector<QPointF>> &paths);
QPointF start() const;
void addToPath(QPainterPath &path, const QQuickPathData &) override;
diff --git a/src/src.pro b/src/src.pro
index b1e0a72c9f..98e1779dc5 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -11,9 +11,10 @@ qtConfig(qml-worker-script): \
SUBDIRS += qmlworkerscript
qtHaveModule(gui):qtConfig(qml-animation) {
- SUBDIRS += \
- quick \
- quickshapes
+ SUBDIRS += quick
+
+ qtConfig(quick-path): \
+ SUBDIRS += quickshapes
qtConfig(testlib): \
SUBDIRS += qmltest
diff --git a/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml b/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml
new file mode 100644
index 0000000000..0a75ea6f36
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/semicolonAfterProperty.qml
@@ -0,0 +1,10 @@
+import QtQml 2.0
+
+QtObject {
+ property var field: { "key": "value"};
+ property list<QtObject> mylist: [
+ QtObject {id: a},
+ QtObject {id: b}
+ ];
+ property var object: QtObject {};
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 1decaeda7f..cfdb15304d 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -374,6 +374,7 @@ private slots:
void hugeRegexpQuantifiers();
void singletonTypeWrapperLookup();
void getThisObject();
+ void semicolonAfterProperty();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -9108,6 +9109,16 @@ void tst_qqmlecmascript::getThisObject()
QTRY_COMPARE(qvariant_cast<QObject *>(test->property("self")), test.data());
}
+// QTBUG-77954
+void tst_qqmlecmascript::semicolonAfterProperty()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("semicolonAfterProperty.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> test(component.create());
+ QVERIFY(!test.isNull());
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt b/tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt
index 30748234bc..5a144f2db5 100644
--- a/tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/fakeDotProperty.errors.txt
@@ -1 +1 @@
-3:5:Invalid grouped property access
+3:5:Invalid grouped property access: Property "value" with primitive type "int".
diff --git a/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt
index 810fd31b41..5deec4ccf9 100644
--- a/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/invalidGroupedProperty.2.errors.txt
@@ -1 +1 @@
-5:5:Invalid grouped property access
+5:5:Invalid grouped property access: Property "o" with primitive type "int".
diff --git a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
index 945dacf8ab..043f714636 100644
--- a/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/objectValueTypeProperty.errors.txt
@@ -1 +1 @@
-4:18:Can not assign value of type "int" to property "x", expecting an object
+4:18:Can not assign value of type "MyTypeObject" to property "x", expecting "int"
diff --git a/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt
new file mode 100644
index 0000000000..1655f9264a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.errors.txt
@@ -0,0 +1 @@
+3:23:Cannot assign to property of unknown type "SomethingUnknown*".
diff --git a/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml
new file mode 100644
index 0000000000..c22fd65350
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/propertyUnknownType.qml
@@ -0,0 +1,4 @@
+import Test 1.0
+MyQmlObject {
+ somethingUnknown: SomethingKnown {}
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index 05c1bd0116..226a78b960 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -62,6 +62,7 @@ void registerTypes()
qmlRegisterType<MyRevisionedClass,1>("Test",1,1,"MyRevisionedClass");
qmlRegisterType<MyRevisionedIllegalOverload>("Test",1,0,"MyRevisionedIllegalOverload");
qmlRegisterType<MyRevisionedLegalOverload>("Test",1,0,"MyRevisionedLegalOverload");
+ qmlRegisterType<SomethingKnown>("Test",1,0,"SomethingKnown");
// Register the uncreatable base class
qmlRegisterRevision<MyRevisionedBaseClassRegistered,1>("Test",1,1);
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index 0618d2b20f..1aab24841a 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -89,6 +89,14 @@ private:
int m_value2;
};
+class SomethingUnknown : public QObject {
+ Q_OBJECT
+};
+
+class SomethingKnown : public SomethingUnknown {
+ Q_OBJECT
+};
+
class MyQmlObject : public QObject, public MyInterface
{
Q_OBJECT
@@ -104,6 +112,7 @@ class MyQmlObject : public QObject, public MyInterface
Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal)
Q_PROPERTY(int nonScriptable READ nonScriptable WRITE setNonScriptable SCRIPTABLE false)
Q_PROPERTY(QJSValue qjsvalue READ qjsvalue WRITE setQJSValue NOTIFY qjsvalueChanged)
+ Q_PROPERTY(SomethingUnknown* somethingUnknown READ somethingUnknown WRITE setSomethingUnknown NOTIFY somethingUnknownChanged)
Q_INTERFACES(MyInterface)
public:
@@ -151,6 +160,9 @@ public:
int childAddedEventCount() const { return m_childAddedEventCount; }
+ SomethingUnknown* somethingUnknown() const { return nullptr; }
+ void setSomethingUnknown(SomethingUnknown* something) { Q_UNUSED(something); }
+
public slots:
void basicSlot() { qWarning("MyQmlObject::basicSlot"); }
void basicSlotWithArgs(int v) { qWarning("MyQmlObject::basicSlotWithArgs(%d)", v); }
@@ -162,6 +174,7 @@ signals:
void oddlyNamedNotifySignal();
void signalWithDefaultArg(int parameter = 5);
void qjsvalueChanged();
+ void somethingUnknownChanged();
protected:
virtual bool event(QEvent *event);
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 27b550457d..8adacd8829 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -626,8 +626,9 @@ void tst_qqmllanguage::errors_data()
QTest::newRow("bareQmlImport") << "bareQmlImport.qml" << "bareQmlImport.errors.txt" << false;
QTest::newRow("typeAnnotations.2") << "typeAnnotations.2.qml" << "typeAnnotations.2.errors.txt" << false;
-}
+ QTest::newRow("propertyUnknownType") << "propertyUnknownType.qml" << "propertyUnknownType.errors.txt" << false;
+}
void tst_qqmllanguage::errors()
{
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index 8a602a0356..a55da25a91 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -97,6 +97,7 @@ private slots:
void enumerableProperties();
void enumProperties();
void scarceTypes();
+ void nonValueTypes();
private:
QQmlEngine engine;
@@ -1844,6 +1845,16 @@ void tst_qqmlvaluetypes::scarceTypes()
QCOMPARE(QByteArray(pixmapValue->vtable()->className), QByteArray("VariantObject"));
}
+#define CHECK_TYPE_IS_NOT_VALUETYPE(Type, typeId, cppType) \
+ QVERIFY(!QQmlValueTypeFactory::isValueType(QMetaType::Type));
+
+void tst_qqmlvaluetypes::nonValueTypes()
+{
+ CHECK_TYPE_IS_NOT_VALUETYPE(UnknownType, 0, void)
+ QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(CHECK_TYPE_IS_NOT_VALUETYPE);
+}
+
+#undef CHECK_TYPE_IS_NOT_VALUETYPE
QTEST_MAIN(tst_qqmlvaluetypes)
diff --git a/tests/auto/quick/qquickshape/data/multiline.png b/tests/auto/quick/qquickshape/data/multiline.png
new file mode 100644
index 0000000000..ae25d111df
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/multiline.png
Binary files differ
diff --git a/tests/auto/quick/qquickshape/data/multiline.qml b/tests/auto/quick/qquickshape/data/multiline.qml
new file mode 100644
index 0000000000..ad07506972
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/multiline.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+import QtQuick.Shapes 1.14
+
+Shape {
+ width: 200
+ height: 150
+ vendorExtensionsEnabled: false
+ objectName: "shape"
+ id: shape
+ property alias paths: multiline.paths
+ property point vertexBeingChecked;
+
+ function checkVertexAt(i, j) {
+ vertexBeingChecked = multiline.paths[i][j]
+ }
+
+ ShapePath {
+ strokeWidth: 4
+ strokeColor: "green"
+ PathMultiline {
+ id: multiline
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml b/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml
new file mode 100644
index 0000000000..46d650e053
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+import QtQuick.Shapes 1.14
+import Qt.test 1.0
+
+Shape {
+ width: 200
+ height: 150
+ vendorExtensionsEnabled: false
+ objectName: "shape"
+ id: shape
+ property alias paths: multiline.paths
+ property point vertexBeingChecked;
+
+ function checkVertexAt(i, j) {
+ vertexBeingChecked = multiline.paths[i][j]
+ }
+
+ PolygonProvider {
+ id: provider
+ objectName: "provider"
+ }
+
+ ShapePath {
+ strokeWidth: 4
+ strokeColor: "green"
+ PathMultiline {
+ id: multiline
+ paths: provider.paths
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshape/data/polyline.png b/tests/auto/quick/qquickshape/data/polyline.png
new file mode 100644
index 0000000000..00123fba44
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/polyline.png
Binary files differ
diff --git a/tests/auto/quick/qquickshape/data/polyline.qml b/tests/auto/quick/qquickshape/data/polyline.qml
new file mode 100644
index 0000000000..e62d952ae7
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/polyline.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.14
+import QtQuick.Shapes 1.14
+
+Shape {
+ width: 200
+ height: 150
+ vendorExtensionsEnabled: false
+ objectName: "shape"
+ id: shape
+ property alias path: polyline.path
+ property point vertexBeingChecked;
+
+ function checkVertexAt(i) {
+ vertexBeingChecked = polyline.path[i]
+ }
+
+ ShapePath {
+ strokeWidth: 4
+ strokeColor: "green"
+ PathPolyline {
+ id: polyline
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
index b3b8d2d148..851475e2cd 100644
--- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp
+++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
@@ -43,6 +43,28 @@
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
+class PolygonProvider : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector<QPolygonF> paths READ paths WRITE setPaths NOTIFY pathsChanged)
+
+public:
+ QVector<QPolygonF> paths() const { return m_paths; }
+ void setPaths(QVector<QPolygonF> paths)
+ {
+ if (m_paths == paths)
+ return;
+ m_paths = paths;
+ emit pathsChanged();
+ }
+
+signals:
+ void pathsChanged();
+
+private:
+ QVector<QPolygonF> m_paths;
+};
+
class tst_QQuickShape : public QQmlDataTest
{
Q_OBJECT
@@ -60,6 +82,14 @@ private slots:
void conicalGrad();
void renderPolyline();
void renderMultiline();
+ void polylineDataTypes_data();
+ void polylineDataTypes();
+ void multilineDataTypes_data();
+ void multilineDataTypes();
+ void multilineStronglyTyped();
+
+private:
+ QVector<QPolygonF> m_lowPolyLogo;
};
tst_QQuickShape::tst_QQuickShape()
@@ -75,6 +105,30 @@ tst_QQuickShape::tst_QQuickShape()
qmlRegisterType<QQuickShapeRadialGradient>(uri, 1, 0, "RadialGradient");
qmlRegisterType<QQuickShapeConicalGradient>(uri, 1, 0, "ConicalGradient");
qmlRegisterType<QQuickPathPolyline>(uri, 1, 0, "PathPolyline");
+ qmlRegisterType<PolygonProvider>("Qt.test", 1, 0, "PolygonProvider");
+
+ m_lowPolyLogo << (QPolygonF() <<
+ QPointF(20, 0) <<
+ QPointF(140, 0) <<
+ QPointF(140, 80) <<
+ QPointF(120, 100) <<
+ QPointF(0, 100) <<
+ QPointF(0, 20) <<
+ QPointF(20, 0) )
+ << (QPolygonF() << QPointF(20, 80) <<
+ QPointF(60, 80) <<
+ QPointF(80, 60) <<
+ QPointF(80, 20) <<
+ QPointF(40, 20) <<
+ QPointF(20, 40) <<
+ QPointF(20, 80) )
+ << (QPolygonF() << QPointF(80, 80) <<
+ QPointF(70, 70) )
+ << (QPolygonF() << QPointF(120, 80) <<
+ QPointF(100, 60) <<
+ QPointF(100, 20) )
+ << (QPolygonF() << QPointF(100, 40) <<
+ QPointF(120, 40) );
}
void tst_QQuickShape::initValues()
@@ -373,6 +427,286 @@ void tst_QQuickShape::renderMultiline()
QVERIFY2(res, qPrintable(errorMessage));
}
+void tst_QQuickShape::polylineDataTypes_data()
+{
+ QTest::addColumn<QVariant>("path");
+
+ QTest::newRow("polygon") << QVariant::fromValue(m_lowPolyLogo.first());
+ {
+ QVector<QPointF> points;
+ points << m_lowPolyLogo.first();
+ QTest::newRow("vector of points") << QVariant::fromValue(points);
+ }
+ {
+ QList<QPointF> points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point;
+ QTest::newRow("list of points") << QVariant::fromValue(points);
+ }
+ {
+ QVariantList points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point;
+ QTest::newRow("QVariantList of points") << QVariant::fromValue(points);
+ }
+ {
+ QVector<QPoint> points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point.toPoint();
+ QTest::newRow("vector of QPoint (integer points)") << QVariant::fromValue(points);
+ }
+ // Oddly, QPolygon is not supported, even though it's really QVector<QPoint>.
+ // We don't want to have a special case for it in QQuickPathPolyline::setPath(),
+ // but it could potentially be supported by fixing one of the QVariant conversions.
+}
+
+void tst_QQuickShape::polylineDataTypes()
+{
+ QFETCH(QVariant, path);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("polyline.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ shape->setProperty("path", path);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("polyline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/polyline.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QCOMPARE(shape->property("path").value<QVector<QPointF>>(), m_lowPolyLogo.first());
+ // Verify that QML sees it as an array of points
+ int i = 0;
+ for (QPointF p : m_lowPolyLogo.first()) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+}
+
+void tst_QQuickShape::multilineDataTypes_data()
+{
+ QTest::addColumn<QVariant>("paths");
+
+ QTest::newRow("vector of polygons") << QVariant::fromValue(m_lowPolyLogo);
+ {
+ QVector<QVector<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << points;
+ }
+ QTest::newRow("vector of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QVector<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << points;
+ }
+ QTest::newRow("list of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QList<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPointF> points;
+ for (const auto &point : poly)
+ points << point;
+ paths << points;
+ }
+ QTest::newRow("list of point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPointF> points;
+ for (const auto &point : poly)
+ points << point;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVariantList points;
+ for (const auto &point : poly)
+ points << point;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of QVariantLists") << QVariant::fromValue(paths);
+ }
+ /* These could be supported if QVariant knew how to convert lists and vectors of QPolygon to QPolygonF.
+ But they are omitted for now because we don't want to have special cases for them
+ in QQuickPathMultiline::setPaths(). Floating point is preferred for geometry in Qt Quick.
+ {
+ QList<QPolygon> paths;
+ for (const auto &poly : m_lowPolyLogo)
+ paths << poly.toPolygon();
+ QTest::newRow("list of QPolygon (integer points)") << QVariant::fromValue(paths);
+ }
+ {
+ QVector<QPolygon> paths;
+ for (const auto &poly : m_lowPolyLogo)
+ paths << poly.toPolygon();
+ QTest::newRow("vector of QPolygon (integer points)") << QVariant::fromValue(paths);
+ }
+ */
+ {
+ QList<QList<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("list of integer point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVector<QList<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("vector of integer point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QVector<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("list of integer point vectors") << QVariant::fromValue(paths);
+ }
+}
+
+void tst_QQuickShape::multilineDataTypes()
+{
+ QFETCH(QVariant, paths);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("multiline.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ shape->setProperty("paths", paths);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("multiline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/multiline.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QVector<QVector<QPointF>> pointVectors;
+ for (auto v : m_lowPolyLogo)
+ pointVectors << v;
+ QCOMPARE(shape->property("paths").value<QVector<QVector<QPointF>>>(), pointVectors);
+ // Verify that QML sees it as an array of arrays of points
+ int i = 0;
+ for (auto pv : m_lowPolyLogo) {
+ int j = 0;
+ for (QPointF p : pv) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i)), Q_ARG(QVariant, QVariant::fromValue<int>(j++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+ ++i;
+ }
+}
+
+void tst_QQuickShape::multilineStronglyTyped()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("multilineStronglyTyped.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ PolygonProvider *provider = shape->findChild<PolygonProvider*>("provider");
+ QVERIFY(provider);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ provider->setPaths(m_lowPolyLogo);
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("multiline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/multilineStronglyTyped.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QVector<QVector<QPointF>> pointVectors;
+ for (auto v : m_lowPolyLogo)
+ pointVectors << v;
+ QCOMPARE(shape->property("paths").value<QVector<QVector<QPointF>>>(), pointVectors);
+ // Verify that QML sees it as an array of arrays of points
+ int i = 0;
+ for (auto pv : m_lowPolyLogo) {
+ int j = 0;
+ for (QPointF p : pv) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i)), Q_ARG(QVariant, QVariant::fromValue<int>(j++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+ ++i;
+ }
+}
+
QTEST_MAIN(tst_QQuickShape)
#include "tst_qquickshape.moc"