aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--dist/changes-5.12.1032
-rw-r--r--dist/changes-5.12.836
-rw-r--r--dist/changes-5.12.946
-rw-r--r--src/3rdparty/masm/wtf/PageBlock.cpp2
-rw-r--r--src/3rdparty/masm/wtf/PageBlock.h5
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp62
-rw-r--r--src/qml/animations/qanimationgroupjob_p.h3
-rw-r--r--src/qml/animations/qanimationjobutil_p.h4
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp14
-rw-r--r--src/qml/compiler/qv4compileddata.cpp7
-rw-r--r--src/qml/compiler/qv4compiler.cpp23
-rw-r--r--src/qml/doc/snippets/code/backend/main.qml2
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp6
-rw-r--r--src/qml/jit/qv4baselinejit.cpp9
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp2
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp5
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp19
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp15
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4object.cpp2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp2
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4proxy.cpp24
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp2
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp3
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp35
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp5
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp6
-rw-r--r--src/qml/jsruntime/qv4value_p.h2
-rw-r--r--src/qml/memory/qv4mm.cpp13
-rw-r--r--src/qml/qml/qqmlcontext.cpp7
-rw-r--r--src/qml/qml/qqmldirparser_p.h2
-rw-r--r--src/qml/qml/qqmlproperty.cpp4
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp12
-rw-r--r--src/qml/types/qqmllistmodel.cpp8
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp24
-rw-r--r--src/quick/items/qquickitem.cpp15
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp7
-rw-r--r--src/quick/items/qquicklistview.cpp168
-rw-r--r--src/quick/items/qquickmousearea.cpp6
-rw-r--r--src/quick/items/qquickshadereffect.cpp6
-rw-r--r--src/quick/items/qquicktextinput.cpp5
-rw-r--r--src/quick/items/qquickview.cpp54
-rw-r--r--src/quick/items/qquickview_p.h2
-rw-r--r--src/quick/items/qquickwindow.cpp98
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp10
-rw-r--r--src/quick/util/qquickanimation.cpp20
-rw-r--r--src/quick/util/qquickbehavior.cpp2
-rw-r--r--tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp42
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp49
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp10
-rw-r--r--tests/auto/quick/qquickanimations/data/signalorder.qml27
-rw-r--r--tests/auto/quick/qquickanimations/qquickanimations.pro1
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp43
-rw-r--r--tests/auto/quick/qquickbehaviors/data/delete.qml37
-rw-r--r--tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp11
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp82
-rw-r--r--tests/auto/quick/qquickitem2/data/keynavigationtest_repeater.qml37
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp19
-rw-r--r--tests/auto/quick/qquicklistview/data/headerSnapToItem.qml67
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp597
-rw-r--r--tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml36
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp38
-rw-r--r--tests/auto/quick/qquickshadereffect/data/hideParent.qml133
-rw-r--r--tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp14
-rw-r--r--tests/auto/quick/qquicktext/BLACKLIST2
-rw-r--r--tests/auto/quick/qquicktextinput/data/checkCursorDelegateWhenPaddingChanged.qml16
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp30
-rw-r--r--tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in2
-rw-r--r--tools/qmlprofiler/qmlprofilerapplication.cpp4
-rw-r--r--tools/qmlprofiler/qmlprofilerdata.cpp1
79 files changed, 1982 insertions, 188 deletions
diff --git a/.qmake.conf b/.qmake.conf
index 71ee0ceb5a..4feec109d3 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,4 +1,4 @@
load(qt_build_config)
CONFIG += warning_clean
-MODULE_VERSION = 5.12.8
+MODULE_VERSION = 5.12.12
diff --git a/dist/changes-5.12.10 b/dist/changes-5.12.10
new file mode 100644
index 0000000000..2f3bad1943
--- /dev/null
+++ b/dist/changes-5.12.10
@@ -0,0 +1,32 @@
+Qt 5.12.10 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.9.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+ https://doc.qt.io/qt-5.12/index.html
+
+The Qt version 5.12 series is binary compatible with the 5.11.x series.
+Applications compiled for 5.11 will continue to run with 5.12.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+ https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* QtQml *
+****************************************************************************
+
+ - [QTBUG-78044] Fixed an index out of range bug in the interactive mode of
+ qmlprofiler.
+
+****************************************************************************
+* QtQuick *
+****************************************************************************
+
+ - [QTBUG-65170] Fixed a crash when QSGTexture is deleted in rc->endSync().
+
diff --git a/dist/changes-5.12.8 b/dist/changes-5.12.8
new file mode 100644
index 0000000000..b6b5d0f2e1
--- /dev/null
+++ b/dist/changes-5.12.8
@@ -0,0 +1,36 @@
+Qt 5.12.8 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.0 through 5.12.7.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.12 series is binary compatible with the 5.11.x series.
+Applications compiled for 5.11 will continue to run with 5.12.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* QtQml *
+****************************************************************************
+
+ - [QTBUG-48809] Fixed a warning about non-relative paths in qmldir files.
+ We now permit the use of resource urls in qmldir files to allow a plugin
+ to include its .qml files in resources, optionally compiled ahead of time.
+ - [QTBUG-81123] Fixed a crash when objects were deleted from a QML list property.
+
+****************************************************************************
+* QtQuick *
+****************************************************************************
+
+ - [QTBUG-76362] Fixed behavior of ListView with PullBackHeader positioning
+ mode in combination with snapMode.
+ - [QTBUG-64138] Particle effects can now run continuously over longer
+ periods of time.
diff --git a/dist/changes-5.12.9 b/dist/changes-5.12.9
new file mode 100644
index 0000000000..7c705e8fc9
--- /dev/null
+++ b/dist/changes-5.12.9
@@ -0,0 +1,46 @@
+Qt 5.12.9 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.0 through 5.12.8.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.12 series is binary compatible with the 5.11.x series.
+Applications compiled for 5.11 will continue to run with 5.12.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* QtQml *
+****************************************************************************
+
+ - [Coverity 175402] Refactored some code so that Coverity and future human
+ readers can understand it.
+ - [Coverity 190701] Standardized QV4_SHOW_BYTECODE output for JS classes.
+ - [Coverity 193545] Fixed a dangling pointer dereference when getting
+ QML property values from dynamic accessors.
+ - [QTBUG-81581][QTBUG-83384] Fixed various crashes related to the JavaScript
+ accumulator register.
+ - JavaScript's isSafeInteger() covers a sensible range now. Before it
+ flagged anything greater than 55 as unsafe.
+ - [QTBUG-84095] Fixed a crash on QML context destruction.
+
+****************************************************************************
+* QtQuick *
+****************************************************************************
+
+ - [Coverity 218729] If setting a new root item on QQuickView fails, the
+ old one is no longer deleted.
+ - [QTBUG-73929][QTBUG-82474] Fixed a crash by releasing resources while
+ closing a window.
+ - [QTBUG-40220][QTBUG-83856] Recursive loops caused by items that call
+ polish() within updatePolish() are now detected and terminated earlier.
+ - [QTBUG-55879][QTBUG-79339] Fixed QQuickItem::grabToImage() with
+ QQuickWidget and QQuickRenderControl.
diff --git a/src/3rdparty/masm/wtf/PageBlock.cpp b/src/3rdparty/masm/wtf/PageBlock.cpp
index e715ed262a..bc0e8d6f2d 100644
--- a/src/3rdparty/masm/wtf/PageBlock.cpp
+++ b/src/3rdparty/masm/wtf/PageBlock.cpp
@@ -64,6 +64,7 @@ inline size_t systemPageSize()
#endif
+inline namespace hidden {
size_t pageSize()
{
if (!s_pageSize)
@@ -78,5 +79,6 @@ size_t pageMask()
s_pageMask = ~(pageSize() - 1);
return s_pageMask;
}
+}
} // namespace WTF
diff --git a/src/3rdparty/masm/wtf/PageBlock.h b/src/3rdparty/masm/wtf/PageBlock.h
index 4d408e1c91..9e2e561073 100644
--- a/src/3rdparty/masm/wtf/PageBlock.h
+++ b/src/3rdparty/masm/wtf/PageBlock.h
@@ -28,8 +28,13 @@
namespace WTF {
+// avoid false positive detection by apple
+// by putting the function inside an inline namespace
+// to obtain different name mangling
+inline namespace hidden {
WTF_EXPORT_PRIVATE size_t pageSize();
WTF_EXPORT_PRIVATE size_t pageMask();
+}
inline bool isPageAligned(void* address) { return !(reinterpret_cast<intptr_t>(address) & (pageSize() - 1)); }
inline bool isPageAligned(size_t size) { return !(size & (pageSize() - 1)); }
inline bool isPowerOfTwo(size_t size) { return !(size & (size - 1)); }
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
index 66599561fc..60b3003d0a 100644
--- a/src/qml/animations/qanimationgroupjob.cpp
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -47,9 +47,45 @@ QAnimationGroupJob::QAnimationGroupJob()
m_isGroup = true;
}
+void QAnimationGroupJob::ungroupChild(QAbstractAnimationJob *animation)
+{
+ Q_ASSERT(animation);
+ Q_ASSERT(animation->m_group == this);
+ QAbstractAnimationJob *prev = animation->previousSibling();
+ QAbstractAnimationJob *next = animation->nextSibling();
+
+ if (prev)
+ prev->m_nextSibling = next;
+ else
+ m_firstChild = next;
+
+ if (next)
+ next->m_previousSibling = prev;
+ else
+ m_lastChild = prev;
+
+ animation->m_previousSibling = nullptr;
+ animation->m_nextSibling = nullptr;
+
+ animation->m_group = nullptr;
+}
+
+void QAnimationGroupJob::handleAnimationRemoved(QAbstractAnimationJob *animation)
+{
+ resetUncontrolledAnimationFinishTime(animation);
+ if (!firstChild()) {
+ m_currentTime = 0;
+ stop();
+ }
+}
+
QAnimationGroupJob::~QAnimationGroupJob()
{
- clear();
+ while (QAbstractAnimationJob *animation = firstChild()) {
+ ungroupChild(animation);
+ handleAnimationRemoved(animation);
+ delete animation;
+ }
}
void QAnimationGroupJob::topLevelAnimationLoopChanged()
@@ -96,25 +132,9 @@ void QAnimationGroupJob::prependAnimation(QAbstractAnimationJob *animation)
void QAnimationGroupJob::removeAnimation(QAbstractAnimationJob *animation)
{
- Q_ASSERT(animation);
- Q_ASSERT(animation->m_group == this);
QAbstractAnimationJob *prev = animation->previousSibling();
QAbstractAnimationJob *next = animation->nextSibling();
-
- if (prev)
- prev->m_nextSibling = next;
- else
- m_firstChild = next;
-
- if (next)
- next->m_previousSibling = prev;
- else
- m_lastChild = prev;
-
- animation->m_previousSibling = nullptr;
- animation->m_nextSibling = nullptr;
-
- animation->m_group = nullptr;
+ ungroupChild(animation);
animationRemoved(animation, prev, next);
}
@@ -154,11 +174,7 @@ void QAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *an
void QAnimationGroupJob::animationRemoved(QAbstractAnimationJob* anim, QAbstractAnimationJob* , QAbstractAnimationJob* )
{
- resetUncontrolledAnimationFinishTime(anim);
- if (!firstChild()) {
- m_currentTime = 0;
- stop();
- }
+ handleAnimationRemoved(anim);
}
void QAnimationGroupJob::debugChildren(QDebug d) const
diff --git a/src/qml/animations/qanimationgroupjob_p.h b/src/qml/animations/qanimationgroupjob_p.h
index b01b2f3b36..6a908ccece 100644
--- a/src/qml/animations/qanimationgroupjob_p.h
+++ b/src/qml/animations/qanimationgroupjob_p.h
@@ -91,6 +91,9 @@ protected:
void debugChildren(QDebug d) const;
private:
+ void ungroupChild(QAbstractAnimationJob *animation);
+ void handleAnimationRemoved(QAbstractAnimationJob *animation);
+
//definition
QAbstractAnimationJob *m_firstChild = nullptr;
QAbstractAnimationJob *m_lastChild = nullptr;
diff --git a/src/qml/animations/qanimationjobutil_p.h b/src/qml/animations/qanimationjobutil_p.h
index 83cf3b246f..2b7bda3123 100644
--- a/src/qml/animations/qanimationjobutil_p.h
+++ b/src/qml/animations/qanimationjobutil_p.h
@@ -70,7 +70,7 @@ struct SelfDeletable {
// \param func statements or functions that to be executed under test.
// \param action post process if p was deleted under test.
#define ACTION_IF_DELETED(p, func, action) \
-{ \
+do { \
static_assert(std::is_same<decltype((p)->m_selfDeletable), SelfDeletable>::value, "m_selfDeletable must be SelfDeletable");\
bool *prevWasDeleted = (p)->m_selfDeletable.m_wasDeleted; \
bool wasDeleted = false; \
@@ -82,7 +82,7 @@ struct SelfDeletable {
{action;} \
} \
(p)->m_selfDeletable.m_wasDeleted = prevWasDeleted; \
-}
+} while (false)
#define RETURN_IF_DELETED(func) \
ACTION_IF_DELETED(this, func, return)
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index 22e20d9268..89adf0d64a 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -329,7 +329,7 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
if (m_direction == Forward) {
// set the current animation to be the next one
if (m_currentAnimation->nextSibling())
- setCurrentAnimation(m_currentAnimation->nextSibling());
+ RETURN_IF_DELETED(setCurrentAnimation(m_currentAnimation->nextSibling()));
for (QAbstractAnimationJob *a = animation->nextSibling(); a; a = a->nextSibling()) {
int dur = a->duration();
@@ -344,7 +344,7 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
} else {
// set the current animation to be the previous one
if (m_currentAnimation->previousSibling())
- setCurrentAnimation(m_currentAnimation->previousSibling());
+ RETURN_IF_DELETED(setCurrentAnimation(m_currentAnimation->previousSibling()));
for (QAbstractAnimationJob *a = animation->previousSibling(); a; a = a->previousSibling()) {
int dur = a->duration();
@@ -365,12 +365,12 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
void QSequentialAnimationGroupJob::animationInserted(QAbstractAnimationJob *anim)
{
if (m_currentAnimation == nullptr)
- setCurrentAnimation(firstChild()); // initialize the current animation
+ RETURN_IF_DELETED(setCurrentAnimation(firstChild())); // initialize the current animation
if (m_currentAnimation == anim->nextSibling()
&& m_currentAnimation->currentTime() == 0 && m_currentAnimation->currentLoop() == 0) {
//in this case we simply insert the animation before the current one has actually started
- setCurrentAnimation(anim);
+ RETURN_IF_DELETED(setCurrentAnimation(anim));
}
// TODO
@@ -389,11 +389,11 @@ void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim,
bool removingCurrent = anim == m_currentAnimation;
if (removingCurrent) {
if (next)
- setCurrentAnimation(next); //let's try to take the next one
+ RETURN_IF_DELETED(setCurrentAnimation(next)); //let's try to take the next one
else if (prev)
- setCurrentAnimation(prev);
+ RETURN_IF_DELETED(setCurrentAnimation(prev));
else// case all animations were removed
- setCurrentAnimation(nullptr);
+ RETURN_IF_DELETED(setCurrentAnimation(nullptr));
}
// duration of the previous animations up to the current animation
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 9fb91e9140..adef147ccd 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -62,6 +62,7 @@
#include <QStandardPaths>
#include <QDir>
#include <private/qv4identifiertable_p.h>
+#include <private/qqmltypewrapper_p.h>
#endif
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
@@ -285,7 +286,8 @@ void CompilationUnit::unlink()
if (runtimeLookups) {
for (uint i = 0; i < data->lookupTableSize; ++i) {
QV4::Lookup &l = runtimeLookups[i];
- if (l.getter == QV4::QObjectWrapper::lookupGetter) {
+ if (l.getter == QV4::QObjectWrapper::lookupGetter
+ || l.getter == QQmlTypeWrapper::lookupSingletonProperty) {
if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
pc->release();
} else if (l.getter == QQmlValueTypeWrapper::lookupGetter) {
@@ -293,7 +295,8 @@ void CompilationUnit::unlink()
pc->release();
}
- if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty) {
+ if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
+ || l.qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) {
if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
pc->release();
}
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 4d85f25d4b..9c4f99d93a 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -480,25 +480,26 @@ void QV4::Compiler::JSUnitGenerator::writeClass(char *b, const QV4::Compiler::Cl
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
if (showCode) {
- qDebug() << "=== Class " << stringForIndex(cls->nameIndex) << "static methods" << cls->nStaticMethods << "methods" << cls->nMethods;
+ qDebug() << "=== Class" << stringForIndex(cls->nameIndex) << "static methods"
+ << cls->nStaticMethods << "methods" << cls->nMethods;
qDebug() << " constructor:" << cls->constructorFunction;
- const char *staticString = ": static ";
for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) {
- if (i == cls->nStaticMethods)
- staticString = ": ";
- const char *type;
+ QDebug output = qDebug().nospace();
+ output << " " << i << ": ";
+ if (i < cls->nStaticMethods)
+ output << "static ";
switch (cls->methodTable()[i].type) {
case CompiledData::Method::Getter:
- type = "get "; break;
+ output << "get "; break;
case CompiledData::Method::Setter:
- type = "set "; break;
+ output << "set "; break;
default:
- type = "";
-
+ break;
}
- qDebug() << " " << i << staticString << type << stringForIndex(cls->methodTable()[i].name) << cls->methodTable()[i].function;
+ output << stringForIndex(cls->methodTable()[i].name) << " "
+ << cls->methodTable()[i].function;
}
- qDebug();
+ qDebug().space();
}
}
diff --git a/src/qml/doc/snippets/code/backend/main.qml b/src/qml/doc/snippets/code/backend/main.qml
index fadc9cd768..316dea215e 100644
--- a/src/qml/doc/snippets/code/backend/main.qml
+++ b/src/qml/doc/snippets/code/backend/main.qml
@@ -72,7 +72,7 @@ ApplicationWindow {
placeholderText: qsTr("User name")
anchors.centerIn: parent
- onTextChanged: backend.userName = text
+ onEditingFinished: backend.userName = text
}
//![username_input]
}
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index 73e396890e..c64f1406b5 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -91,6 +91,8 @@ public:
PlatformAssemblerCommon::callRuntime(functionName, funcPtr);
if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator();
+ else if (AccumulatorRegister == ReturnValueRegister)
+ loadUndefined();
}
void saveReturnValueInAccumulator()
@@ -391,6 +393,8 @@ public:
PlatformAssemblerCommon::callRuntime(functionName, funcPtr);
if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator();
+ else if (AccumulatorRegisterValue == ReturnValueRegisterValue)
+ loadUndefined();
}
void saveReturnValueInAccumulator()
@@ -920,7 +924,7 @@ void BaselineAssembler::loadValue(ReturnedValue value)
void BaselineAssembler::storeHeapObject(int reg)
{
- pasm()->storeHeapObject(PlatformAssembler::ReturnValueRegisterValue, regAddr(reg));
+ pasm()->storeHeapObject(PlatformAssembler::AccumulatorRegisterValue, regAddr(reg));
}
void BaselineAssembler::loadImport(int index)
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 51cd15099d..b106d62e8b 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -66,6 +66,8 @@ void BaselineJIT::generate()
labels = collectLabelsInBytecode(code, len);
as->generatePrologue();
+ // Make sure the ACC register is initialized and not clobbered by the caller.
+ as->loadAccumulatorFromFrame();
decode(code, len);
as->generateEpilogue();
@@ -567,10 +569,12 @@ void BaselineJIT::generate_SetException() { as->setException(); }
void BaselineJIT::generate_CreateCallContext()
{
+ as->saveAccumulatorInFrame();
as->prepareCallWithArgCount(1);
as->passCppFrameAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(ExecutionContext::newCallContext, CallResultDestination::Ignore); // keeps result in return value register
+ BASELINEJIT_GENERATE_RUNTIME_CALL(ExecutionContext::newCallContext, CallResultDestination::InAccumulator);
as->storeHeapObject(CallData::Context);
+ as->loadAccumulatorFromFrame();
}
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
@@ -582,9 +586,10 @@ void BaselineJIT::generate_PushWithContext()
as->prepareCallWithArgCount(2);
as->passJSSlotAsArg(0, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_createWithContext, CallResultDestination::Ignore); // keeps result in return value register
+ BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_createWithContext, CallResultDestination::InAccumulator);
as->checkException();
as->storeHeapObject(CallData::Context);
+ as->loadAccumulatorFromFrame();
}
void BaselineJIT::generate_PushBlockContext(int index)
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 654d33b8d1..ba62f078f0 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -654,6 +654,8 @@ bool ArrayElementLessThan::operator()(Value v1, Value v2) const
jsCallData->args[0] = v1;
jsCallData->args[1] = v2;
result = o->call(jsCallData);
+ if (scope.hasException())
+ return false;
return result->toNumber() < 0;
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index b5b421fa39..b67eceb7f7 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -361,7 +361,7 @@ ReturnedValue ArrayPrototype::method_toString(const FunctionObject *builtin, con
ScopedString string(scope, scope.engine->newString(QStringLiteral("join")));
ScopedFunctionObject f(scope, that->get(string));
if (f)
- return f->call(that, argv, argc);
+ return checkedResult(scope.engine, f->call(that, argv, argc));
return ObjectPrototype::method_toString(builtin, that, argv, argc);
}
@@ -1209,6 +1209,7 @@ ReturnedValue ArrayPrototype::method_every(const FunctionObject *b, const Value
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
r = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
ok = r->toBoolean();
}
return Encode(ok);
@@ -1276,6 +1277,7 @@ ReturnedValue ArrayPrototype::method_some(const FunctionObject *b, const Value *
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
result = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (result->toBoolean())
return Encode(true);
}
@@ -1345,6 +1347,7 @@ ReturnedValue ArrayPrototype::method_map(const FunctionObject *b, const Value *t
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
mapped = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
a->arraySet(k, mapped);
}
return a.asReturnedValue();
@@ -1380,6 +1383,7 @@ ReturnedValue ArrayPrototype::method_filter(const FunctionObject *b, const Value
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
selected = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (selected->toBoolean()) {
a->arraySet(to, arguments[0]);
++to;
@@ -1430,6 +1434,7 @@ ReturnedValue ArrayPrototype::method_reduce(const FunctionObject *b, const Value
arguments[2] = Value::fromDouble(k);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
++k;
}
@@ -1483,6 +1488,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(const FunctionObject *b, const
arguments[2] = Value::fromDouble(k - 1);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
--k;
}
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index a13fb37a52..f643a1180f 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -1547,7 +1547,7 @@ ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value
if (!toIso)
return v4->throwTypeError();
- return toIso->call(O, nullptr, 0);
+ return checkedResult(v4, toIso->call(O, nullptr, 0));
}
ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index f9747207db..a4831422d3 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1090,8 +1090,11 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
void ExecutionEngine::markObjects(MarkStack *markStack)
{
for (int i = 0; i < NClasses; ++i)
- if (classes[i])
+ if (classes[i]) {
classes[i]->mark(markStack);
+ if (markStack->top >= markStack->limit)
+ markStack->drain();
+ }
markStack->drain();
identifierTable->markObjects(markStack);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 41a21ba379..fbc7897c67 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -357,7 +357,7 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
return v4->throwTypeError();
thisObject = argc ? argv : nullptr;
if (argc < 2 || argv[1].isNullOrUndefined())
- return f->call(thisObject, argv, 0);
+ return checkedResult(v4, f->call(thisObject, argv, 0));
Object *arr = argv[1].objectValue();
if (!arr)
@@ -391,13 +391,14 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
}
}
- return f->call(thisObject, arguments, len);
+ return checkedResult(v4, f->call(thisObject, arguments, len));
}
ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
+ QV4::ExecutionEngine *v4 = b->engine();
if (!thisObject->isFunctionObject())
- return b->engine()->throwTypeError();
+ return v4->throwTypeError();
const FunctionObject *f = static_cast<const FunctionObject *>(thisObject);
@@ -406,7 +407,7 @@ ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const
++argv;
--argc;
}
- return f->call(thisObject, argv, argc);
+ return checkedResult(v4, f->call(thisObject, argv, argc));
}
ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
@@ -706,12 +707,12 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject
ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc)
{
- const BoundFunction *f = static_cast<const BoundFunction *>(fo);
- Scope scope(f->engine());
-
- if (scope.hasException())
+ QV4::ExecutionEngine *v4 = fo->engine();
+ if (v4->hasException)
return Encode::undefined();
+ const BoundFunction *f = static_cast<const BoundFunction *>(fo);
+ Scope scope(v4);
Scoped<MemberData> boundArgs(scope, f->boundArgs());
ScopedFunctionObject target(scope, f->target());
JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc);
@@ -722,7 +723,7 @@ ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *
argp += boundArgs->size();
}
memcpy(argp, argv, argc*sizeof(Value));
- return target->call(jsCallData);
+ return checkedResult(v4, target->call(jsCallData));
}
ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index e03d49c74d..ec250659bc 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -328,6 +328,10 @@ inline bool FunctionObject::isBoundFunction() const
return d()->vtable() == BoundFunction::staticVTable();
}
+inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
+{
+ return v4->hasException ? QV4::Encode::undefined() : result;
+}
}
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index becdc3bc55..107aebc502 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -376,12 +376,12 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc,
if (function->isStrict() || isStrict) {
ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
ScopedValue thisObject(scope, directCall ? scope.engine->currentStackFrame->thisObject() : scope.engine->globalObject->asReturnedValue());
- return e->call(thisObject, nullptr, 0);
+ return checkedResult(v4, e->call(thisObject, nullptr, 0));
}
ScopedValue thisObject(scope, scope.engine->currentStackFrame->thisObject());
- return function->call(thisObject, nullptr, 0, ctx);
+ return checkedResult(v4, function->call(thisObject, nullptr, 0, ctx));
}
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 936c032fad..ce759111f4 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -703,6 +703,8 @@ QString Stringify::Str(const QString &key, const Value &v)
*jsCallData->thisObject = value;
jsCallData->args[0] = v4->newString(key);
value = toJSON->call(jsCallData);
+ if (v4->hasException)
+ return QString();
}
}
@@ -714,6 +716,8 @@ QString Stringify::Str(const QString &key, const Value &v)
jsCallData->args[1] = value;
*jsCallData->thisObject = holder;
value = replacerFunction->call(jsCallData);
+ if (v4->hasException)
+ return QString();
}
o = value->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index f8999342d1..86b96e0e3c 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -304,7 +304,8 @@ ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const V
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterFallback;
@@ -321,7 +322,8 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
return getterTwoClasses(l, engine, object);
}
@@ -341,7 +343,8 @@ ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterFallback;
@@ -386,7 +389,8 @@ ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ &object, nullptr, 0));
}
}
l->getter = getterGeneric;
@@ -424,7 +428,8 @@ ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engi
if (!getter->isFunctionObject()) // ### catch at resolve time
return Encode::undefined();
- return static_cast<const FunctionObject *>(getter)->call(engine->globalObject, nullptr, 0);
+ return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call(
+ engine->globalObject, nullptr, 0));
}
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 13f6912371..0044e0bc68 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -196,7 +196,7 @@ ReturnedValue NumberPrototype::method_isSafeInteger(const FunctionObject *, cons
return Encode(false);
double iv = v.toInteger();
- return Encode(dv == iv && std::fabs(iv) <= (2^53)-1);
+ return Encode(dv == iv && std::fabs(iv) <= (1LL << 53) - 1);
}
ReturnedValue NumberPrototype::method_isNaN(const FunctionObject *, const Value *, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 7dd0a247d6..fa24fde9c2 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -104,7 +104,7 @@ ReturnedValue Object::getValueAccessor(const Value &thisObject, const Value &v,
Scope scope(f->engine());
JSCallData jsCallData(scope);
*jsCallData->thisObject = thisObject;
- return f->call(jsCallData);
+ return checkedResult(scope.engine, f->call(jsCallData));
}
bool Object::putValue(uint memberIndex, PropertyAttributes attrs, const Value &value)
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 6b4c3ba71a..c412f19a0a 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -666,7 +666,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, co
if (!f)
THROW_TYPE_ERROR();
- return f->call(thisObject, argv, argc);
+ return checkedResult(scope.engine, f->call(thisObject, argv, argc));
}
ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 40a0dfaa57..adb440b6a0 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -617,7 +617,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this
}
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
- if (!nextPromise || scope.hasException()) {
+ if (scope.hasException() || !nextPromise) {
ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
@@ -763,7 +763,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi
}
ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1)));
- if (!nextPromise || scope.hasException()) {
+ if (scope.hasException() || !nextPromise) {
ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue));
if (scope.hasException()) {
completion = e->exceptionValue->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp
index 9325e2e53b..8a76ed09fe 100644
--- a/src/qml/jsruntime/qv4proxy.cpp
+++ b/src/qml/jsruntime/qv4proxy.cpp
@@ -96,6 +96,8 @@ ReturnedValue ProxyObject::virtualGet(const Managed *m, PropertyKey id, const Va
cdata.args[2] = *receiver;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return Encode::undefined();
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
if (attributes != Attr_Invalid && !attributes.isConfigurable()) {
@@ -136,7 +138,7 @@ bool ProxyObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Val
cdata.args[3] = *receiver;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- if (!trapResult->toBoolean())
+ if (scope.engine->hasException || !trapResult->toBoolean())
return false;
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
@@ -176,7 +178,7 @@ bool ProxyObject::virtualDeleteProperty(Managed *m, PropertyKey id)
cdata.args[2] = o->d(); // ### fix receiver handling
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- if (!trapResult->toBoolean())
+ if (scope.engine->hasException || !trapResult->toBoolean())
return false;
ScopedProperty targetDesc(scope);
PropertyAttributes attributes = target->getOwnProperty(id, targetDesc);
@@ -211,6 +213,8 @@ bool ProxyObject::virtualHasProperty(const Managed *m, PropertyKey id)
cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return false;
bool result = trapResult->toBoolean();
if (!result) {
ScopedProperty targetDesc(scope);
@@ -251,6 +255,8 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property
cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol();
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return Attr_Invalid;
if (!trapResult->isObject() && !trapResult->isUndefined()) {
scope.engine->throwTypeError();
return Attr_Invalid;
@@ -323,7 +329,7 @@ bool ProxyObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Pro
cdata.args[2] = ObjectPrototype::fromPropertyDescriptor(scope.engine, p, attrs);
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- bool result = trapResult->toBoolean();
+ bool result = !scope.engine->hasException && trapResult->toBoolean();
if (!result)
return false;
@@ -373,6 +379,8 @@ bool ProxyObject::virtualIsExtensible(const Managed *m)
cdata.args[0] = target;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return false;
bool result = trapResult->toBoolean();
if (result != target->isExtensible()) {
scope.engine->throwTypeError();
@@ -404,6 +412,8 @@ bool ProxyObject::virtualPreventExtensions(Managed *m)
cdata.args[0] = target;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return false;
bool result = trapResult->toBoolean();
if (result && target->isExtensible()) {
scope.engine->throwTypeError();
@@ -439,6 +449,8 @@ Heap::Object *ProxyObject::virtualGetPrototypeOf(const Managed *m)
cdata.args[0] = target;
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return nullptr;
if (!trapResult->isNull() && !trapResult->isObject()) {
scope.engine->throwTypeError();
return nullptr;
@@ -482,7 +494,7 @@ bool ProxyObject::virtualSetPrototypeOf(Managed *m, const Object *p)
cdata.args[1] = p ? p->asReturnedValue() : Encode::null();
ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
- bool result = trapResult->toBoolean();
+ bool result = !scope.engine->hasException && trapResult->toBoolean();
if (!result)
return false;
if (!target->isExtensible()) {
@@ -573,6 +585,8 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
JSCallData cdata(scope, 1, nullptr, handler);
cdata.args[0] = target;
ScopedObject trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata));
+ if (scope.engine->hasException)
+ return nullptr;
if (!trapResult) {
scope.engine->throwTypeError();
return nullptr;
@@ -699,7 +713,7 @@ ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Va
if (scope.hasException())
return Encode::undefined();
if (trap->isNullOrUndefined())
- return target->call(thisObject, argv, argc);
+ return checkedResult(scope.engine, target->call(thisObject, argv, argc));
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 63b6435112..917c4d3cb5 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -384,7 +384,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
if (hasProperty)
*hasProperty = true;
- if (property)
+ if (property && result != &local)
*property = result;
return getProperty(engine, object, result);
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index 15dcb602eb..3950fb139e 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -98,7 +98,8 @@ ReturnedValue Reflect::method_apply(const FunctionObject *f, const Value *, cons
if (scope.hasException())
return Encode::undefined();
- return static_cast<const FunctionObject &>(argv[0]).call(&argv[1], arguments.argv, arguments.argc);
+ return checkedResult(scope.engine, static_cast<const FunctionObject &>(argv[0]).call(
+ &argv[1], arguments.argv, arguments.argc));
}
ReturnedValue Reflect::method_construct(const FunctionObject *f, const Value *, const Value *argv, int argc)
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 39a2e96b45..2693384cdb 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -452,6 +452,8 @@ ReturnedValue RegExpPrototype::exec(ExecutionEngine *engine, const Object *o, co
ScopedFunctionObject exec(scope, o->get(key));
if (exec) {
ScopedValue result(scope, exec->call(o, s, 1));
+ if (scope.hasException())
+ RETURN_UNDEFINED();
if (!result->isNull() && !result->isObject())
return scope.engine->throwTypeError();
return result->asReturnedValue();
@@ -708,6 +710,8 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val
cData->args[nCaptures + 1] = Encode(position);
cData->args[nCaptures + 2] = s;
ScopedValue replValue(scope, replaceFunction->call(cData));
+ if (scope.hasException())
+ return Encode::undefined();
replacement = replValue->toQString();
} else {
replacement = RegExp::getSubstitution(matchString->toQString(), s->toQString(), position, cData.args, nCaptures, replaceValue->toQString());
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 6a242ba5f6..57beaa8ccd 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -373,7 +373,7 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val
return engine->throwTypeError();
ScopedValue result(scope, fHasInstance->call(&rval, &lval, 1));
- return Encode(result->toBoolean());
+ return scope.hasException() ? Encode::undefined() : Encode(result->toBoolean());
}
QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -489,6 +489,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const
ScopedValue conv(scope, object->get(meth1));
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
+ if (engine->hasException)
+ return Encode::undefined();
if (result->isPrimitive())
return result->asReturnedValue();
}
@@ -499,6 +501,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const
conv = object->get(meth2);
if (FunctionObject *o = conv->as<FunctionObject>()) {
result = o->call(object, nullptr, 0);
+ if (engine->hasException)
+ return Encode::undefined();
if (result->isPrimitive())
return result->asReturnedValue();
}
@@ -775,6 +779,8 @@ ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &
return engine->throwTypeError();
JSCallData cData(scope, 0, nullptr, o);
ScopedObject it(scope, f->call(cData));
+ if (engine->hasException)
+ return Encode::undefined();
if (!it)
return engine->throwTypeError();
return it->asReturnedValue();
@@ -1321,7 +1327,8 @@ ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint ind
return throwPropertyIsNotAFunctionTypeError(engine, &thisObject,
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
- return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(function).call(
+ &thisObject, argv, argc));
}
ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engine, uint index, Value *argv, int argc)
@@ -1334,7 +1341,8 @@ ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engi
return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
- return static_cast<FunctionObject &>(function).call(thisObject, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(function).call(
+ thisObject, argv, argc));
}
ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Value *argv, int argc)
@@ -1353,7 +1361,7 @@ ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Va
if (function->d() == engine->evalFunction()->d())
return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true);
- return function->call(thisObject, argv, argc);
+ return checkedResult(engine, function->call(thisObject, argv, argc));
}
ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, Value *argv, int argc)
@@ -1371,7 +1379,7 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, V
return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString());
- return f->call(thisObject, argv, argc);
+ return checkedResult(engine, f->call(thisObject, argv, argc));
}
ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)
@@ -1410,7 +1418,7 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base,
return engine->throwTypeError(error);
}
- return f->call(base, argv, argc);
+ return checkedResult(engine, f->call(base, argv, argc));
}
ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)
@@ -1422,7 +1430,7 @@ ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, Value
if (!f.isFunctionObject())
return engine->throwTypeError();
- return static_cast<FunctionObject &>(f).call(base, argv, argc);
+ return checkedResult(engine, static_cast<FunctionObject &>(f).call(base, argv, argc));
}
ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc)
@@ -1439,7 +1447,7 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base,
if (!f)
return engine->throwTypeError();
- return f->call(base, argv, argc);
+ return checkedResult(engine, f->call(base, argv, argc));
}
ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, Value *argv, int argc)
@@ -1447,14 +1455,16 @@ ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &fu
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
Value undef = Value::undefinedValue();
- return static_cast<const FunctionObject &>(func).call(&undef, argv, argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(func).call(
+ &undef, argv, argc));
}
ReturnedValue Runtime::method_callWithReceiver(ExecutionEngine *engine, const Value &func, const Value *thisObject, Value *argv, int argc)
{
if (!func.isFunctionObject())
return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow()));
- return static_cast<const FunctionObject &>(func).call(thisObject, argv, argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(func).call(
+ thisObject, argv, argc));
}
struct CallArgs {
@@ -1508,7 +1518,8 @@ ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Valu
if (engine->hasException)
return Encode::undefined();
- return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc);
+ return checkedResult(engine, static_cast<const FunctionObject &>(function).call(
+ &thisObject, arguments.argv, arguments.argc));
}
ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc)
@@ -1551,7 +1562,7 @@ ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *en
if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()
|| unsigned(argc) > fo.formalParameterCount()) {
// Cannot tailcall, do a normal call:
- return fo.call(&thisObject, argv, argc);
+ return checkedResult(engine, fo.call(&thisObject, argv, argc));
}
memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 1eef12a491..e01aadb5cf 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -440,6 +440,8 @@ public:
argv[0] = convertElementToValue(m_v4, lhs);
argv[1] = convertElementToValue(m_v4, rhs);
QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2));
+ if (scope.engine->hasException)
+ return false;
return result->toNumber() < 0;
}
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 6afa6d36d6..43185db676 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -570,7 +570,7 @@ ReturnedValue StringPrototype::method_match(const FunctionObject *b, const Value
ScopedFunctionObject fo(scope, f);
if (!fo)
return scope.engine->throwTypeError();
- return fo->call(r, thisObject, 1);
+ return checkedResult(scope.engine, fo->call(r, thisObject, 1));
}
}
@@ -590,7 +590,7 @@ ReturnedValue StringPrototype::method_match(const FunctionObject *b, const Value
ScopedFunctionObject match(scope, that->get(scope.engine->symbol_match()));
if (!match)
return scope.engine->throwTypeError();
- return match->call(that, s, 1);
+ return checkedResult(scope.engine, match->call(that, s, 1));
}
ReturnedValue StringPrototype::method_normalize(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
@@ -861,6 +861,7 @@ ReturnedValue StringPrototype::method_replace(const FunctionObject *b, const Val
Value that = Value::undefinedValue();
replacement = searchCallback->call(&that, arguments, numCaptures + 2);
+ CHECK_EXCEPTION();
result += string.midRef(lastEnd, matchStart - lastEnd);
result += replacement->toQString();
lastEnd = matchEnd;
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index faf7934c06..e1ef19e42b 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -765,6 +765,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_every(const FunctionObject *b
arguments[1] = Value::fromDouble(k);
arguments[2] = v;
r = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
ok = r->toBoolean();
}
return Encode(ok);
@@ -864,6 +865,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_filter(const FunctionObject *
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
selected = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (selected->toBoolean()) {
++arguments;
scope.alloc(1);
@@ -1203,6 +1205,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_map(const FunctionObject *b,
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
mapped = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
a->put(k, mapped);
}
return a->asReturnedValue();
@@ -1252,6 +1255,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduce(const FunctionObject *
arguments[2] = Value::fromDouble(k);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
++k;
}
@@ -1307,6 +1311,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduceRight(const FunctionObj
arguments[2] = Value::fromDouble(k - 1);
arguments[3] = instance;
acc = callback->call(nullptr, arguments, 4);
+ CHECK_EXCEPTION();
}
--k;
}
@@ -1368,6 +1373,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_some(const FunctionObject *b,
arguments[1] = Value::fromDouble(k);
arguments[2] = instance;
result = callback->call(that, arguments, 3);
+ CHECK_EXCEPTION();
if (result->toBoolean())
return Encode(true);
}
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index ce85e48b72..128ae3528d 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -869,6 +869,8 @@ struct ValueArray {
} else {
while (v < end) {
v->mark(markStack);
+ if (markStack->top >= markStack->limit)
+ markStack->drain();
++v;
}
}
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index cac68bdcaf..7286b0ad27 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -473,12 +473,15 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
uint freeStart = i*Bits + index;
usedSlots &= ~((static_cast<quintptr>(1) << index) - 1);
while (!usedSlots) {
- ++i;
- if (i == EntriesInBitmap) {
- usedSlots = (quintptr)-1;
+ if (++i < EntriesInBitmap) {
+ usedSlots = (objectBitmap[i]|extendsBitmap[i]);
+ } else {
+ Q_ASSERT(i == EntriesInBitmap);
+ // Overflows to 0 when counting trailing zeroes above in next iteration.
+ // Then, all the bits are zeroes and we break.
+ usedSlots = std::numeric_limits<quintptr>::max();
break;
}
- usedSlots = (objectBitmap[i]|extendsBitmap[i]);
#ifndef QT_NO_DEBUG
allocatedSlots += qPopulationCount(usedSlots);
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
@@ -1209,6 +1212,8 @@ void MemoryManager::collectFromJSStack(MarkStack *markStack) const
Q_ASSERT(m->inUse());
// Skip pointers to already freed objects, they are bogus as well
m->mark(markStack);
+ if (markStack->top >= markStack->limit)
+ markStack->drain();
}
++v;
}
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 3710cee162..66ba6fdaf3 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -51,6 +51,7 @@
#include <qjsengine.h>
#include <QtCore/qvarlengtharray.h>
#include <private/qmetaobject_p.h>
+#include <QtQml/private/qqmlcontext_p.h>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
@@ -562,8 +563,8 @@ void QQmlContextData::emitDestruction()
emit a->destruction();
}
- QQmlContextData * child = childContexts;
- while (child) {
+ QQmlContextDataRef child = childContexts;
+ while (!child.isNull()) {
child->emitDestruction();
child = child->nextChild;
}
@@ -625,12 +626,12 @@ void QQmlContextData::clearContext()
void QQmlContextData::destroy()
{
Q_ASSERT(refCount == 0);
- linkedContext = nullptr;
// avoid recursion
++refCount;
if (engine)
invalidate();
+ linkedContext = nullptr;
Q_ASSERT(refCount == 1);
clearContext();
diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h
index bfb75d0509..637852091f 100644
--- a/src/qml/qml/qqmldirparser_p.h
+++ b/src/qml/qml/qqmldirparser_p.h
@@ -78,7 +78,7 @@ public:
static void checkNonRelative(const char *item, const QString &typeName, const QString &fileName)
{
- if (fileName.startsWith(QLatin1Char('/')) || fileName.contains(QLatin1Char(':'))) {
+ if (fileName.startsWith(QLatin1Char('/'))) {
qWarning() << item << typeName
<< "is specified with non-relative URL" << fileName << "in a qmldir file."
<< "URLs in qmldir files should be relative to the qmldir file's directory.";
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index c8166695ba..6f1994bfce 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -907,6 +907,8 @@ QQmlPropertyPrivate::signalExpression(const QQmlProperty &that)
if (!(that.type() & QQmlProperty::SignalProperty))
return nullptr;
+ if (!that.d->object)
+ return nullptr;
QQmlData *data = QQmlData::get(that.d->object);
if (!data)
return nullptr;
@@ -946,6 +948,8 @@ void QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that,
return;
}
+ if (!that.d->object)
+ return;
QQmlData *data = QQmlData::get(that.d->object, nullptr != expr);
if (!data)
return;
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index b22d1530e2..5d7a2130b2 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -192,7 +192,11 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj
r->d()->object = object;
r->d()->property = property;
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
+ auto valueType = QQmlValueTypeFactory::valueType(typeId);
+ if (!valueType) {
+ return engine->throwTypeError(QString::fromLatin1("Type %1 is not a value type").arg(QString::fromLocal8Bit(QMetaType::typeName(typeId))));
+ }
+ r->d()->valueType = valueType;
r->d()->gadgetPtr = nullptr;
return r->asReturnedValue();
}
@@ -204,7 +208,11 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria
Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocate<QQmlValueTypeWrapper>());
r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject));
- r->d()->valueType = QQmlValueTypeFactory::valueType(typeId);
+ auto valueType = QQmlValueTypeFactory::valueType(typeId);
+ if (!valueType) {
+ return engine->throwTypeError(QString::fromLatin1("Type %1 is not a value type").arg(QString::fromLocal8Bit(QMetaType::typeName(typeId))));
+ }
+ r->d()->valueType = valueType;
r->d()->gadgetPtr = nullptr;
r->d()->setValue(value);
return r->asReturnedValue();
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 69b7876cf6..ff2a783dcd 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -2780,10 +2780,12 @@ bool QQmlListModelParser::applyProperty(const QQmlRefPointer<QV4::CompiledData::
QV4::ScopedContext context(scope, QV4::QmlContext::create(v4->rootContext(), QQmlContextData::get(qmlContext(model->m_modelCache)), nullptr));
QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(context, compilationUnit->runtimeFunctions[id]));
- QV4::ReturnedValue result = function->call(v4->globalObject, nullptr, 0);
-
QJSValue v;
- QJSValuePrivate::setValue(&v, v4, result);
+ QV4::ScopedValue result(scope, function->call(v4->globalObject, nullptr, 0));
+ if (v4->hasException)
+ v4->catchException();
+ else
+ QJSValuePrivate::setValue(&v, v4, result->asReturnedValue());
value.setValue<QJSValue>(v);
} else {
QByteArray script = scriptStr.toUtf8();
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index dc1a9a92f9..186ee06b28 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -84,7 +84,14 @@ Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
\image touchpoints-pinchhandler.png
- \sa PinchArea
+ \note The pinch begins when the number of fingers pressed is between
+ \l {MultiPointHandler::minimumPointCount}{minimumPointCount} and
+ \l {MultiPointHandler::maximumPointCount}{maximumPointCount}, inclusive.
+ Until then, PinchHandler tracks the positions of any pressed fingers,
+ but if it's a disallowed number, it does not scale or rotate
+ its \l target, and the \l active property remains \c false.
+
+ \sa PinchArea, QPointerEvent::pointCount()
*/
QQuickPinchHandler::QQuickPinchHandler(QQuickItem *parent)
@@ -248,19 +255,12 @@ bool QQuickPinchHandler::wantsPointerEvent(QQuickPointerEvent *event)
*/
/*!
- \qmlproperty int QtQuick::PinchHandler::minimumTouchPoints
-
- The pinch begins when this number of fingers are pressed.
- Until then, PinchHandler tracks the positions of any pressed fingers,
- but if it's an insufficient number, it does not scale or rotate
- its \l target, and the \l active property will remain false.
-*/
-
-/*!
\qmlproperty bool QtQuick::PinchHandler::active
- This property is true when all the constraints (epecially \l minimumTouchPoints)
- are satisfied and the \l target, if any, is being manipulated.
+ This property is \c true when all the constraints (epecially
+ \l {MultiPointHandler::minimumPointCount}{minimumPointCount} and
+ \l {MultiPointHandler::maximumPointCount}{maximumPointCount}) are satisfied
+ and the \l target, if any, is being manipulated.
*/
void QQuickPinchHandler::onActiveChanged()
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 9e32ccfee9..a403b393a3 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -464,8 +464,8 @@ void QQuickKeyNavigationAttached::setLeft(QQuickItem *i)
Q_D(QQuickKeyNavigationAttached);
if (d->leftSet && d->left == i)
return;
+ d->leftSet = d->left != i;
d->left = i;
- d->leftSet = true;
QQuickKeyNavigationAttached* other =
qobject_cast<QQuickKeyNavigationAttached*>(qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(i));
if (other && !other->d_func()->rightSet){
@@ -486,8 +486,8 @@ void QQuickKeyNavigationAttached::setRight(QQuickItem *i)
Q_D(QQuickKeyNavigationAttached);
if (d->rightSet && d->right == i)
return;
+ d->rightSet = d->right != i;
d->right = i;
- d->rightSet = true;
QQuickKeyNavigationAttached* other =
qobject_cast<QQuickKeyNavigationAttached*>(qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(i));
if (other && !other->d_func()->leftSet){
@@ -508,8 +508,8 @@ void QQuickKeyNavigationAttached::setUp(QQuickItem *i)
Q_D(QQuickKeyNavigationAttached);
if (d->upSet && d->up == i)
return;
+ d->upSet = d->up != i;
d->up = i;
- d->upSet = true;
QQuickKeyNavigationAttached* other =
qobject_cast<QQuickKeyNavigationAttached*>(qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(i));
if (other && !other->d_func()->downSet){
@@ -530,8 +530,8 @@ void QQuickKeyNavigationAttached::setDown(QQuickItem *i)
Q_D(QQuickKeyNavigationAttached);
if (d->downSet && d->down == i)
return;
+ d->downSet = d->down != i;
d->down = i;
- d->downSet = true;
QQuickKeyNavigationAttached* other =
qobject_cast<QQuickKeyNavigationAttached*>(qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(i));
if (other && !other->d_func()->upSet) {
@@ -552,8 +552,8 @@ void QQuickKeyNavigationAttached::setTab(QQuickItem *i)
Q_D(QQuickKeyNavigationAttached);
if (d->tabSet && d->tab == i)
return;
+ d->tabSet = d->tab != i;
d->tab = i;
- d->tabSet = true;
QQuickKeyNavigationAttached* other =
qobject_cast<QQuickKeyNavigationAttached*>(qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(i));
if (other && !other->d_func()->backtabSet) {
@@ -574,8 +574,8 @@ void QQuickKeyNavigationAttached::setBacktab(QQuickItem *i)
Q_D(QQuickKeyNavigationAttached);
if (d->backtabSet && d->backtab == i)
return;
+ d->backtabSet = d->backtab != i;
d->backtab = i;
- d->backtabSet = true;
QQuickKeyNavigationAttached* other =
qobject_cast<QQuickKeyNavigationAttached*>(qmlAttachedPropertiesObject<QQuickKeyNavigationAttached>(i));
if (other && !other->d_func()->tabSet) {
@@ -3753,6 +3753,9 @@ QList<QQuickItem *> QQuickItem::childItems() const
as the painting of its children, to its bounding rectangle. If you set
clipping during an item's paint operation, remember to re-set it to
prevent clipping the rest of your scene.
+
+ \note Clipping can affect rendering performance. See \l {Clipping} for more
+ information.
*/
bool QQuickItem::clip() const
{
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index f298803c7f..9631eb7bf3 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -40,6 +40,7 @@
#include <private/qtquickglobal_p.h>
#include "qquickitemgrabresult.h"
+#include "qquickrendercontrol.h"
#include "qquickwindow.h"
#include "qquickitem.h"
#if QT_CONFIG(quick_shadereffect)
@@ -291,7 +292,11 @@ QQuickItemGrabResult *QQuickItemGrabResultPrivate::create(QQuickItem *item, cons
return nullptr;
}
- if (!item->window()->isVisible()) {
+ QWindow *effectiveWindow = item->window();
+ if (QWindow *renderWindow = QQuickRenderControl::renderWindowFor(item->window()))
+ effectiveWindow = renderWindow;
+
+ if (!effectiveWindow->isVisible()) {
qmlWarning(item) << "grabToImage: item's window is not visible";
return nullptr;
}
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index c4c22526f3..7ff39b1d88 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -138,6 +138,8 @@ public:
bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QQuickTimeLineCallback::Callback fixupCallback, qreal velocity) override;
+ void fixupHeader();
+ void fixupHeaderCompleted();
QQuickListView::Orientation orient;
qreal visiblePos;
qreal averageSize;
@@ -166,6 +168,12 @@ public:
QString nextSection;
qreal overshootDist;
+
+ qreal desiredViewportPosition;
+ qreal fixupHeaderPosition;
+ bool headerNeedsSeparateFixup : 1;
+ bool desiredHeaderVisible : 1;
+
bool correctFlick : 1;
bool inFlickCorrection : 1;
@@ -179,7 +187,9 @@ public:
, highlightPosAnimator(nullptr), highlightWidthAnimator(nullptr), highlightHeightAnimator(nullptr)
, highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
, sectionCriteria(nullptr), currentSectionItem(nullptr), nextSectionItem(nullptr)
- , overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
+ , overshootDist(0.0), desiredViewportPosition(0.0), fixupHeaderPosition(0.0)
+ , headerNeedsSeparateFixup(false), desiredHeaderVisible(false)
+ , correctFlick(false), inFlickCorrection(false)
{
highlightMoveDuration = -1; //override default value set in base class
}
@@ -1387,6 +1397,31 @@ void QQuickListViewPrivate::updateFooter()
emit q->footerItemChanged();
}
+void QQuickListViewPrivate::fixupHeaderCompleted()
+{
+ headerNeedsSeparateFixup = false;
+ QObjectPrivate::disconnect(&timeline, &QQuickTimeLine::updated, this, &QQuickListViewPrivate::fixupHeader);
+}
+
+void QQuickListViewPrivate::fixupHeader()
+{
+ FxListItemSG *listItem = static_cast<FxListItemSG*>(header);
+ const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp;
+ if (fixingUp && headerPositioning == QQuickListView::PullBackHeader && visibleItems.count()) {
+ int fixupDura = timeline.duration();
+ if (fixupDura < 0)
+ fixupDura = fixupDuration/2;
+ const int t = timeline.time();
+
+ const qreal progress = qreal(t)/fixupDura;
+ const qreal ultimateHeaderPosition = desiredHeaderVisible ? desiredViewportPosition : desiredViewportPosition - headerSize();
+ const qreal headerPosition = fixupHeaderPosition * (1 - progress) + ultimateHeaderPosition * progress;
+ const qreal viewPos = isContentFlowReversed() ? -position() - size() : position();
+ const qreal clampedPos = qBound(originPosition() - headerSize(), headerPosition, lastPosition() - size());
+ listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos));
+ }
+}
+
void QQuickListViewPrivate::updateHeader()
{
Q_Q(QQuickListView);
@@ -1404,9 +1439,14 @@ void QQuickListViewPrivate::updateHeader()
if (headerPositioning == QQuickListView::OverlayHeader) {
listItem->setPosition(isContentFlowReversed() ? -position() - size() : position());
} else if (visibleItems.count()) {
+ const bool fixingUp = (orient == QQuickListView::Vertical ? vData : hData).fixingUp;
if (headerPositioning == QQuickListView::PullBackHeader) {
- qreal viewPos = isContentFlowReversed() ? -position() - size() : position();
- qreal clampedPos = qBound(originPosition() - headerSize(), listItem->position(), lastPosition() - headerSize() - size());
+ qreal headerPosition = listItem->position();
+ const qreal viewPos = isContentFlowReversed() ? -position() - size() : position();
+ // Make sure the header is not shown if we absolutely do not have any plans to show it
+ if (fixingUp && !headerNeedsSeparateFixup)
+ headerPosition = viewPos - headerSize();
+ qreal clampedPos = qBound(originPosition() - headerSize(), headerPosition, lastPosition() - size());
listItem->setPosition(qBound(viewPos - headerSize(), clampedPos, viewPos));
} else {
qreal startPos = originPosition();
@@ -1524,13 +1564,46 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
bias = -bias;
tempPosition -= bias;
}
- FxViewItem *topItem = snapItemAt(tempPosition+highlightRangeStart);
+
+ qreal snapOffset = 0;
+ qreal overlayHeaderOffset = 0;
+ bool isHeaderWithinBounds = false;
+ if (header) {
+ qreal visiblePartOfHeader = header->position() + header->size() - tempPosition;
+ isHeaderWithinBounds = visiblePartOfHeader > 0;
+ switch (headerPositioning) {
+ case QQuickListView::OverlayHeader:
+ snapOffset = header->size();
+ overlayHeaderOffset = header->size();
+ break;
+ case QQuickListView::InlineHeader:
+ if (isHeaderWithinBounds && tempPosition < originPosition())
+ // For the inline header, we want to snap to the first item
+ // if we're more than halfway down the inline header.
+ // So if we look for an item halfway down of the header
+ snapOffset = header->size() / 2;
+ break;
+ case QQuickListView::PullBackHeader:
+ desiredHeaderVisible = visiblePartOfHeader > header->size()/2;
+ if (qFuzzyCompare(header->position(), tempPosition)) {
+ // header was pulled down; make sure it remains visible and snap items to bottom of header
+ snapOffset = header->size();
+ } else if (desiredHeaderVisible) {
+ // More than 50% of the header is shown. Show it fully.
+ // Scroll the view so the next item snaps to the header.
+ snapOffset = header->size();
+ overlayHeaderOffset = header->size();
+ }
+ break;
+ }
+ }
+ FxViewItem *topItem = snapItemAt(tempPosition + snapOffset + highlightRangeStart);
if (strictHighlightRange && currentItem && (!topItem || (topItem->index != currentIndex && fixupMode == Immediate))) {
// StrictlyEnforceRange always keeps an item in range
updateHighlight();
topItem = currentItem;
}
- FxViewItem *bottomItem = snapItemAt(tempPosition+highlightRangeEnd);
+ FxViewItem *bottomItem = snapItemAt(tempPosition + snapOffset + highlightRangeEnd);
if (strictHighlightRange && currentItem && (!bottomItem || (bottomItem->index != currentIndex && fixupMode == Immediate))) {
// StrictlyEnforceRange always keeps an item in range
updateHighlight();
@@ -1538,27 +1611,92 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
}
qreal pos;
bool isInBounds = -position() > maxExtent && -position() <= minExtent;
- if (topItem && (isInBounds || strictHighlightRange)) {
- if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
- pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
+
+ if (header && !topItem && isInBounds) {
+ // We are trying to pull back further than needed
+ switch (headerPositioning) {
+ case QQuickListView::OverlayHeader:
+ pos = startPosition() - overlayHeaderOffset;
+ break;
+ case QQuickListView::InlineHeader:
+ pos = isContentFlowReversed() ? header->size() - size() : header->position();
+ break;
+ case QQuickListView::PullBackHeader:
+ pos = isContentFlowReversed() ? -size() : startPosition();
+ break;
+ }
+ } else if (topItem && (isInBounds || strictHighlightRange)) {
+ if (topItem->index == 0 && header && !hasStickyHeader() && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
+ pos = isContentFlowReversed() ? -header->position() + highlightRangeStart - size() : (header->position() - highlightRangeStart + header->size());
} else {
- if (isContentFlowReversed())
- pos = qMax(qMin(-static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size(), -maxExtent), -minExtent);
- else
- pos = qMax(qMin(static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart, -maxExtent), -minExtent);
+ if (header && headerPositioning == QQuickListView::PullBackHeader) {
+ // We pulled down the header. If it isn't pulled all way down, we need to snap
+ // the header.
+ if (qFuzzyCompare(tempPosition, header->position())) {
+ // It is pulled all way down. Scroll-snap the content, but not the header.
+ if (isContentFlowReversed())
+ pos = -static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + snapOffset;
+ else
+ pos = static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - snapOffset;
+ } else {
+ // Header is not pulled all way down, make it completely visible or hide it.
+ // Depends on how much of the header is visible.
+ if (desiredHeaderVisible) {
+ // More than half of the header is visible - show it.
+ // Scroll so that the topItem is aligned to a fully visible header
+ if (isContentFlowReversed())
+ pos = -static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + headerSize();
+ else
+ pos = static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - headerSize();
+ } else {
+ // Less than half is visible - hide the header. Scroll so
+ // that the topItem is aligned to the top of the view
+ if (isContentFlowReversed())
+ pos = -static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size();
+ else
+ pos = static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart;
+ }
+ }
+
+ headerNeedsSeparateFixup = isHeaderWithinBounds || desiredHeaderVisible;
+ if (headerNeedsSeparateFixup) {
+ // We need to animate the header independently if it starts visible or should end as visible,
+ // since the header should not necessarily follow the content.
+ // Store the desired viewport position.
+ // Also store the header position so we know where to animate the header from (fixupHeaderPosition).
+ // We deduce the desired header position from the desiredViewportPosition variable.
+ pos = qBound(-minExtent, pos, -maxExtent);
+ desiredViewportPosition = isContentFlowReversed() ? -pos - size() : pos;
+
+ FxListItemSG *headerItem = static_cast<FxListItemSG*>(header);
+ fixupHeaderPosition = headerItem->position();
+
+ // follow the same fixup timeline
+ QObjectPrivate::connect(&timeline, &QQuickTimeLine::updated, this, &QQuickListViewPrivate::fixupHeader);
+ QObjectPrivate::connect(&timeline, &QQuickTimeLine::completed, this, &QQuickListViewPrivate::fixupHeaderCompleted);
+ }
+ } else if (isContentFlowReversed()) {
+ pos = -static_cast<FxListItemSG*>(topItem)->itemPosition() + highlightRangeStart - size() + overlayHeaderOffset;
+ } else {
+ pos = static_cast<FxListItemSG*>(topItem)->itemPosition() - highlightRangeStart - overlayHeaderOffset;
+ }
}
} else if (bottomItem && isInBounds) {
if (isContentFlowReversed())
- pos = qMax(qMin(-static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size(), -maxExtent), -minExtent);
+ pos = -static_cast<FxListItemSG*>(bottomItem)->itemPosition() + highlightRangeEnd - size() + overlayHeaderOffset;
else
- pos = qMax(qMin(static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd, -maxExtent), -minExtent);
+ pos = static_cast<FxListItemSG*>(bottomItem)->itemPosition() - highlightRangeEnd - overlayHeaderOffset;
} else {
QQuickItemViewPrivate::fixup(data, minExtent, maxExtent);
return;
}
+ pos = qBound(-minExtent, pos, -maxExtent);
qreal dist = qAbs(data.move + pos);
- if (dist > 0) {
+ if (dist >= 0) {
+ // Even if dist == 0 we still start the timeline, because we use the same timeline for
+ // moving the header. And we might need to move the header while the content does not
+ // need moving
timeline.reset(data.move);
if (fixupMode != Immediate) {
timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 5124802dbf..0cdd90d529 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -1079,6 +1079,12 @@ void QQuickMouseArea::itemChange(ItemChange change, const ItemChangeData &value)
}
setHovered(!d->hovered);
}
+ if (d->pressed && (!isVisible())) {
+ // This happens when the mouse area sets itself disabled or hidden
+ // inside the press handler. In that case we should not keep the internal
+ // state as pressed, since we never became the mouse grabber.
+ ungrabMouse();
+ }
break;
default:
break;
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 78458ce6b0..1d931a656f 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -843,7 +843,11 @@ void QQuickShaderEffect::itemChange(ItemChange change, const ItemChangeData &val
return;
}
#endif
- m_impl->handleItemChange(change, value);
+ // It's possible for itemChange to be called during destruction when deleting
+ // the QQuickShaderEffectImpl. We nullify m_impl before deleting it via another pointer
+ // to it, so we must check that it's not null before trying to use it here.
+ if (m_impl)
+ m_impl->handleItemChange(change, value);
QQuickItem::itemChange(change, value);
}
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index aac7137ff3..56ce752987 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -2954,6 +2954,7 @@ void QQuickTextInputPrivate::setTopPadding(qreal value, bool reset)
}
if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
updateLayout();
+ q->updateCursorRectangle();
emit q->topPaddingChanged();
}
}
@@ -2968,6 +2969,7 @@ void QQuickTextInputPrivate::setLeftPadding(qreal value, bool reset)
}
if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
updateLayout();
+ q->updateCursorRectangle();
emit q->leftPaddingChanged();
}
}
@@ -2982,6 +2984,7 @@ void QQuickTextInputPrivate::setRightPadding(qreal value, bool reset)
}
if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
updateLayout();
+ q->updateCursorRectangle();
emit q->rightPaddingChanged();
}
}
@@ -2996,6 +2999,7 @@ void QQuickTextInputPrivate::setBottomPadding(qreal value, bool reset)
}
if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
updateLayout();
+ q->updateCursorRectangle();
emit q->bottomPaddingChanged();
}
}
@@ -4705,6 +4709,7 @@ void QQuickTextInput::setPadding(qreal padding)
d->extra.value().padding = padding;
d->updateLayout();
+ updateCursorRectangle();
emit paddingChanged();
if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
emit topPaddingChanged();
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index c411da9519..70d7f57b81 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -76,7 +76,7 @@ void QQuickViewPrivate::init(QQmlEngine* e)
}
QQuickViewPrivate::QQuickViewPrivate()
- : root(nullptr), component(nullptr), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0)
+ : component(nullptr), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0)
{
}
@@ -92,10 +92,8 @@ void QQuickViewPrivate::execute()
return;
}
- if (root) {
+ if (root)
delete root;
- root = nullptr;
- }
if (component) {
delete component;
component = nullptr;
@@ -212,7 +210,6 @@ QQuickView::~QQuickView()
// be a child of the QQuickViewPrivate, and will be destroyed by its dtor
Q_D(QQuickView);
delete d->root;
- d->root = nullptr;
}
/*!
@@ -263,7 +260,8 @@ void QQuickView::setContent(const QUrl& url, QQmlComponent *component, QObject*
return;
}
- d->setRootObject(item);
+ if (!d->setRootObject(item))
+ delete item;
emit statusChanged(status());
}
@@ -486,43 +484,55 @@ void QQuickView::continueExecute()
return;
}
- d->setRootObject(obj);
+ if (!d->setRootObject(obj))
+ delete obj;
emit statusChanged(status());
}
/*!
\internal
+
+ Sets \a obj as root object and returns true if that operation succeeds.
+ Otherwise returns \c false. If \c false is returned, the root object is
+ \c nullptr afterwards. You can explicitly set the root object to nullptr,
+ and the return value will be \c true.
*/
-void QQuickViewPrivate::setRootObject(QObject *obj)
+bool QQuickViewPrivate::setRootObject(QObject *obj)
{
Q_Q(QQuickView);
if (root == obj)
- return;
+ return true;
+
+ delete root;
+ if (obj == nullptr)
+ return true;
+
if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
root = sgItem;
sgItem->setParentItem(q->QQuickWindow::contentItem());
QQml_setParent_noEvent(sgItem, q->QQuickWindow::contentItem());
- } else if (qobject_cast<QWindow *>(obj)) {
- qWarning() << "QQuickView does not support using windows as a root item." << endl
- << endl
- << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << endl;
- } else {
- qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl
- << endl
- << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl
- << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl;
- delete obj;
- root = nullptr;
- }
- if (root) {
initialSize = rootObjectSize();
if ((resizeMode == QQuickView::SizeViewToRootObject || q->width() <= 1 || q->height() <= 1) &&
initialSize != q->size()) {
q->resize(initialSize);
}
initResize();
+ return true;
+ }
+
+ if (qobject_cast<QWindow *>(obj)) {
+ qWarning() << "QQuickView does not support using a window as a root item." << endl
+ << endl
+ << "If you wish to create your root window from QML, consider using QQmlApplicationEngine instead." << endl;
+ return false;
}
+
+ qWarning() << "QQuickView only supports loading of root objects that derive from QQuickItem." << endl
+ << endl
+ << "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl
+ << "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl;
+ return false;
}
/*!
diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h
index 3f284c0519..75e369411f 100644
--- a/src/quick/items/qquickview_p.h
+++ b/src/quick/items/qquickview_p.h
@@ -91,7 +91,7 @@ public:
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) override;
void initResize();
void updateSize();
- void setRootObject(QObject *);
+ bool setRootObject(QObject *);
void init(QQmlEngine* e = nullptr);
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index c55db04566..3c97475e86 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -70,6 +70,8 @@
#include <QtCore/QLibraryInfo>
#include <QtCore/QRunnable>
#include <QtQml/qqmlincubator.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
@@ -293,6 +295,79 @@ static bool transformDirtyOnItemOrAncestor(const QQuickItem *item)
}
#endif
+/*!
+ * \internal
+
+ A "polish loop" can occur inside QQuickWindowPrivate::polishItems(). It is when an item calls
+ polish() on an(other?) item from updatePolish(). If this anomaly happens repeatedly and without
+ interruption (of a well-behaved updatePolish() that doesn't call polish()), it is a strong
+ indication that we are heading towards an infinite polish loop. A polish loop is not a bug in
+ Qt Quick - it is a bug caused by ill-behaved items put in the scene.
+
+ We can detect this sequence of polish loops easily, since the
+ QQuickWindowPrivate::itemsToPolish is basically a stack: polish() will push to it, and
+ polishItems() will pop from it.
+ Therefore if updatePolish() calls polish(), the immediate next item polishItems() processes is
+ the item that was polished by the previous call to updatePolish().
+ We therefore just need to count the number of polish loops we detected in _sequence_.
+*/
+struct PolishLoopDetector
+{
+ PolishLoopDetector(const QVector<QQuickItem*> &itemsToPolish)
+ : itemsToPolish(itemsToPolish)
+ {
+ }
+
+ /*
+ * returns true when it detected a likely infinite loop
+ * (suggests it should abort the polish loop)
+ **/
+ bool check(QQuickItem *item, int itemsRemainingBeforeUpdatePolish)
+ {
+ if (itemsToPolish.count() > itemsRemainingBeforeUpdatePolish) {
+ // Detected potential polish loop.
+ ++numPolishLoopsInSequence;
+ if (numPolishLoopsInSequence >= 1000) {
+ // Start to warn about polish loop after 1000 consecutive polish loops
+ if (numPolishLoopsInSequence == 100000) {
+ // We have looped 100,000 times without actually reducing the list of items to
+ // polish, give up for now.
+ // This is not a fix, just a remedy so that the application can be somewhat
+ // responsive.
+ numPolishLoopsInSequence = 0;
+ return true;
+ } else if (numPolishLoopsInSequence < 1005) {
+ // Show the 5 next items involved in the polish loop.
+ // (most likely they will be the same 5 items...)
+ QQuickItem *guiltyItem = itemsToPolish.last();
+ qmlWarning(item) << "possible QQuickItem::polish() loop";
+
+ auto typeAndObjectName = [](QQuickItem *item) {
+ QString typeName = QQmlMetaType::prettyTypeName(item);
+ QString objName = item->objectName();
+ if (!objName.isNull())
+ return QString::fromLatin1("%1(%2)").arg(typeName, objName);
+ return typeName;
+ };
+
+ qmlWarning(guiltyItem) << typeAndObjectName(guiltyItem)
+ << " called polish() inside updatePolish() of " << typeAndObjectName(item);
+
+ if (numPolishLoopsInSequence == 1004)
+ // Enough warnings. Reset counter in order to speed things up and re-detect
+ // more loops
+ numPolishLoopsInSequence = 0;
+ }
+ }
+ } else {
+ numPolishLoopsInSequence = 0;
+ }
+ return false;
+ }
+ const QVector<QQuickItem*> &itemsToPolish; // Just a ref to the one in polishItems()
+ int numPolishLoopsInSequence = 0;
+};
+
void QQuickWindowPrivate::polishItems()
{
// An item can trigger polish on another item, or itself for that matter,
@@ -300,20 +375,21 @@ void QQuickWindowPrivate::polishItems()
// iterate through the set, we must continue pulling items out until it
// is empty.
// In the case where polish is called from updatePolish() either directly
- // or indirectly, we use a recursionSafeguard to print a warning to
- // the user.
- int recursionSafeguard = INT_MAX;
- while (!itemsToPolish.isEmpty() && --recursionSafeguard > 0) {
+ // or indirectly, we use a PolishLoopDetector to determine if a warning should
+ // be printed to the user.
+
+ PolishLoopDetector polishLoopDetector(itemsToPolish);
+ while (!itemsToPolish.isEmpty()) {
QQuickItem *item = itemsToPolish.takeLast();
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
itemPrivate->polishScheduled = false;
+ const int itemsRemaining = itemsToPolish.count();
itemPrivate->updatePolish();
item->updatePolish();
+ if (polishLoopDetector.check(item, itemsRemaining) == true)
+ break;
}
- if (recursionSafeguard == 0)
- qWarning("QQuickWindow: possible QQuickItem::polish() loop");
-
#if QT_CONFIG(im)
if (QQuickItem *focusItem = q_func()->activeFocusItem()) {
// If the current focus item, or any of its anchestors, has changed location
@@ -1655,6 +1731,14 @@ bool QQuickWindow::event(QEvent *e)
emit closing(&qev);
e->setAccepted(qev.isAccepted());
} break;
+ case QEvent::PlatformSurface:
+ if ((static_cast<QPlatformSurfaceEvent *>(e))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
+ // Ensure that the rendering thread is notified before
+ // the QPlatformWindow is destroyed.
+ if (d->windowManager)
+ d->windowManager->hide(this);
+ }
+ break;
case QEvent::FocusAboutToChange:
#if QT_CONFIG(im)
if (d->activeFocusItem)
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 2e91bafa7c..28f75b71d6 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -502,10 +502,18 @@ QImage QSGGuiThreadRenderLoop::grab(QQuickWindow *window)
void QSGGuiThreadRenderLoop::maybeUpdate(QQuickWindow *window)
{
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
- if (!cd->isRenderable() || !m_windows.contains(window))
+ if (!m_windows.contains(window))
return;
+ // Even if the window is not renderable,
+ // renderWindow() called on different window
+ // should not delete QSGTexture's
+ // from this unrenderable window.
m_windows[window].updatePending = true;
+
+ if (!cd->isRenderable())
+ return;
+
window->requestUpdate();
}
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 2043b50545..34942bdd9a 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -176,11 +176,8 @@ void QQuickAbstractAnimationPrivate::commence()
animationInstance = new QQuickAnimatorProxyJob(animationInstance, q);
animationInstance->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
}
+ emit q->started();
animationInstance->start();
- if (animationInstance->isStopped()) {
- running = false;
- emit q->stopped();
- }
}
}
@@ -293,10 +290,8 @@ void QQuickAbstractAnimation::setRunning(bool r)
d->animationInstance->setLoopCount(d->animationInstance->currentLoop() + d->loopCount);
supressStart = true; //we want the animation to continue, rather than restart
}
- if (!supressStart) {
+ if (!supressStart)
d->commence();
- emit started();
- }
} else {
if (d->paused) {
d->paused = false; //reset paused state to false when stopped
@@ -314,7 +309,16 @@ void QQuickAbstractAnimation::setRunning(bool r)
}
}
- emit runningChanged(d->running);
+
+ if (r == d->running) {
+ // This might happen if we start an animation with 0 duration: This will result in that
+ // commence() will emit started(), and then when it starts it will call setCurrentTime(0),
+ // (which is both start and end time of the animation), so it will also end up calling
+ // setRunning(false) (recursively) and stop the animation.
+ // Therefore, the state of d->running will in that case be different than r if we are back in
+ // the root stack frame of the recursive calls to setRunning()
+ emit runningChanged(d->running);
+ }
}
/*!
diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp
index d9b13067ad..31c0ecddf6 100644
--- a/src/quick/util/qquickbehavior.cpp
+++ b/src/quick/util/qquickbehavior.cpp
@@ -143,7 +143,7 @@ void QQuickBehavior::setAnimation(QQuickAbstractAnimation *animation)
void QQuickBehaviorPrivate::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState,QAbstractAnimationJob::State)
{
- if (!blockRunningChanged)
+ if (!blockRunningChanged && animation)
animation->notifyRunningChanged(newState == QAbstractAnimationJob::Running);
}
diff --git a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
index 57b0905a8a..150734496e 100644
--- a/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
+++ b/tests/auto/qml/animation/qsequentialanimationgroupjob/tst_qsequentialanimationgroupjob.cpp
@@ -68,6 +68,7 @@ private slots:
void insertAnimation();
void clear();
void pauseResume();
+ void deleteFromListener();
};
void tst_QSequentialAnimationGroupJob::initTestCase()
@@ -126,15 +127,23 @@ protected:
class StateChangeListener: public QAnimationJobChangeListener
{
public:
- virtual void animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState, QAbstractAnimationJob::State)
+ virtual void animationStateChanged(
+ QAbstractAnimationJob *job, QAbstractAnimationJob::State newState,
+ QAbstractAnimationJob::State)
{
states << newState;
+ if (beEvil) {
+ delete job->group();
+ groupDeleted = true;
+ }
}
void clear() { states.clear(); }
int count() const { return states.count(); }
QList<QAbstractAnimationJob::State> states;
+ bool beEvil = false;
+ bool groupDeleted = false;
};
class FinishedListener: public QAnimationJobChangeListener
@@ -1644,6 +1653,37 @@ void tst_QSequentialAnimationGroupJob::uncontrolledWithLoops()
QTRY_COMPARE(group.state(), QAbstractAnimationJob::Stopped);
}
+void tst_QSequentialAnimationGroupJob::deleteFromListener()
+{
+ QSequentialAnimationGroupJob *group = new QSequentialAnimationGroupJob;
+
+ UncontrolledAnimation *uncontrolled = new UncontrolledAnimation();
+ TestAnimation *shortLoop = new TestAnimation(100);
+ UncontrolledAnimation *more = new UncontrolledAnimation();
+
+ shortLoop->setLoopCount(-1);
+
+ group->appendAnimation(uncontrolled);
+ group->appendAnimation(shortLoop);
+ group->appendAnimation(more);
+
+ StateChangeListener listener;
+ listener.beEvil = true;
+ shortLoop->addAnimationChangeListener(&listener, QAbstractAnimationJob::StateChange);
+ group->setLoopCount(2);
+
+ group->start();
+
+ QCOMPARE(group->currentLoop(), 0);
+ QCOMPARE(group->state(), QAbstractAnimationJob::Running);
+ QTRY_COMPARE(uncontrolled->state(), QAbstractAnimationJob::Running);
+
+ QVERIFY(!listener.groupDeleted);
+ uncontrolled->stop();
+
+ QTRY_VERIFY(listener.groupDeleted);
+ // It's dead, Jim.
+}
QTEST_MAIN(tst_QSequentialAnimationGroupJob)
#include "tst_qsequentialanimationgroupjob.moc"
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index dc8ef232c1..da116aaed0 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -374,6 +374,8 @@ private slots:
void getThisObject();
void semicolonAfterProperty();
+ void gcCrashRegressionTest();
+
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
static void verifyContextLifetime(QQmlContextData *ctxt);
@@ -9065,6 +9067,53 @@ void tst_qqmlecmascript::semicolonAfterProperty()
QVERIFY(!test.isNull());
}
+void tst_qqmlecmascript::gcCrashRegressionTest()
+{
+ const QString qmljs = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs";
+ if (!QFile::exists(qmljs)) {
+ QSKIP("Tets requires qmljs");
+ }
+ QProcess process;
+
+ QTemporaryFile infile;
+ QVERIFY(infile.open());
+ infile.write(R"js(
+ function i_want_to_break_free() {
+ var n = 400;
+ var m = 10;
+ var regex = new RegExp("(ab)".repeat(n), "g"); // g flag to trigger the vulnerable path
+ var part = "ab".repeat(n); // matches have to be at least size 2 to prevent interning
+ var s = (part + "|").repeat(m);
+ var cnt = 0;
+ var ary = [];
+ s.replace(regex, function() {
+ for (var i = 1; i < arguments.length-2; ++i) {
+ if (typeof arguments[i] !== 'string') {
+ i_am_free = arguments[i];
+ throw "success";
+ }
+ ary[cnt++] = arguments[i]; // root everything to force GC
+ }
+ return "x";
+ });
+ }
+ try { i_want_to_break_free(); } catch (e) {console.log("hi") }
+ console.log(typeof(i_am_free)); // will print "object"
+ )js");
+ infile.close();
+
+ QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
+ environment.insert("QV4_GC_MAX_STACK_SIZE", "32768");
+
+ process.setProcessEnvironment(environment);
+ process.start(qmljs, QStringList({infile.fileName()}));
+ QVERIFY(process.waitForStarted());
+ const qint64 pid = process.processId();
+ QVERIFY(pid != 0);
+ QVERIFY(process.waitForFinished());
+ QCOMPARE(process.exitCode(), 0);
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 27e06c6f67..1bf044ec32 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -149,6 +149,8 @@ private slots:
void floatToStringPrecision();
void copy();
+
+ void signalExpressionWithoutObject();
private:
QQmlEngine engine;
};
@@ -2106,6 +2108,14 @@ void tst_qqmlproperty::initTestCase()
qmlRegisterType<MyContainer>("Test",1,0,"MyContainer");
}
+void tst_qqmlproperty::signalExpressionWithoutObject()
+{
+ QQmlProperty invalid;
+ QQmlPropertyPrivate::setSignalExpression(invalid, nullptr);
+ QQmlBoundSignalExpression *expr = QQmlPropertyPrivate::signalExpression(invalid);
+ QVERIFY(!expr);
+}
+
QTEST_MAIN(tst_qqmlproperty)
#include "tst_qqmlproperty.moc"
diff --git a/tests/auto/quick/qquickanimations/data/signalorder.qml b/tests/auto/quick/qquickanimations/data/signalorder.qml
new file mode 100644
index 0000000000..35029b0c84
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/signalorder.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.12
+
+
+Item {
+ id: wrapper
+ width: 400; height: 400
+
+ Rectangle {
+ id: greenRect
+ width: 50; height: 50
+ color: "red"
+
+ ColorAnimation on color {
+ id: colorAnimation
+ objectName: "ColorAnimation"
+ to: "green"
+ duration: 10
+ running: false
+ }
+
+ ParallelAnimation {
+ id: parallelAnimation
+ objectName: "ParallelAnimation"
+ running: false
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/qquickanimations.pro b/tests/auto/quick/qquickanimations/qquickanimations.pro
index 1c5494a24a..fa46cb422d 100644
--- a/tests/auto/quick/qquickanimations/qquickanimations.pro
+++ b/tests/auto/quick/qquickanimations/qquickanimations.pro
@@ -64,6 +64,7 @@ OTHER_FILES += \
data/scriptActionCrash.qml \
data/sequentialAnimationNullChildBug.qml \
data/signals.qml \
+ data/signalorder.qml \
data/transitionAssignmentBug.qml \
data/valuesource.qml \
data/valuesource2.qml
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index d9b42bdeb5..e0ce2d7134 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -89,6 +89,8 @@ private slots:
void easingProperties();
void rotation();
void startStopSignals();
+ void signalOrder_data();
+ void signalOrder();
void runningTrueBug();
void nonTransitionBug();
void registrationBug();
@@ -1292,6 +1294,47 @@ void tst_qquickanimations::startStopSignals()
QVERIFY(timer.elapsed() >= 200);
}
+void tst_qquickanimations::signalOrder_data()
+{
+ QTest::addColumn<QByteArray>("animationType");
+ QTest::addColumn<int>("duration");
+
+ QTest::addRow("ColorAnimation, duration = 10") << QByteArray("ColorAnimation") << 10;
+ QTest::addRow("ColorAnimation, duration = 0") << QByteArray("ColorAnimation") << 0;
+ QTest::addRow("ParallelAnimation, duration = 0") << QByteArray("ParallelAnimation") << 0;
+}
+
+void tst_qquickanimations::signalOrder()
+{
+ QFETCH(QByteArray, animationType);
+ QFETCH(int, duration);
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("signalorder.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ auto *root = qobject_cast<QQuickItem *>(obj.data());
+ QVERIFY(root);
+ QQuickAbstractAnimation *animation = root->findChild<QQuickAbstractAnimation*>(animationType);
+ QVector<const char*> actualSignalOrder;
+ connect(animation, &QQuickAbstractAnimation::started , [&actualSignalOrder] () {
+ actualSignalOrder.append("started");
+ });
+ connect(animation, &QQuickAbstractAnimation::stopped , [&actualSignalOrder] () {
+ actualSignalOrder.append("stopped");
+ });
+ connect(animation, &QQuickAbstractAnimation::finished , [&actualSignalOrder] () {
+ actualSignalOrder.append("finished");
+ });
+ QSignalSpy finishedSpy(animation, SIGNAL(finished()));
+ if (QQuickColorAnimation *colorAnimation = qobject_cast<QQuickColorAnimation*>(animation))
+ colorAnimation->setDuration(duration);
+
+ animation->start();
+ QTRY_VERIFY(finishedSpy.count());
+ const QVector<const char*> expectedSignalOrder = { "started", "stopped", "finished" };
+ QCOMPARE(actualSignalOrder, expectedSignalOrder);
+}
+
void tst_qquickanimations::runningTrueBug()
{
//ensure we start correctly when "running: true" is explicitly set
diff --git a/tests/auto/quick/qquickbehaviors/data/delete.qml b/tests/auto/quick/qquickbehaviors/data/delete.qml
new file mode 100644
index 0000000000..1bf0267b84
--- /dev/null
+++ b/tests/auto/quick/qquickbehaviors/data/delete.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.12
+
+Item {
+ visible: true
+ width: 640
+ height: 480
+
+ Component.onCompleted: {
+ myLoader.active = false
+ }
+
+ Loader {
+ id: myLoader
+
+ active: true
+ sourceComponent: Item {
+ width: 100
+ height: 100
+ id: myPopup
+
+ NumberAnimation {
+ id: anim
+ }
+
+ Rectangle {
+ color: "black"
+ Component.onCompleted: {
+ opacity = 20
+ }
+
+ Behavior on opacity {
+ animation: anim
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
index fa9eba095d..8a962ce240 100644
--- a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
+++ b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
@@ -73,6 +73,7 @@ private slots:
void disabledWriteWhileRunning();
void aliasedProperty();
void innerBehaviorOverwritten();
+ void safeToDelete();
};
void tst_qquickbehaviors::simpleBehavior()
@@ -598,6 +599,16 @@ void tst_qquickbehaviors::innerBehaviorOverwritten()
QVERIFY(item->property("behaviorTriggered").toBool());
}
+// QTBUG-76749
+void tst_qquickbehaviors::safeToDelete()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("delete.qml"));
+ QVERIFY(c.create());
+}
+
+
+
QTEST_MAIN(tst_qquickbehaviors)
#include "tst_qquickbehaviors.moc"
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index 7e132f97b6..61b6902b43 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -40,6 +40,7 @@
#include "../../shared/util.h"
#include "../shared/viewtestutil.h"
#include <QSignalSpy>
+#include <QtCore/qregularexpression.h>
#ifdef TEST_QTBUG_60123
#include <QWidget>
@@ -111,10 +112,15 @@ public:
}
bool wasPolished;
+ int repolishLoopCount = 0;
protected:
virtual void updatePolish() {
wasPolished = true;
+ if (repolishLoopCount > 0) {
+ --repolishLoopCount;
+ polish();
+ }
}
public slots:
@@ -197,6 +203,9 @@ private slots:
void qtBug60123();
#endif
+ void polishLoopDetection_data();
+ void polishLoopDetection();
+
private:
enum PaintOrderOp {
@@ -1427,6 +1436,79 @@ void tst_qquickitem::polishOnCompleted()
QTRY_VERIFY(item->wasPolished);
}
+struct PolishItemSpan {
+ int itemCount; // Number of items...
+ int repolishCount; // ...repolishing 'repolishCount' times
+};
+
+/*
+ * For instance, two consecutive spans {99,0} and {1,2000} } instructs to
+ * construct 99 items with no repolish, and 1 item with 2000 repolishes (in that sibling order)
+ */
+typedef QVector<PolishItemSpan> PolishItemSpans;
+
+Q_DECLARE_METATYPE(PolishItemSpan)
+Q_DECLARE_METATYPE(PolishItemSpans)
+
+void tst_qquickitem::polishLoopDetection_data()
+{
+ QTest::addColumn<PolishItemSpans>("listOfItemsToPolish");
+ QTest::addColumn<int>("expectedNumberOfWarnings");
+
+ QTest::newRow("test1.100") << PolishItemSpans({ {1, 100} }) << 0;
+ QTest::newRow("test1.1002") << PolishItemSpans({ {1, 1002} }) << 3;
+ QTest::newRow("test1.2020") << PolishItemSpans({ {1, 2020} }) << 10;
+
+ QTest::newRow("test5.1") << PolishItemSpans({ {5, 1} }) << 0;
+ QTest::newRow("test5.10") << PolishItemSpans({ {5, 10} }) << 0;
+ QTest::newRow("test5.100") << PolishItemSpans({ {5, 100} }) << 0;
+ QTest::newRow("test5.1000") << PolishItemSpans({ {5, 1000} }) << 5;
+
+ QTest::newRow("test1000.1") << PolishItemSpans({ {1000,1} }) << 0;
+ QTest::newRow("test2000.1") << PolishItemSpans({ {2000,1} }) << 0;
+
+ QTest::newRow("test99.0-1.1100") << PolishItemSpans({ {99,0},{1,1100} }) << 5;
+ QTest::newRow("test98.0-2.1100") << PolishItemSpans({ {98,0},{2,1100} }) << 5+5;
+
+ // reverse the two above
+ QTest::newRow("test1.1100-99.0") << PolishItemSpans({ {1,1100},{99,0} }) << 5;
+ QTest::newRow("test2.1100-98.0") << PolishItemSpans({ {2,1100},{98,0} }) << 5+5;
+}
+
+void tst_qquickitem::polishLoopDetection()
+{
+ QFETCH(PolishItemSpans, listOfItemsToPolish);
+ QFETCH(int, expectedNumberOfWarnings);
+
+ QQuickWindow window;
+ window.resize(200, 200);
+ window.show();
+
+ TestPolishItem *item = nullptr;
+ int count = 0;
+ for (PolishItemSpan s : listOfItemsToPolish) {
+ for (int i = 0; i < s.itemCount; ++i) {
+ item = new TestPolishItem(window.contentItem());
+ item->setSize(QSizeF(200, 100));
+ item->repolishLoopCount = s.repolishCount;
+ item->setObjectName(QString::fromLatin1("obj%1").arg(count++));
+ }
+ }
+
+ for (int i = 0; i < expectedNumberOfWarnings; ++i) {
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*possible QQuickItem..polish.. loop.*"));
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*TestPolishItem.* called polish.. inside updatePolish.. of TestPolishItem.*"));
+ }
+
+ QList<QQuickItem*> items = window.contentItem()->childItems();
+ for (int i = 0; i < items.count(); ++i) {
+ static_cast<TestPolishItem*>(items.at(i))->doPolish();
+ }
+ item = static_cast<TestPolishItem*>(items.first());
+ // item is the last item, so we wait until the last item reached 0
+ QVERIFY(QTest::qWaitFor([=](){return item->repolishLoopCount == 0 && item->wasPolished;}));
+}
+
void tst_qquickitem::wheelEvent_data()
{
QTest::addColumn<bool>("visible");
diff --git a/tests/auto/quick/qquickitem2/data/keynavigationtest_repeater.qml b/tests/auto/quick/qquickitem2/data/keynavigationtest_repeater.qml
new file mode 100644
index 0000000000..12ce10e139
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/keynavigationtest_repeater.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.0
+
+Grid {
+ property var textModel: ["1", "2", "3", "4", "5"]
+ columns: 5
+ width: 50*textModel.length
+
+ Repeater {
+ id: repeater
+ model: textModel.length
+ Rectangle {
+ width: 50
+ height: 50
+ color: focus ? "red" : "lightgrey"
+ focus: index == 2
+ Text {
+ id: t
+ text: textModel[index]
+ }
+ KeyNavigation.left: repeater.itemAt(index - 1)
+ KeyNavigation.right: repeater.itemAt(index + 1)
+ }
+ }
+
+ function verify() {
+ for (var i = 0; i < repeater.count; i++) {
+ var item = repeater.itemAt(i);
+ var prev = repeater.itemAt(i - 1);
+ var next = repeater.itemAt(i + 1);
+ if (item.KeyNavigation.left != prev || item.KeyNavigation.right != next)
+ return false;
+ }
+
+ return true;
+ }
+}
+
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 399535cfa6..db473d1ea1 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -89,6 +89,7 @@ private slots:
void keyNavigation_implicitDestroy();
void keyNavigation_focusReason();
void keyNavigation_loop();
+ void keyNavigation_repeater();
void layoutMirroring();
void layoutMirroringWindow();
void layoutMirroringIllegalParent();
@@ -2273,6 +2274,24 @@ void tst_QQuickItem::keyNavigation_loop()
delete window;
}
+void tst_QQuickItem::keyNavigation_repeater()
+{
+ // QTBUG-83356
+ QQuickView *window = new QQuickView(nullptr);
+ window->setBaseSize(QSize(240,320));
+
+ window->setSource(testFileUrl("keynavigationtest_repeater.qml"));
+ window->show();
+ window->requestActivate();
+
+ QVariant result;
+ QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "verify",
+ Q_RETURN_ARG(QVariant, result)));
+ QVERIFY(result.toBool());
+
+ delete window;
+}
+
void tst_QQuickItem::smooth()
{
QQmlComponent component(&engine);
diff --git a/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml b/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml
new file mode 100644
index 0000000000..1e5a811630
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/headerSnapToItem.qml
@@ -0,0 +1,67 @@
+import QtQuick 2.12
+
+Rectangle {
+
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: list.orientation == ListView.Vertical ? 240 : 20
+ height: list.orientation == ListView.Vertical ? 20 : 240
+ border.width: 1
+ border.color: "black"
+ Text {
+ text: index + ":" + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(0)
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ width: 240
+ height: 200
+ clip: true
+ snapMode: ListView.SnapToItem
+ headerPositioning: ListView.OverlayHeader
+ model: 30
+ delegate: myDelegate
+ orientation: ListView.Vertical
+ verticalLayoutDirection: ListView.BottomToTop
+
+ header: Rectangle {
+ width: list.orientation == Qt.Vertical ? 240 : 30
+ height: list.orientation == Qt.Vertical ? 30 : 240
+ objectName: "header";
+ color: "green"
+ z: 11
+ Text {
+ anchors.centerIn: parent
+ text: "header " + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(1)
+ }
+ }
+ }
+
+ Rectangle {
+ color: "red"
+ opacity: 0.5
+ width: txt.implicitWidth + 50
+ height: txt.implicitHeight
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+
+ Text {
+ id: txt
+ anchors.centerIn: parent
+ text: "header position: " + (list.orientation == ListView.Vertical ? list.headerItem.y : list.headerItem.x).toFixed(1)
+ + "\ncontent position: " + (list.orientation == ListView.Vertical ? list.contentY : list.contentX).toFixed(1)
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 25212b06f6..be3f2601d6 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -30,6 +30,7 @@
#include <QtCore/QStringListModel>
#include <QtCore/QSortFilterProxyModel>
#include <QtGui/QStandardItemModel>
+#include <QtGui/QStyleHints>
#include <QtQuick/qquickview.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
@@ -181,6 +182,8 @@ private slots:
void creationContext();
void snapToItem_data();
void snapToItem();
+ void headerSnapToItem_data();
+ void headerSnapToItem();
void snapToItemWithSpacing_QTBUG_59852();
void snapOneItemResize_QTBUG_43555();
void snapOneItem_data();
@@ -5364,6 +5367,600 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852()
releaseView(window);
}
+static void drag_helper(QWindow *window, QPoint *startPos, const QPoint &delta)
+{
+ QPoint pos = *startPos;
+ int dragDistance = delta.manhattanLength();
+ Q_ASSERT(qAbs(delta.x()) >= 1 || qAbs(delta.y()) >= 1);
+
+ const int stepSize = 8;
+ QPoint unitVector(0, 0);
+ if (delta.x())
+ unitVector.setX(qBound(-1, delta.x(), 1));
+ if (delta.y())
+ unitVector.setY(qBound(-1, delta.y(), 1));
+ QPoint dragStepSize = unitVector * stepSize;
+ int nDragSteps = qAbs(dragDistance/stepSize);
+
+ for (int i = 0 ; i < nDragSteps; ++i) {
+ QTest::mouseMove(window, pos);
+ pos += dragStepSize;
+ }
+ // Move to the final position
+ pos = *startPos + delta;
+ QTest::mouseMove(window, pos);
+ *startPos = pos;
+}
+
+static void dragtwice(QWindow *window, QPoint *startPos, const QPoint &delta1, const QPoint &delta2)
+{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QPoint &pos = *startPos;
+ QPoint unitVector(0, 0);
+ if (delta1.x())
+ unitVector.setX(qBound(-1, delta1.x(), 1));
+ if (delta1.y())
+ unitVector.setY(qBound(-1, delta1.y(), 1));
+
+ // go just beyond the drag theshold
+ drag_helper(window, &pos, unitVector * (dragThreshold + 1));
+ drag_helper(window, &pos, unitVector);
+
+ // next drag will actually scroll the listview
+ if (delta1.manhattanLength() >= 1)
+ drag_helper(window, &pos, delta1);
+ if (delta2.manhattanLength() >= 1)
+ drag_helper(window, &pos, delta2);
+}
+
+struct MyListView : public QQuickListView{
+ qreal contentPosition() const
+ {
+ return (orientation() == QQuickListView::Horizontal ? contentX(): contentY());
+ }
+
+ qreal headerPosition() const
+ {
+ return (orientation() == QQuickListView::Horizontal ? headerItem()->x() : headerItem()->y());
+ }
+};
+
+void tst_QQuickListView::headerSnapToItem()
+{
+ QFETCH(QQuickItemView::LayoutDirection, layoutDirection);
+ QFETCH(QQuickListView::HeaderPositioning, headerPositioning);
+ QFETCH(int, firstDragDistance);
+ QFETCH(int, secondDragDistance);
+ QFETCH(int, expectedContentPosition);
+ QFETCH(int, expectedHeaderPosition);
+
+ QQuickView *window = getView();
+ window->setSource(testFileUrl("headerSnapToItem.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ MyListView *listview = static_cast<MyListView *>(findItem<QQuickListView>(window->rootObject(), "list"));
+ QVERIFY(listview != nullptr);
+
+ const bool horizontal = layoutDirection < QQuickItemView::VerticalTopToBottom;
+ listview->setOrientation(horizontal ? QQuickListView::Horizontal : QQuickListView::Vertical);
+
+ if (horizontal)
+ listview->setLayoutDirection(static_cast<Qt::LayoutDirection>(layoutDirection));
+ else
+ listview->setVerticalLayoutDirection(static_cast<QQuickItemView::VerticalLayoutDirection>(layoutDirection));
+
+ listview->setHeaderPositioning(headerPositioning);
+ QTest::qWaitFor([&]() { return !QQuickItemPrivate::get(listview)->polishScheduled; });
+
+ QQuickItem *contentItem = listview->contentItem();
+ QVERIFY(contentItem != nullptr);
+ QQuickItem *header = findItem<QQuickItem>(contentItem, "header");
+ QVERIFY(header != nullptr);
+ QCOMPARE(header, listview->headerItem());
+
+ QPoint startPos = (QPointF(listview->width(), listview->height())/2).toPoint();
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos, 200);
+
+ QPoint firstDragDelta = horizontal ? QPoint(firstDragDistance, 0) : QPoint(0, firstDragDistance);
+ QPoint secondDragDelta = horizontal ? QPoint(secondDragDistance, 0) : QPoint(0, secondDragDistance);
+
+ dragtwice(window, &startPos, firstDragDelta, secondDragDelta);
+
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos, 200); // Wait 200 ms before we release to avoid trigger a flick
+
+ // wait for the "fixup" animation to finish
+ QTest::qWaitFor([&]()
+ { return !listview->isMoving();}
+ );
+
+ QCOMPARE(listview->contentPosition(), expectedContentPosition);
+ QCOMPARE(listview->headerPosition(), expectedHeaderPosition);
+}
+
+void tst_QQuickListView::headerSnapToItem_data()
+{
+ QTest::addColumn<QQuickItemView::LayoutDirection>("layoutDirection");
+ QTest::addColumn<QQuickListView::HeaderPositioning>("headerPositioning");
+ QTest::addColumn<int>("firstDragDistance");
+ QTest::addColumn<int>("secondDragDistance");
+ QTest::addColumn<int>("expectedContentPosition");
+ QTest::addColumn<int>("expectedHeaderPosition");
+
+ // --------------------
+ // InlineHeader TopToBottom
+ QTest::newRow("InlineHeader TopToBottom -10") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -10 << 0
+ << -30 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -14") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -14 << 0
+ << -30 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -16") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -16 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -30") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -30 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -39") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -39 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -41") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -41 << 0
+ << 20 << -30;
+
+ QTest::newRow("InlineHeader TopToBottom -65+10") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::InlineHeader
+ << -65 << 10
+ << 20 << -30;
+
+ // --------------------
+ // InlineHeader BottomToTop
+ QTest::newRow("InlineHeader BottomToTop +10") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 10 << 0
+ << -170 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +14") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 14 << 0
+ << -170 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +16") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 16 << 0
+ << -200 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +30") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 30 << 0
+ << -200 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +39") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 39 << 0
+ << -200 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +41") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 41 << 0
+ << -220 << 0;
+
+ QTest::newRow("InlineHeader BottomToTop +65-10") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::InlineHeader
+ << 65 << -10
+ << -220 << 0;
+
+ // --------------------
+ // InlineHeader LeftToRight
+ QTest::newRow("InlineHeader LeftToRight -10") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -10 << 0
+ << -30 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -14") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -14 << 0
+ << -30 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -16") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -16 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -30") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -30 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -39") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -39 << 0
+ << 0 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -41") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -41 << 0
+ << 20 << -30;
+
+ QTest::newRow("InlineHeader LeftToRight -65+10") << QQuickItemView::LeftToRight
+ << QQuickListView::InlineHeader
+ << -65 << 10
+ << 20 << -30;
+
+ // --------------------
+ // InlineHeader RightToLeft
+ QTest::newRow("InlineHeader RightToLeft +10") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 10 << 0
+ << -210 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +14") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 14 << 0
+ << -210 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +16") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 16 << 0
+ << -240 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +30") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 30 << 0
+ << -240 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +39") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 39 << 0
+ << -240 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +41") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 41 << 0
+ << -260 << 0;
+
+ QTest::newRow("InlineHeader RightToLeft +65-10") << QQuickItemView::RightToLeft
+ << QQuickListView::InlineHeader
+ << 65 << -10
+ << -260 << 0;
+
+ // --------------------
+ // OverlayHeader TopToBottom
+ QTest::newRow("OverlayHeader TopToBottom +9") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << 9 << 0
+ << -30 << -30;
+
+ QTest::newRow("OverlayHeader TopToBottom -9") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << -9 << 0
+ << -30 << -30;
+
+ QTest::newRow("OverlayHeader TopToBottom -11") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << -11 << 0
+ << -10 << -10;
+
+ QTest::newRow("OverlayHeader TopToBottom -29") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << -29 << 0
+ << -10 << -10;
+
+ QTest::newRow("OverlayHeader TopToBottom -31") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::OverlayHeader
+ << -31 << 0
+ << 10 << 10;
+
+ // --------------------
+ // OverlayHeader BottomToTop
+ QTest::newRow("OverlayHeader BottomToTop -9") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << -9 << 0
+ << -170 << 0;
+
+ QTest::newRow("OverlayHeader BottomToTop +9") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << 9 << 0
+ << -170 << 0;
+
+ QTest::newRow("OverlayHeader BottomToTop +11") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << 11 << 0
+ << -190 << -20;
+
+ QTest::newRow("OverlayHeader BottomToTop +29") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << 29 << 0
+ << -190 << -20;
+
+ QTest::newRow("OverlayHeader BottomToTop +31") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::OverlayHeader
+ << 31 << 0
+ << -210 << -40;
+
+ // --------------------
+ // OverlayHeader LeftToRight
+ QTest::newRow("OverlayHeader LeftToRight +9") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << 9 << 0
+ << -30 << -30;
+
+ QTest::newRow("OverlayHeader LeftToRight -9") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << -9 << 0
+ << -30 << -30;
+
+ QTest::newRow("OverlayHeader LeftToRight -11") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << -11 << 0
+ << -10 << -10;
+
+ QTest::newRow("OverlayHeader LeftToRight -29") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << -29 << 0
+ << -10 << -10;
+
+ QTest::newRow("OverlayHeader LeftToRight -31") << QQuickItemView::LeftToRight
+ << QQuickListView::OverlayHeader
+ << -31 << 0
+ << 10 << 10;
+
+ // --------------------
+ // OverlayHeader RightToLeft
+ QTest::newRow("OverlayHeader RightToLeft -9") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << -9 << 0
+ << -210 << 0;
+
+ QTest::newRow("OverlayHeader RightToLeft +9") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << 9 << 0
+ << -210 << 0;
+
+ QTest::newRow("OverlayHeader RightToLeft +11") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << 11 << 0
+ << -230 << -20;
+
+ QTest::newRow("OverlayHeader RightToLeft +29") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << 29 << 0
+ << -230 << -20;
+
+ QTest::newRow("OverlayHeader RightToLeft +31") << QQuickItemView::RightToLeft
+ << QQuickListView::OverlayHeader
+ << 31 << 0
+ << -250 << -40;
+
+ // --------------------
+ // PullbackHeader TopToBottom
+ QTest::newRow("PullbackHeader TopToBottom -2") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -2 << 0
+ << -30 << -30;
+
+ QTest::newRow("PullbackHeader TopToBottom -10") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -10 << 0
+ << -30 << -30;
+
+ QTest::newRow("PullbackHeader TopToBottom -11") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -11 << 0
+ << -10 << -10;
+
+ QTest::newRow("PullbackHeader TopToBottom -14") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -14 << 0
+ << -10 << -10;
+
+ QTest::newRow("PullbackHeader TopToBottom -16") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -16 << 0
+ << 0 << -30;
+
+ QTest::newRow("PullbackHeader TopToBottom -20") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -20 << 0
+ << 0 << -30;
+
+ QTest::newRow("PullbackHeader TopToBottom -65+10") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -65 << 10
+ << 20 << -10;
+
+ QTest::newRow("PullbackHeader TopToBottom -65+20") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -65 << 20
+ << 10 << 10;
+
+ // Should move header even if contentY doesn't move (its aligned with top)
+ QTest::newRow("PullbackHeader TopToBottom -55+5") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -55 << 5
+ << 20 << -10;
+
+ // Should move header even if contentY doesn't move (it's aligned with header)
+ QTest::newRow("PullbackHeader TopToBottom -76+16") << QQuickItemView::VerticalTopToBottom
+ << QQuickListView::PullBackHeader
+ << -76 << 16
+ << 30 << 30;
+
+ // --------------------
+ // PullbackHeader BottomToTop
+ QTest::newRow("PullbackHeader BottomToTop +2") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +2 << 0
+ << -170 << 0;
+
+ QTest::newRow("PullbackHeader BottomToTop +9") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +9 << 0
+ << -170 << 0;
+
+ QTest::newRow("PullbackHeader BottomToTop +11") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +11 << 0
+ << -190 << -20;
+
+ QTest::newRow("PullbackHeader BottomToTop +14") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +14 << 0
+ << -190 << -20;
+
+ QTest::newRow("PullbackHeader BottomToTop +16") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +16 << 0
+ << -200 << 0;
+
+ QTest::newRow("PullbackHeader BottomToTop +20") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +20 << 0
+ << -200 << 0;
+
+ QTest::newRow("PullbackHeader BottomToTop +65-10") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +65 << -10
+ << -220 << -20;
+
+ QTest::newRow("PullbackHeader BottomToTop +65-20") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << +65 << -20
+ << -210 << -40;
+
+ // Should move header even if contentY doesn't move (it's aligned with top)
+ QTest::newRow("PullbackHeader BottomToTop +55-5") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << 55 << -5
+ << -220 << -20;
+
+ // Should move header even if contentY doesn't move (it's aligned with header)
+ QTest::newRow("PullbackHeader BottomToTop +76-16") << QQuickItemView::VerticalBottomToTop
+ << QQuickListView::PullBackHeader
+ << 76 << -16
+ << -230 << -60;
+
+ // --------------------
+ // PullbackHeader LeftToRight
+ QTest::newRow("PullbackHeader LeftToRight -2") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -2 << 0
+ << -30 << -30;
+
+ QTest::newRow("PullbackHeader LeftToRight -10") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -10 << 0
+ << -30 << -30;
+
+ QTest::newRow("PullbackHeader LeftToRight -11") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -11 << 0
+ << -10 << -10;
+
+ QTest::newRow("PullbackHeader LeftToRight -14") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -14 << 0
+ << -10 << -10;
+
+ QTest::newRow("PullbackHeader LeftToRight -16") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -16 << 0
+ << 0 << -30;
+
+ QTest::newRow("PullbackHeader LeftToRight -20") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -20 << 0
+ << 0 << -30;
+
+ QTest::newRow("PullbackHeader LeftToRight -65+10") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -65 << 10
+ << 20 << -10;
+
+ QTest::newRow("PullbackHeader LeftToRight -65+20") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -65 << 20
+ << 10 << 10;
+
+ // Should move header even if contentX doesn't move (its aligned with top)
+ QTest::newRow("PullbackHeader LeftToRight -55+5") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -55 << 5
+ << 20 << -10;
+
+ // Should move header even if contentX doesn't move (it's aligned with header)
+ QTest::newRow("PullbackHeader LeftToRight -76+16") << QQuickItemView::LeftToRight
+ << QQuickListView::PullBackHeader
+ << -76 << 16
+ << 30 << 30;
+
+ // --------------------
+ // PullbackHeader RightToLeft
+ QTest::newRow("PullbackHeader RightToLeft +2") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +2 << 0
+ << -210 << 0;
+
+ QTest::newRow("PullbackHeader RightToLeft +9") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +9 << 0
+ << -210 << 0;
+
+ QTest::newRow("PullbackHeader RightToLeft +11") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +11 << 0
+ << -230 << -20;
+
+ QTest::newRow("PullbackHeader RightToLeft +14") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +14 << 0
+ << -230 << -20;
+
+ QTest::newRow("PullbackHeader RightToLeft +16") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +16 << 0
+ << -240 << 0;
+
+ QTest::newRow("PullbackHeader RightToLeft +20") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +20 << 0
+ << -240 << 0;
+
+ QTest::newRow("PullbackHeader RightToLeft +65-10") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +65 << -10
+ << -260 << -20;
+
+ QTest::newRow("PullbackHeader RightToLeft +65-20") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << +65 << -20
+ << -250 << -40;
+
+ // Should move header even if contentX doesn't move (it's aligned with top)
+ QTest::newRow("PullbackHeader RightToLeft +55-5") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << 55 << -5
+ << -260 << -20;
+
+ // Should move header even if contentX doesn't move (it's aligned with header)
+ QTest::newRow("PullbackHeader RightToLeft +76-16") << QQuickItemView::RightToLeft
+ << QQuickListView::PullBackHeader
+ << 76 << -16
+ << -270 << -60;
+
+}
+
void tst_QQuickListView::snapOneItemResize_QTBUG_43555()
{
QScopedPointer<QQuickView> window(createView());
diff --git a/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml b/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml
new file mode 100644
index 0000000000..4532dabfd8
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/settingHiddenInPressUngrabs.qml
@@ -0,0 +1,36 @@
+import QtQuick 2.11
+import QtQuick.Window 2.11
+
+Window {
+ id: window
+ visible: true
+ width: 200
+ height: 200
+
+ MouseArea {
+ objectName: "cat"
+ anchors.fill: parent
+ onPressed: visible = false
+ width: parent.width / 2
+ height: parent.height
+ Rectangle {
+ width: 10
+ height: 10
+ color: "blue"
+ }
+ }
+ MouseArea {
+ objectName: "mouse"
+ x: parent.width / 2
+ width: parent.width / 2
+ height: parent.height
+ onPressed: {
+ enabled = false
+ }
+ Rectangle {
+ width: 10
+ height: 10
+ color: "blue"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 52d1458a53..0c44121830 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -158,6 +158,7 @@ private slots:
void pressOneAndTapAnother();
void mask();
void nestedEventDelivery();
+ void settingHiddenInPressUngrabs();
private:
int startDragDistance() const {
@@ -2306,6 +2307,43 @@ void tst_QQuickMouseArea::nestedEventDelivery() // QTBUG-70898
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50,150));
}
+void tst_QQuickMouseArea::settingHiddenInPressUngrabs()
+{
+ // When an item sets itself hidden, while handling pressed, it doesn't receive the grab.
+ // But that in turn means it doesn't see any release events, so we need to make sure it
+ // receives an ungrab event.
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("settingHiddenInPressUngrabs.qml"));
+ QScopedPointer<QQuickWindow> window(qmlobject_cast<QQuickWindow *>(c.create()));
+ QVERIFY(window.data());
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickMouseArea *catArea = window->findChild<QQuickMouseArea*>("cat");
+ QVERIFY(catArea != nullptr);
+ auto pointOnCatArea = catArea->mapToScene(QPointF(5.0, 5.0)).toPoint();
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, pointOnCatArea);
+
+ QCoreApplication::processEvents();
+ // The click hides the cat area
+ QTRY_VERIFY(!catArea->isVisible());
+ // The cat area is not stuck in pressed state.
+ QVERIFY(!catArea->pressed());
+
+ QQuickMouseArea *mouseArea = window->findChild<QQuickMouseArea*>("mouse");
+ QVERIFY(mouseArea != nullptr);
+ auto pointOnMouseArea = mouseArea->mapToScene(QPointF(5.0, 5.0)).toPoint();
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, pointOnMouseArea);
+
+ QCoreApplication::processEvents();
+ // The click disables the mouse area
+ QTRY_VERIFY(!mouseArea->isEnabled());
+ // The mouse area is not stuck in pressed state.
+ QVERIFY(!mouseArea->pressed());
+}
+
QTEST_MAIN(tst_QQuickMouseArea)
#include "tst_qquickmousearea.moc"
diff --git a/tests/auto/quick/qquickshadereffect/data/hideParent.qml b/tests/auto/quick/qquickshadereffect/data/hideParent.qml
new file mode 100644
index 0000000000..aeeb5b5f78
--- /dev/null
+++ b/tests/auto/quick/qquickshadereffect/data/hideParent.qml
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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.12
+
+Item {
+ id: root
+ width: 640
+ height: 480
+ objectName: "qtbug86402Container"
+
+ property bool finished
+
+ Item {
+ id: popup
+ objectName: "popup"
+ width: 200
+ height: 200
+
+ Rectangle {
+ id: rect
+ objectName: "rect"
+ implicitWidth: 100
+ implicitHeight: 100
+ color: "blue"
+
+ Item {
+ id: ripple
+ objectName: "ripple"
+ anchors.fill: parent
+ visible: false
+
+ Rectangle {
+ id: rippleBox
+ objectName: "rippleBox"
+ property real cx
+ property real cy
+ x: cx - width / 2
+ y: cy - height / 2
+ width: 0
+ height: width
+ radius: width / 2
+ color: Qt.darker("red", 1.8)
+ }
+ layer.effect: ShaderEffect {
+ id: mask
+ objectName: "shaderEffect"
+ property variant source
+ property variant mask: rect
+
+ fragmentShader: "
+ uniform lowp sampler2D source;
+ uniform lowp sampler2D mask;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ gl_FragColor = texture2D(source, qt_TexCoord0) * texture2D(mask, qt_TexCoord0).a;
+ }"
+ }
+ }
+
+ SequentialAnimation {
+ id: rippleStartAnimation
+ running: popup.visible
+ onFinished: {
+ popup.parent = null
+ rippleEndAnimation.start()
+ }
+
+ ScriptAction {
+ script: {
+ rippleBox.width = 0
+ rippleBox.opacity = 0.3
+ ripple.visible = true
+ ripple.layer.enabled = true
+ }
+ }
+ NumberAnimation {
+ target: rippleBox
+ property: "width"
+ from: 0
+ to: Math.max(rect.width,
+ rect.height) * 2.2
+ duration: 100
+ }
+ }
+ SequentialAnimation {
+ id: rippleEndAnimation
+
+ onFinished: root.finished = true
+
+ //Causes Crash on QT Versions > 5.12.5
+ NumberAnimation {
+ target: rippleBox
+ property: "opacity"
+ to: 0
+ duration: 100
+ }
+ ScriptAction {
+ script: {
+ rippleBox.opacity = 0
+ ripple.layer.enabled = false
+ ripple.visible = false
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
index f601f520bb..1db4c8e0d5 100644
--- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
+++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
@@ -79,6 +79,8 @@ private slots:
void deleteShaderEffectSource();
void twoImagesOneShaderEffect();
+ void hideParent();
+
private:
enum PresenceFlags {
VertexPresent = 0x01,
@@ -320,6 +322,18 @@ void tst_qquickshadereffect::twoImagesOneShaderEffect()
delete view;
}
+// QTBUG-86402: hiding the parent of an item that uses an effect should not cause a crash.
+void tst_qquickshadereffect::hideParent()
+{
+ QScopedPointer<QQuickView> view(new QQuickView);
+ view->setSource(testFileUrl("hideParent.qml"));
+ QCOMPARE(view->status(), QQuickView::Ready);
+ view->show();
+ QVERIFY(QTest::qWaitForWindowExposed(view.data()));
+ // Should finish without crashing.
+ QTRY_VERIFY(view->rootObject()->property("finished").toBool());
+}
+
QTEST_MAIN(tst_qquickshadereffect)
#include "tst_qquickshadereffect.moc"
diff --git a/tests/auto/quick/qquicktext/BLACKLIST b/tests/auto/quick/qquicktext/BLACKLIST
index 531d981159..9317ee37bc 100644
--- a/tests/auto/quick/qquicktext/BLACKLIST
+++ b/tests/auto/quick/qquicktext/BLACKLIST
@@ -4,3 +4,5 @@
msvc-2015
[fontSizeMode]
opensuse-42.1
+[hAlignVisual]
+sles
diff --git a/tests/auto/quick/qquicktextinput/data/checkCursorDelegateWhenPaddingChanged.qml b/tests/auto/quick/qquicktextinput/data/checkCursorDelegateWhenPaddingChanged.qml
new file mode 100644
index 0000000000..e6f07b4687
--- /dev/null
+++ b/tests/auto/quick/qquicktextinput/data/checkCursorDelegateWhenPaddingChanged.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.12
+
+Rectangle {
+ width: 200
+ height: 200
+ TextInput {
+ objectName: "textInput"
+ leftPadding: 10
+ focus: true
+ cursorDelegate: Rectangle {
+ objectName: "cursorDelegate"
+ width: 5
+ color: "red"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index ed2d535fda..f736d0a873 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -231,6 +231,7 @@ private slots:
void QTBUG_51115_readOnlyResetsSelection();
+ void checkCursorDelegateWhenPaddingChanged();
private:
void simulateKey(QWindow *, int key);
@@ -7003,6 +7004,35 @@ void tst_qquicktextinput::QTBUG_51115_readOnlyResetsSelection()
QCOMPARE(obj->selectedText(), QString());
}
+void tst_qquicktextinput::checkCursorDelegateWhenPaddingChanged()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("checkCursorDelegateWhenPaddingChanged.qml"));
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickTextInput *textInput = view.rootObject()->findChild<QQuickTextInput *>("textInput");
+ QVERIFY(textInput);
+
+ QQuickItem *cursorDelegate = textInput->findChild<QQuickItem *>("cursorDelegate");
+ QVERIFY(cursorDelegate);
+
+ QCOMPARE(cursorDelegate->x(), textInput->leftPadding());
+ QCOMPARE(cursorDelegate->y(), textInput->topPadding());
+
+ textInput->setPadding(5);
+ QCOMPARE(cursorDelegate->x(), textInput->leftPadding());
+ QCOMPARE(cursorDelegate->y(), textInput->topPadding());
+
+ textInput->setTopPadding(10);
+ QCOMPARE(cursorDelegate->x(), textInput->leftPadding());
+ QCOMPARE(cursorDelegate->y(), textInput->topPadding());
+
+ textInput->setLeftPadding(10);
+ QCOMPARE(cursorDelegate->x(), textInput->leftPadding());
+ QCOMPARE(cursorDelegate->y(), textInput->topPadding());
+}
+
QTEST_MAIN(tst_qquicktextinput)
#include "tst_qquicktextinput.moc"
diff --git a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
index 75fbb0fcf3..5eb9c4442c 100644
--- a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
+++ b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in
@@ -85,6 +85,6 @@ but not all the files it references.
list(APPEND compiler_output ${loader_source})
endif()
- qt5_add_resources(output_resources ${filtered_rcc_files} OPTIONS ${options})
+ qt5_add_resources(output_resources ${filtered_rcc_files} OPTIONS ${rcc_options})
set(${outfiles} ${output_resources} ${compiler_output} PARENT_SCOPE)
endfunction()
diff --git a/tools/qmlprofiler/qmlprofilerapplication.cpp b/tools/qmlprofiler/qmlprofilerapplication.cpp
index 6732766b46..13a0021051 100644
--- a/tools/qmlprofiler/qmlprofilerapplication.cpp
+++ b/tools/qmlprofiler/qmlprofilerapplication.cpp
@@ -303,7 +303,7 @@ void QmlProfilerApplication::flush()
{
if (m_recording) {
m_pendingRequest = REQUEST_FLUSH;
- m_qmlProfilerClient->sendRecordingStatus(false);
+ m_qmlProfilerClient->setRecording(false);
} else {
if (m_profilerData->save(m_interactiveOutputFile)) {
m_profilerData->clear();
@@ -393,7 +393,7 @@ void QmlProfilerApplication::userCommand(const QString &command)
if (cmd == Constants::CMD_RECORD || cmd == Constants::CMD_RECORD2) {
m_pendingRequest = REQUEST_TOGGLE_RECORDING;
- m_qmlProfilerClient->sendRecordingStatus(!m_recording);
+ m_qmlProfilerClient->setRecording(!m_recording);
} else if (cmd == Constants::CMD_QUIT || cmd == Constants::CMD_QUIT2) {
m_pendingRequest = REQUEST_QUIT;
if (m_recording) {
diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp
index d5662a0182..9ec143975e 100644
--- a/tools/qmlprofiler/qmlprofilerdata.cpp
+++ b/tools/qmlprofiler/qmlprofilerdata.cpp
@@ -101,7 +101,6 @@ QmlProfilerData::~QmlProfilerData()
void QmlProfilerData::clear()
{
- d->eventTypes.clear();
d->events.clear();
d->traceEndTime = std::numeric_limits<qint64>::min();