aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--src/imports/statemachine/signaltransition.cpp6
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp5
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp4
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp6
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc27
-rw-r--r--src/quick/items/qquickflickable.cpp8
-rw-r--r--src/quick/items/qquickflickable_p_p.h1
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp4
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp4
-rw-r--r--tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp4
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp12
-rw-r--r--tests/auto/qml/qqmllanguage/data/Broken.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/asBroken.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp20
-rw-r--r--tests/auto/quick/qquickflickable/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp8
-rw-r--r--tools/qmlimportscanner/main.cpp66
18 files changed, 113 insertions, 78 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 703f7df915..65ef03633e 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -4,4 +4,4 @@ CONFIG += warning_clean
DEFINES += QT_NO_LINKED_LIST
DEFINES += QT_NO_JAVA_STYLE_ITERATORS
-MODULE_VERSION = 5.15.12
+MODULE_VERSION = 5.15.13
diff --git a/src/imports/statemachine/signaltransition.cpp b/src/imports/statemachine/signaltransition.cpp
index eb7095bc2a..dcebb21b41 100644
--- a/src/imports/statemachine/signaltransition.cpp
+++ b/src/imports/statemachine/signaltransition.cpp
@@ -171,7 +171,11 @@ void SignalTransition::connectTriggered()
QV4::ExecutionEngine *jsEngine = QQmlEngine::contextForObject(this)->engine()->handle();
QV4::Scope scope(jsEngine);
QV4::Scoped<QV4::QObjectMethod> qobjectSignal(scope, QJSValuePrivate::convertedToValue(jsEngine, m_signal));
- Q_ASSERT(qobjectSignal);
+ if (!qobjectSignal) {
+ m_signalExpression.take(nullptr);
+ return;
+ }
+
QMetaMethod metaMethod = target->metaObject()->method(qobjectSignal->methodIndex());
int signalIndex = QMetaObjectPrivate::signalIndex(metaMethod);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 5fc94b9ddd..cf2e4ec1dd 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1530,6 +1530,11 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
if (done->booleanValue())
break;
++argCount;
+ constexpr auto safetyMargin = 100; // leave some space on the stack for actual work with the elements
+ if (qint64(scope.engine->jsStackLimit - scope.engine->jsStackTop) < safetyMargin) {
+ scope.engine->throwRangeError(QLatin1String("Too many elements in array to use it with the spread operator"));
+ return { nullptr, 0 };
+ }
v = scope.alloc<Scope::Uninitialized>();
}
}
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 6b68a2a288..8a0abf8bdd 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -51,8 +51,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/QCryptographicHash>
+#include <QtCore/private/qtools_p.h>
-#include <ctype.h> // for toupper
#include <limits.h>
#include <algorithm>
@@ -571,7 +571,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QVarLengthArray<char, 128> str(length+3);
str[0] = 'o';
str[1] = 'n';
- str[2] = toupper(rawName[0]);
+ str[2] = QtMiscUtils::toAsciiUpper(rawName[0]);
if (length > 1)
memcpy(&str[3], &rawName[1], length - 1);
str[length + 2] = '\0';
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 175de8b936..a6ba4b8cb3 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -419,8 +419,10 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
return Encode(false);
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
- ExecutableCompilationUnit *cu = td->compilationUnit();
- myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ if (ExecutableCompilationUnit *cu = td->compilationUnit())
+ myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ else
+ return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
} else {
myQmlType = qenginepriv->metaObjectForType(myTypeId);
}
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
index abfff7cc11..8cd51a50c6 100644
--- a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -52,11 +52,16 @@ options that align with the latest UI design trends. If these UI controls do not
satisfy your application's needs, only then it is recommended to create a
custom control.
+You can use the controls when you design UIs in Qt Design Studio. In addition,
+it provides timeline-based animations, visual effects, layouts, and a
+live-preview for prototyping applications.
\section2 Related Information
\list
\li \l{Qt Quick Controls}
+\li \l{Customizing Qt Quick Controls}
\li \l{Qt Quick}
+\li \l{Qt Design Studio Manual}
\endlist
\omit
@@ -146,7 +151,7 @@ specific file managed by the resource system. For example, if we wanted to give
\li \l{The Qt Resource System}
\endlist
-\section1 Separate UI from Logic
+\section1 Separate UI from Business Logic
One of the key goals that most application developers want to achieve is to
create a maintainable application. One of the ways to achieve this goal is
@@ -162,8 +167,8 @@ reasons why an application's UI should be written in QML:
\li JavaScript can easily be used in QML to respond to events.
\endlist
-Being a strongly typed language, C++ is best suited for an application's logic.
-Typically, such code performs tasks such as complex calculations
+Being a strongly typed language, C++ is best suited for an application's
+business logic. Typically, such code performs tasks such as complex calculations
or data processing, which are faster in C++ than QML.
Qt offers various approaches to integrate QML and C++ code in an application.
@@ -326,6 +331,22 @@ see \l {Choosing the Correct Integration Method Between C++ and QML}.
\li \l{Qt Quick Controls - Chat Tutorial}{Chat application tutorial}
\endlist
+\section1 Using Qt Design Studio
+
+Qt Design Studio uses UI files that have the filename extension \e {.ui.qml}
+to separate the visual parts of the UI from the UI logic you implement in
+\e {.qml} files. You should edit UI files only in the \uicontrol {2D} view in
+Qt Design Studio. If you use some other tool to add code that Qt Design Studio
+does not support, it displays error messages. Fix the errors to enable visual
+editing of the UI files again. Typically, you should move the unsupported code
+to a \e {.qml} file.
+
+\section2 Related Information
+
+\list
+ \li \l{Qt Design Studio: UI Files}
+\endlist
+
\section1 Using Qt Quick Layouts
Qt offers Qt Quick Layouts to arrange Qt Quick items visually in a layout.
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index ea357d819d..2634b68248 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -2120,11 +2120,9 @@ void QQuickFlickable::setContentWidth(qreal w)
d->contentItem->setWidth(w);
d->hData.markExtentsDirty();
// Make sure that we're entirely in view.
- if ((!d->pressed && !d->hData.moving && !d->vData.moving) || d->hData.dragging) {
- d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
+ if (!d->pressed && !d->hData.moving && !d->vData.moving) {
d->fixupMode = QQuickFlickablePrivate::Immediate;
d->fixupX();
- d->hData.contentPositionChangedExternallyDuringDrag = false;
} else if (!d->pressed && d->hData.fixingUp) {
d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
d->fixupX();
@@ -2151,11 +2149,9 @@ void QQuickFlickable::setContentHeight(qreal h)
d->contentItem->setHeight(h);
d->vData.markExtentsDirty();
// Make sure that we're entirely in view.
- if ((!d->pressed && !d->hData.moving && !d->vData.moving) || d->vData.dragging) {
- d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
+ if (!d->pressed && !d->hData.moving && !d->vData.moving) {
d->fixupMode = QQuickFlickablePrivate::Immediate;
d->fixupY();
- d->vData.contentPositionChangedExternallyDuringDrag = false;
} else if (!d->pressed && d->vData.fixingUp) {
d->fixupMode = QQuickFlickablePrivate::ExtentChanged;
d->fixupY();
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index d5d838eaea..aef15e150a 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -120,6 +120,7 @@ public:
dragStartOffset = 0;
fixingUp = false;
inOvershoot = false;
+ contentPositionChangedExternallyDuringDrag = false;
}
void markExtentsDirty() {
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 10fd2c094d..d6834b554e 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -842,9 +842,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
for (int i=0; i<glyphIndexes.size(); ++i) {
QPointF glyphPosition = glyphPositions.at(i) + position;
+ QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
+
QFixed subPixelPosition;
if (supportsSubPixelPositions)
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x() * glyphCacheScaleX));
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index ff840eabaf..98170be6d9 100644
--- a/src/quickshapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
@@ -188,8 +188,12 @@ void QQuickShapeGenericRenderer::setPath(int index, const QQuickPath *path)
void QQuickShapeGenericRenderer::setStrokeColor(int index, const QColor &color)
{
ShapePathData &d(m_sp[index]);
+ const bool wasTransparent = d.strokeColor.a == 0;
d.strokeColor = colorToColor4ub(color);
+ const bool isTransparent = d.strokeColor.a == 0;
d.syncDirty |= DirtyColor;
+ if (wasTransparent && !isTransparent)
+ d.syncDirty |= DirtyStrokeGeom;
}
void QQuickShapeGenericRenderer::setStrokeWidth(int index, qreal w)
diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
index 9fe2de5368..2b6145030b 100644
--- a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
+++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp
@@ -393,9 +393,7 @@ void Test262Runner::loadTestExpectations()
return;
}
- int line = 0;
while (!file.atEnd()) {
- ++line;
QByteArray line = file.readLine().trimmed();
if (line.startsWith('#') || line.isEmpty())
continue;
@@ -440,9 +438,7 @@ void Test262Runner::updateTestExpectations()
QTemporaryFile updatedExpectations;
updatedExpectations.open();
- int line = 0;
while (!file.atEnd()) {
- ++line;
QByteArray originalLine = file.readLine();
QByteArray line = originalLine.trimmed();
if (line.startsWith('#') || line.isEmpty()) {
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 363070d7f8..f1c34e6142 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -271,6 +271,8 @@ private slots:
void uiLanguage();
void forOfAndGc();
+ void spreadNoOverflow();
+
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
Q_INVOKABLE void throwingCppMethod2();
@@ -5339,6 +5341,16 @@ void tst_QJSEngine::forOfAndGc()
QTRY_VERIFY(o->property("count").toInt() > 32768);
}
+void tst_QJSEngine::spreadNoOverflow()
+{
+ QJSEngine engine;
+
+ const QString program = QString::fromLatin1("var a = [] ;a.length = 555840;Math.max(...a)");
+ const QJSValue result = engine.evaluate(program);
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::RangeError);
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/Broken.qml b/tests/auto/qml/qqmllanguage/data/Broken.qml
new file mode 100644
index 0000000000..e1b61f31f4
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/Broken.qml
@@ -0,0 +1,5 @@
+import QtQml
+
+QtObject {
+ notThere: 5
+}
diff --git a/tests/auto/qml/qqmllanguage/data/asBroken.qml b/tests/auto/qml/qqmllanguage/data/asBroken.qml
new file mode 100644
index 0000000000..bd88d14c76
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/asBroken.qml
@@ -0,0 +1,6 @@
+import QtQml 2.15
+
+QtObject {
+ id: self
+ property var selfAsBroken: self as Broken
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index ac6634290a..92d0069ce4 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -343,6 +343,8 @@ private slots:
void bindingAliasToComponentUrl();
void badGroupedProperty();
+ void objectAsBroken();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -5951,6 +5953,24 @@ void tst_qqmllanguage::badGroupedProperty()
.arg(url.toString()));
}
+void tst_qqmllanguage::objectAsBroken()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("asBroken.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QVariant selfAsBroken = o->property("selfAsBroken");
+ QVERIFY(selfAsBroken.isValid());
+
+ // 5.15 doesn't enforce type annotation. So the "as" cast succeeds even though
+ // the target type cannot be resolved.
+ QCOMPARE(selfAsBroken.value<QObject *>(), o.data());
+
+ QQmlComponent b(&engine, testFileUrl("Broken.qml"));
+ QVERIFY(b.isError());
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/quick/qquickflickable/BLACKLIST b/tests/auto/quick/qquickflickable/BLACKLIST
deleted file mode 100644
index 636aef4904..0000000000
--- a/tests/auto/quick/qquickflickable/BLACKLIST
+++ /dev/null
@@ -1,3 +0,0 @@
-# See qtbase/src/testlib/qtestblacklist.cpp for format
-[setContentPositionWhileDragging]
-ci macos # QTBUG-106278
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index d092cd0170..62f7c67dd4 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -2642,7 +2642,12 @@ void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966
} else if (newExtent >= 0) {
// ...or reduce the content size be be less than current (contentX, contentY) position
// This forces the content item to move.
- expectedContentPos = moveDelta;
+ // contentY: 150
+ // 320 - 150 = 170 pixels down to bottom
+ // Now reduce contentHeight to 200
+ // since we are at the bottom, and the flickable is 100 pixels tall, contentY must land
+ // at newExtent - 100.
+
if (isHorizontal) {
flickable->setContentWidth(newExtent);
} else {
@@ -2652,6 +2657,7 @@ void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966
// We therefore cannot scroll/flick it further down. Drag it up towards the top instead
// (by moving mouse down).
pos += moveDelta;
+ expectedContentPos = unitDelta * (newExtent - (isHorizontal ? flickable->width() : flickable->height()));
}
QTest::mouseMove(window.data(), pos);
diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp
index 37368bb794..8209236916 100644
--- a/tools/qmlimportscanner/main.cpp
+++ b/tools/qmlimportscanner/main.cpp
@@ -71,14 +71,6 @@ inline QString dependenciesLiteral() { return QStringLiteral("dependencies"); }
inline QString moduleLiteral() { return QStringLiteral("module"); }
inline QString javascriptLiteral() { return QStringLiteral("javascript"); }
inline QString directoryLiteral() { return QStringLiteral("directory"); }
-inline QString componentsLiteral()
-{
- return QStringLiteral("components");
-}
-inline QString scriptsLiteral()
-{
- return QStringLiteral("scripts");
-}
void printUsage(const QString &appNameIn)
{
@@ -158,42 +150,21 @@ QVariantMap pluginsForModulePath(const QString &modulePath) {
QString plugins;
QString classnames;
QStringList dependencies;
- QStringList componentFiles;
- QStringList scriptFiles;
QByteArray line;
do {
line = qmldirFile.readLine();
- const QList<QByteArray> sections = line.split(' ');
- if (sections.size() > 0) {
- const QByteArray &sectionType = sections.at(0);
- if (sectionType == "plugin") {
- plugins += QString::fromUtf8(line.split(' ').at(1));
- plugins += QLatin1Char(' ');
- } else if (sectionType == "classname") {
- classnames += QString::fromUtf8(line.split(' ').at(1));
- classnames += QLatin1Char(' ');
- } else if (sectionType == "depends") {
- if (sections.size() != 3)
- std::cerr << "depends: expected 2 arguments: module identifier and version"
- << std::endl;
- else
- dependencies << QString::fromUtf8(sections.at(1)) + QLatin1Char(' ')
- + QString::fromUtf8(sections.at(2)).simplified();
- } else if (sections.size() == 2 && sectionType != "module"
- && sectionType != "typeinfo") {
- componentFiles.append(modulePath + QLatin1Char('/')
- + QString::fromUtf8(sections.at(1)).trimmed());
- } else if (sections.size() == 3
- || (sectionType == "singleton" && sections.size() == 4)) {
- int fileNameIndex = (sectionType == "singleton") ? 3 : 2;
- const QString fileName = QString::fromUtf8(sections.at(fileNameIndex)).trimmed();
- const QString filePath = modulePath + QLatin1Char('/') + fileName;
- if (fileName.endsWith(QLatin1String(".js"))
- || fileName.endsWith(QLatin1String(".mjs")))
- scriptFiles.append(filePath);
- else
- componentFiles.append(filePath);
- }
+ if (line.startsWith("plugin")) {
+ plugins += QString::fromUtf8(line.split(' ').at(1));
+ plugins += QLatin1Char(' ');
+ } else if (line.startsWith("classname")) {
+ classnames += QString::fromUtf8(line.split(' ').at(1));
+ classnames += QLatin1Char(' ');
+ } else if (line.startsWith("depends")) {
+ const QList<QByteArray> dep = line.split(' ');
+ if (dep.length() != 3)
+ std::cerr << "depends: expected 2 arguments: module identifier and version" << std::endl;
+ else
+ dependencies << QString::fromUtf8(dep[1]) + QLatin1Char(' ') + QString::fromUtf8(dep[2]).simplified();
}
} while (line.length() > 0);
@@ -202,12 +173,7 @@ QVariantMap pluginsForModulePath(const QString &modulePath) {
pluginInfo[pluginsLiteral()] = plugins.simplified();
pluginInfo[classnamesLiteral()] = classnames.simplified();
if (dependencies.length())
- dependencies.removeDuplicates();
pluginInfo[dependenciesLiteral()] = dependencies;
- if (!componentFiles.isEmpty())
- pluginInfo[componentsLiteral()] = componentFiles;
- if (!scriptFiles.isEmpty())
- pluginInfo[scriptsLiteral()] = scriptFiles;
return pluginInfo;
}
@@ -281,8 +247,6 @@ QVariantList findPathsForModuleImports(const QVariantList &imports)
QVariantMap plugininfo = pluginsForModulePath(import.value(pathLiteral()).toString());
QString plugins = plugininfo.value(pluginsLiteral()).toString();
QString classnames = plugininfo.value(classnamesLiteral()).toString();
- QStringList components = plugininfo.value(componentsLiteral()).toStringList();
- QStringList scripts = plugininfo.value(scriptsLiteral()).toStringList();
if (!plugins.isEmpty())
import.insert(QStringLiteral("plugin"), plugins);
if (!classnames.isEmpty())
@@ -298,12 +262,6 @@ QVariantList findPathsForModuleImports(const QVariantList &imports)
importsCopy.append(depImport);
}
}
- if (!components.isEmpty()) {
- import.insert(componentsLiteral(), components);
- }
- if (!scripts.isEmpty()) {
- import.insert(scriptsLiteral(), scripts);
- }
}
done.append(import);
}