From bae6f43d8e1fafec2771bdeddffa9edaf1bf6130 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 23 May 2019 11:16:56 +0200 Subject: Bump version Change-Id: I0810ede89313a6ee3ee31a352fda620835dfb055 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index a3c853d760..58e82995bd 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,4 @@ load(qt_build_config) CONFIG += warning_clean -MODULE_VERSION = 5.12.3 +MODULE_VERSION = 5.12.4 -- cgit v1.2.3 From 48b4df598c88782f031f3df62964e159feeb20fb Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Thu, 23 May 2019 15:20:44 +0300 Subject: Add changes file for Qt 5.12.4 Change-Id: I6980ffaed4da941fbcd56af36bba7e5abf3dd878 Reviewed-by: Shawn Rutledge Reviewed-by: Ulf Hermann --- dist/changes-5.12.4 | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 dist/changes-5.12.4 diff --git a/dist/changes-5.12.4 b/dist/changes-5.12.4 new file mode 100644 index 0000000000..d963e44e67 --- /dev/null +++ b/dist/changes-5.12.4 @@ -0,0 +1,90 @@ +Qt 5.12.4 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.3. + +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. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - [QTBUG-14769] TextEdit now uses the I-beam cursor by default, and the + pointing hand cursor for links. However in C++ it's still possible to + override with a custom cursor. + - [QTBUG-70826] The QML Runtime tool now has an updated application icon + and a default window icon. QtQuick applications can still use + QWindow::setIcon() to override the window icon. + +**************************************************************************** +* QtQml * +**************************************************************************** + + - [QTBUG-75880] An anonymous function's "name" now comes directly from the + surrounding object pattern if applicable. This fixes some ecmascript tests + where functions were assigned to the key "eval" in an object. + - [QTBUG-75896] Fixed lookups of properties in QML singletons. + - [QTBUG-48809] We now print a warning when encountering a non-relative URL + in a qmldir file. You should use relative paths. + - [QTBUG-75609] Improved the cache for looking up attached properties objects, + to fix a performance regression in Qt Quick Layouts. + - [QTBUG-75392] Fixed a crash caused by std::function. + - [QTBUG-74048] Fixed a crash in QJSEngine::evaluate. + - [QTBUG-75501] lupdate now works better with the Qt Quick compiler. + - [QTBUG-75393] Fixed debugging of named signal arguments in Connections. + - [QTBUG-75410] Fixed maximum call stack depth for clang ASAN builds. + - [QTBUG-74815] We now allow creation of variants from non-singleton + QQmlTypeWrappers. + - [QTBUG-74815] Unknown types are no longer mis-identified as "null". + - [QTBUG-75335] Fixed a crash related to optimized heap lookups. + - [QTBUG-73217] The "QML debugging is enabled" warning is printed + normally rather than via a log message, which works better with + static builds. + - [QTBUG-75176] Fixed a crash on exit related to attached properties + on static builds. + - [QTBUG-75203] Fixed a crash when accessing invalid properties through + QObjectWrapper + - [QTBUG-71116] Errors in fetchOrCreateTypeForUrl are no longer fatal. + - [QTBUG-75121] Fixed an invalid capture in ECMAScript + string.replace(RegExp, backref) + - [QTBUG-74876] Fixed a crash in LinkBuffer's performFinalization. + - [QTBUG-74876] Fixed a memory leak when emitting QImage or QPixmap + as a signal argument. + - [QDS-589] qmlscene now supports file selectors. + - [QTBUG-74867] We now detect and reject cyclic aliases to avoid + infinite recursion. + - [QTBUG-74884] Configuration with -no-feature-delegate-model now works. + - [QTBUG-75030] Fixed an arithmetic exception related to bindings. + +**************************************************************************** +* QtQuick * +**************************************************************************** + + - [QTBUG-73768] Fixed a failing assertion in BorderImage when any border size + exceeds source image size. + - [QTBUG-75770] MouseArea no longer mis-identifies fast drags as double clicks. + - [QTBUG-75002] Accessibility: StaticText nodes are now properly marked as + read-only. + - [QTBUG-70083] Replaced PinchHandler qCInfo messages with qCDebug. + - [QTBUG-70083] Fixed the "no points" warning when using native gestures. + - [QTBUG-73182] Fixed a memory leak by optimizing storage of + QQuickEventPoint instances. + - [QTBUG-65761] Fixed input handling in QWebEngineView on eglfs. + - [QTBUG-51993] Canvas3D now works properly inside QQuickWidget. + - [QTBUG-74966] DragHandler no longer makes its target jump if you + start dragging in the margin area. + - [QTBUG-74679] Touch cancel now results in an ungrab event, so that + any parent flickable can filter the event, reset its state and be ready + to scroll again. -- cgit v1.2.3 From 1eb3a6febec8fa8bb616a3765c1a899210135f31 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 13 Jun 2019 13:24:43 +0200 Subject: Avoid number conversion issue Change-Id: Ia118e5885886605f7364d15d30ac67fdb01a5562 Reviewed-by: Ulf Hermann --- src/imports/sharedimage/qsharedimageloader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/imports/sharedimage/qsharedimageloader.cpp b/src/imports/sharedimage/qsharedimageloader.cpp index 4672ded376..dcd28cb0b2 100644 --- a/src/imports/sharedimage/qsharedimageloader.cpp +++ b/src/imports/sharedimage/qsharedimageloader.cpp @@ -173,7 +173,8 @@ QImage QSharedImageLoaderPrivate::load(const QString &path, QSharedImageLoader:: if (img.isNull()) return nil; size_t size = sizeof(SharedImageHeader) + img.sizeInBytes(); - if (size > std::numeric_limits::max()) { + const size_t intMax = std::numeric_limits::max(); + if (size > intMax) { qCDebug(lcSharedImage) << "Image" << path << "to large to load"; return nil; } else if (shm->create(int(size))) { -- cgit v1.2.3 From 2e25ec139d6b2394650b165e71eba246423fb492 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 13 Jun 2019 15:10:14 +0200 Subject: Fix graphical artifacts after changing only texture If the size of the texture changes, but subrect stays the same, the geometry changed and is now dirty. Change-Id: I5a4de88fd3f788a686fb2186185da2a0a3faad82 Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/util/qsgdefaultimagenode.cpp | 4 ++++ src/quick/scenegraph/util/qsgdefaultimagenode_p.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp index 7186ee4265..48ec8f01d3 100644 --- a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp +++ b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp @@ -156,6 +156,10 @@ void QSGDefaultImageNode::setTexture(QSGTexture *texture) m_isAtlasTexture = texture->isAtlasTexture(); if (wasAtlas || m_isAtlasTexture) dirty |= DirtyGeometry; + // The geometry has also changed if the texture size changed. + if (m_textureSize != texture->textureSize()) + dirty |= DirtyGeometry; + m_textureSize = texture->textureSize(); markDirty(dirty); } diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h index cb23e759d3..7b26daf541 100644 --- a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h +++ b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h @@ -95,6 +95,7 @@ private: QSGTextureMaterial m_material; QRectF m_rect; QRectF m_sourceRect; + QSize m_textureSize; TextureCoordinatesTransformMode m_texCoordMode; uint m_isAtlasTexture : 1; uint m_ownsTexture : 1; -- cgit v1.2.3 From 850d037bd455f2d96b22825756ce136bbd681a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Mon, 17 Jun 2019 12:39:58 +0200 Subject: Software Adaptation: Invalidate on dpr change We need to repaint everything on devicePixelRatio change, like we do on size change. Task-number: QTBUG-66810 Change-Id: I6b2c2ae92335a0aca731a4b0e7621cf7d08881e3 Reviewed-by: Andy Nichols --- .../adaptations/software/qsgabstractsoftwarerenderer.cpp | 7 ++++--- .../adaptations/software/qsgabstractsoftwarerenderer_p.h | 3 ++- .../scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp | 2 +- src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp | 3 ++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp index 2e5fdbbe6b..af3b901af4 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp @@ -238,12 +238,13 @@ void QSGAbstractSoftwareRenderer::setBackgroundColor(const QColor &color) renderableNode(m_background)->markMaterialDirty(); } -void QSGAbstractSoftwareRenderer::setBackgroundRect(const QRect &rect) +void QSGAbstractSoftwareRenderer::setBackgroundRect(const QRect &rect, qreal devicePixelRatio) { - if (m_background->rect().toRect() == rect) + if (m_background->rect().toRect() == rect && m_devicePixelRatio == devicePixelRatio) return; m_background->setRect(rect); - renderableNode(m_background)->markGeometryDirty(); + m_devicePixelRatio = devicePixelRatio; + renderableNode(m_background)->markGeometryDirty(); // Invalidate the whole scene when the background is resized markDirty(); } diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h index 99204ef25e..875569454f 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer_p.h @@ -83,7 +83,7 @@ protected: QRegion optimizeRenderList(); void setBackgroundColor(const QColor &color); - void setBackgroundRect(const QRect &rect); + void setBackgroundRect(const QRect &rect, qreal devicePixelRatio); QColor backgroundColor(); QRect backgroundRect(); // only known after calling optimizeRenderList() @@ -105,6 +105,7 @@ private: QRegion m_dirtyRegion; QRegion m_obscuredRegion; + qreal m_devicePixelRatio = 1; bool m_isOpaque = false; QSGSoftwareRenderableNodeUpdater *m_nodeUpdater; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp index bb4afc8301..4a6d73ec59 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp @@ -79,7 +79,7 @@ void QSGSoftwarePixmapRenderer::render(QPaintDevice *target) QElapsedTimer renderTimer; // Setup background item - setBackgroundRect(m_projectionRect.normalized()); + setBackgroundRect(m_projectionRect.normalized(), qreal(1)); setBackgroundColor(clearColor()); renderTimer.start(); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp index e9ed52d428..df129cbfee 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp @@ -114,7 +114,8 @@ void QSGSoftwareRenderer::render() setBackgroundColor(clearColor()); setBackgroundRect(QRect(0, 0, m_paintDevice->width() / m_paintDevice->devicePixelRatioF(), - m_paintDevice->height() / m_paintDevice->devicePixelRatioF())); + m_paintDevice->height() / m_paintDevice->devicePixelRatioF()), + m_paintDevice->devicePixelRatioF()); // Build Renderlist // The renderlist is created by visiting each node in the tree and when a -- cgit v1.2.3 From c1663865e68d96d4a51351d4d1d2bfa5f313dc18 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Fri, 22 Feb 2019 23:53:30 +0700 Subject: declarative: fix resource initialization for namespaced builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Q_INIT_RESOURCE` cannot be used from within a Qt namespace. so we move the `Q_INIT_RESOURCE` call to static function defined on the global namespace Change-Id: I9eed7699e969369f861b95cdf3f7376ade73c1b3 Reviewed-by: Morten Johan Sørvig --- src/quickshapes/qquickshape.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp index 262d0b3e9a..74cbf52a95 100644 --- a/src/quickshapes/qquickshape.cpp +++ b/src/quickshapes/qquickshape.cpp @@ -48,6 +48,13 @@ #include #include +#if defined(QT_STATIC) +static void initResources() +{ + Q_INIT_RESOURCE(qtquickshapes); +} +#endif + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(QQSHAPE_LOG_TIME_DIRTY_SYNC, "qt.shape.time.sync") @@ -662,7 +669,7 @@ struct QQuickShapeResourceInitializer QQuickShapeResourceInitializer() { #if defined(QT_STATIC) - Q_INIT_RESOURCE(qtquickshapes); + initResources(); #endif } }; -- cgit v1.2.3 From e9520ec84c95e10a6826b2289e46552a2d446895 Mon Sep 17 00:00:00 2001 From: Yulong Bai Date: Tue, 21 May 2019 13:48:52 +0200 Subject: Fix crash caused by objects self-destructions during displacement animations The root cause was that the QAbstractAnimationJob::finished() might delegate its destruction to change.listener->animationFinished(this), and the original author was aware of that and provided a RETURN_IF_DELETE macro to return early if itself got deleted. In the bug's case, change.listener->animationFinished(this) dispatched to QQuickItemViewPrivate::animationFinished() which called QQuickItemViewPrivate::release() and deleted the QAbstractAnimationJob object itself in the end. However, any objects derived from QAbstractAnimationJob, or holding a pointer to a QAbstractAnimationJob, may potentially fall into the code path calling QAbstractAnimationJob::finished(). Any QAnimationJobChangeListener that directly or indirectly deletes QAbstractAnimationJob should be very suspicious to this kind of "heap-use-after-free" bug. Should ensure that the QAbstractAnimationJob won't be referenced after deletion. In the bug's case, within the code path triggered by ListView displacement animation, the other affected classes by QAbstractAnimationJob are: QQuickItemViewFxItem, QQuickItemViewTransitionableItem, QQuickTransitionManager. To fix this, a new SelfDeletable class is factored out to simplify the self-deletion test logic. Any affected classes are made to have a public member m_selfDeletable. Any code paths that finally reach QAbstractAnimationJob::finished() are wrapped with related util macro. Change-Id: Idd33fc3f2d529fd7d8bb088c329101b1e70dd6c0 Task-number: QTBUG-44308 Reviewed-by: Richard Moe Gustavsen --- src/qml/animations/qabstractanimationjob.cpp | 4 - src/qml/animations/qabstractanimationjob_p.h | 3 +- src/qml/animations/qanimationjobutil_p.h | 32 ++++-- src/quick/items/qquickflickable.cpp | 2 +- src/quick/items/qquickitemview.cpp | 5 +- src/quick/items/qquickitemviewfxitem.cpp | 2 + src/quick/items/qquickitemviewfxitem_p_p.h | 2 + src/quick/items/qquickitemviewtransition.cpp | 20 +--- src/quick/items/qquickitemviewtransition_p.h | 2 + src/quick/util/qquicktransitionmanager.cpp | 7 +- src/quick/util/qquicktransitionmanager_p_p.h | 2 + .../data/animationJobSelfDestructionBug.qml | 108 +++++++++++++++++++++ .../quick/qquickanimations/qquickanimations.pro | 1 + .../qquickanimations/tst_qquickanimations.cpp | 21 ++++ 14 files changed, 180 insertions(+), 31 deletions(-) create mode 100644 tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp index ece2f0d692..7a784a2b35 100644 --- a/src/qml/animations/qabstractanimationjob.cpp +++ b/src/qml/animations/qabstractanimationjob.cpp @@ -263,7 +263,6 @@ QAbstractAnimationJob::QAbstractAnimationJob() , m_currentLoopStartTime(0) , m_nextSibling(nullptr) , m_previousSibling(nullptr) - , m_wasDeleted(nullptr) , m_hasRegisteredTimer(false) , m_isPause(false) , m_isGroup(false) @@ -277,9 +276,6 @@ QAbstractAnimationJob::QAbstractAnimationJob() QAbstractAnimationJob::~QAbstractAnimationJob() { - if (m_wasDeleted) - *m_wasDeleted = true; - //we can't call stop here. Otherwise we get pure virtual calls if (m_state != Stopped) { State oldState = m_state; diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h index 0be6ca96ea..d046ce9def 100644 --- a/src/qml/animations/qabstractanimationjob_p.h +++ b/src/qml/animations/qabstractanimationjob_p.h @@ -52,6 +52,7 @@ // #include +#include #include #include #include @@ -130,6 +131,7 @@ public: bool isRenderThreadJob() const { return m_isRenderThreadJob; } bool isRenderThreadProxy() const { return m_isRenderThreadProxy; } + SelfDeletable m_selfDeletable; protected: virtual void updateCurrentTime(int) {} virtual void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState); @@ -174,7 +176,6 @@ protected: QAbstractAnimationJob *m_previousSibling; QQmlAnimationTimer *m_timer = nullptr; - bool *m_wasDeleted; bool m_hasRegisteredTimer:1; bool m_isPause:1; bool m_isGroup:1; diff --git a/src/qml/animations/qanimationjobutil_p.h b/src/qml/animations/qanimationjobutil_p.h index e3d6fe9178..83cf3b246f 100644 --- a/src/qml/animations/qanimationjobutil_p.h +++ b/src/qml/animations/qanimationjobutil_p.h @@ -51,20 +51,40 @@ // We mean it. // +#include + QT_REQUIRE_CONFIG(qml_animation); -#define RETURN_IF_DELETED(func) \ +// SelfDeletable is used for self-destruction detection along with +// ACTION_IF_DELETED and RETURN_IF_DELETED macros. While using, the objects +// under test should have a member m_selfDeletable of type SelfDeletable +struct SelfDeletable { + ~SelfDeletable() { + if (m_wasDeleted) + *m_wasDeleted = true; + } + bool *m_wasDeleted = nullptr; +}; + +// \param p pointer to object under test, which should have a member m_selfDeletable of type 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) \ { \ - bool *prevWasDeleted = m_wasDeleted; \ + static_assert(std::is_samem_selfDeletable), SelfDeletable>::value, "m_selfDeletable must be SelfDeletable");\ + bool *prevWasDeleted = (p)->m_selfDeletable.m_wasDeleted; \ bool wasDeleted = false; \ - m_wasDeleted = &wasDeleted; \ - func; \ + (p)->m_selfDeletable.m_wasDeleted = &wasDeleted; \ + {func;} \ if (wasDeleted) { \ if (prevWasDeleted) \ *prevWasDeleted = true; \ - return; \ + {action;} \ } \ - m_wasDeleted = prevWasDeleted; \ + (p)->m_selfDeletable.m_wasDeleted = prevWasDeleted; \ } +#define RETURN_IF_DELETED(func) \ +ACTION_IF_DELETED(this, func, return) + #endif // QANIMATIONJOBUTIL_P_H diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index d6dddc3f1c..7e1f54f07e 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -206,8 +206,8 @@ public: axisData->move.setValue(-flickable->contentX()); else axisData->move.setValue(-flickable->contentY()); - cancel(); active = false; + cancel(); } protected: diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 8dafc16cf4..2e1962bc7b 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2225,7 +2225,10 @@ bool QQuickItemViewPrivate::prepareNonVisibleItemTransition(FxViewItem *item, co if (item->scheduledTransitionType() == QQuickItemViewTransitioner::MoveTransition) repositionItemAt(item, item->index, 0); - if (item->prepareTransition(transitioner, viewBounds)) { + bool success = false; + ACTION_IF_DELETED(item, success = item->prepareTransition(transitioner, viewBounds), return success); + + if (success) { item->releaseAfterTransition = true; return true; } diff --git a/src/quick/items/qquickitemviewfxitem.cpp b/src/quick/items/qquickitemviewfxitem.cpp index f9c65967ea..16c2182962 100644 --- a/src/quick/items/qquickitemviewfxitem.cpp +++ b/src/quick/items/qquickitemviewfxitem.cpp @@ -56,6 +56,8 @@ QQuickItemViewFxItem::QQuickItemViewFxItem(QQuickItem *item, bool ownItem, QQuic QQuickItemViewFxItem::~QQuickItemViewFxItem() { delete transitionableItem; + transitionableItem = nullptr; + if (ownItem && item) { trackGeometry(false); item->setParentItem(0); diff --git a/src/quick/items/qquickitemviewfxitem_p_p.h b/src/quick/items/qquickitemviewfxitem_p_p.h index 48ffe248bc..d10ebb9cdf 100644 --- a/src/quick/items/qquickitemviewfxitem_p_p.h +++ b/src/quick/items/qquickitemviewfxitem_p_p.h @@ -54,6 +54,7 @@ #include #include #include +#include QT_REQUIRE_CONFIG(quick_itemview); @@ -94,6 +95,7 @@ public: virtual bool contains(qreal x, qreal y) const = 0; + SelfDeletable m_selfDeletable; int index = -1; QPointer item; bool ownItem; diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index 0fde0beb75..109851608b 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -61,7 +61,6 @@ public: QPointF m_toPos; QQuickItemViewTransitioner::TransitionType m_type; bool m_isTarget; - bool *m_wasDeleted; protected: void finished() override; @@ -73,14 +72,11 @@ QQuickItemViewTransitionJob::QQuickItemViewTransitionJob() , m_item(nullptr) , m_type(QQuickItemViewTransitioner::NoTransition) , m_isTarget(false) - , m_wasDeleted(nullptr) { } QQuickItemViewTransitionJob::~QQuickItemViewTransitionJob() { - if (m_wasDeleted) - *m_wasDeleted = true; if (m_transitioner) m_transitioner->runningJobs.remove(this); } @@ -138,13 +134,7 @@ void QQuickItemViewTransitionJob::finished() QQuickTransitionManager::finished(); if (m_transitioner) { - bool deleted = false; - m_wasDeleted = &deleted; - m_transitioner->finishedTransition(this, m_item); - if (deleted) - return; - m_wasDeleted = nullptr; - + RETURN_IF_DELETED(m_transitioner->finishedTransition(this, m_item)); m_transitioner = nullptr; } @@ -482,7 +472,7 @@ bool QQuickItemViewTransitionableItem::prepareTransition(QQuickItemViewTransitio // if transition type is not valid, the previous transition still has to be // canceled so that the item can move immediately to the right position item->setPosition(nextTransitionTo); - stopTransition(); + ACTION_IF_DELETED(this, stopTransition(), return false); } prepared = true; @@ -501,12 +491,12 @@ void QQuickItemViewTransitionableItem::startTransition(QQuickItemViewTransitione if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) { if (transition) - transition->cancel(); + RETURN_IF_DELETED(transition->cancel()); delete transition; transition = new QQuickItemViewTransitionJob; } - transition->startTransition(this, index, transitioner, nextTransitionType, nextTransitionTo, isTransitionTarget); + RETURN_IF_DELETED(transition->startTransition(this, index, transitioner, nextTransitionType, nextTransitionTo, isTransitionTarget)); clearCurrentScheduledTransition(); } @@ -558,7 +548,7 @@ void QQuickItemViewTransitionableItem::clearCurrentScheduledTransition() void QQuickItemViewTransitionableItem::stopTransition() { if (transition) - transition->cancel(); + RETURN_IF_DELETED(transition->cancel()); clearCurrentScheduledTransition(); resetNextTransitionPos(); } diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index 29a62f7f10..0c7a9cad75 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -60,6 +60,7 @@ QT_REQUIRE_CONFIG(quick_viewtransitions); #include #include #include +#include QT_BEGIN_NAMESPACE @@ -157,6 +158,7 @@ public: bool prepareTransition(QQuickItemViewTransitioner *transitioner, int index, const QRectF &viewBounds); void startTransition(QQuickItemViewTransitioner *transitioner, int index); + SelfDeletable m_selfDeletable; QPointF nextTransitionTo; QPointF lastMovedTo; QPointF nextTransitionFrom; diff --git a/src/quick/util/qquicktransitionmanager.cpp b/src/quick/util/qquicktransitionmanager.cpp index e51de1a02a..0ee7e57997 100644 --- a/src/quick/util/qquicktransitionmanager.cpp +++ b/src/quick/util/qquicktransitionmanager.cpp @@ -47,6 +47,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -79,6 +80,7 @@ void QQuickTransitionManager::setState(QQuickState *s) QQuickTransitionManager::~QQuickTransitionManager() { delete d->transitionInstance; + d->transitionInstance = nullptr; delete d; d = nullptr; } @@ -129,7 +131,7 @@ void QQuickTransitionManager::transition(const QList &list, QQuickTransition *transition, QObject *defaultTarget) { - cancel(); + RETURN_IF_DELETED(cancel()); // The copy below is ON PURPOSE, because firing actions might involve scripts that modify the list. QQuickStateOperation::ActionList applyList = list; @@ -154,7 +156,6 @@ void QQuickTransitionManager::transition(const QList &list, // // This doesn't catch everything, and it might be a little fragile in // some cases - but whatcha going to do? - if (transition && !d->bindingsList.isEmpty()) { // Apply all the property and binding changes @@ -258,7 +259,7 @@ void QQuickTransitionManager::transition(const QList &list, void QQuickTransitionManager::cancel() { if (d->transitionInstance && d->transitionInstance->isRunning()) - d->transitionInstance->stop(); + RETURN_IF_DELETED(d->transitionInstance->stop()); for (const QQuickStateAction &action : qAsConst(d->bindingsList)) { if (action.toBinding && action.deletableToBinding) { diff --git a/src/quick/util/qquicktransitionmanager_p_p.h b/src/quick/util/qquicktransitionmanager_p_p.h index 89317e1e07..fc00ec8a52 100644 --- a/src/quick/util/qquicktransitionmanager_p_p.h +++ b/src/quick/util/qquicktransitionmanager_p_p.h @@ -52,6 +52,7 @@ // #include "qquickanimation_p.h" +#include QT_BEGIN_NAMESPACE @@ -70,6 +71,7 @@ public: void cancel(); + SelfDeletable m_selfDeletable; protected: virtual void finished(); diff --git a/tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml b/tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml new file mode 100644 index 0000000000..259871785b --- /dev/null +++ b/tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +import QtQuick 2.11 +import QtQuick.Window 2.11 + +Window { + id: root + property alias timer : timer + property variant ops: [{'op': 'add', 'count': 3}, {'op': 'add', 'count': 6}, {'op': 'rem', 'count': 4}, {'op': 'rem', 'count': 1}, {'op': 'rem', 'count': 3}] + property int opIndex : 0 + width: 400 + height: 600 + + ListModel { + id: theModel + } + + Timer { + id: timer + interval: 100 + running: false + repeat: true + onTriggered: { + if (opIndex >= ops.length) { + timer.stop() + return + } + let op = ops[opIndex] + for (var i = 0; i < op.count; ++i) { + if (op.op === "add") + theModel.append({"name": "opIndex " + opIndex}) + else + theModel.remove(0, 1); + } + opIndex = opIndex + 1 + } + } + + ListView { + anchors.top: parent.top + anchors.right: parent.right + height: 600 + anchors.left: parent.horizontalCenter + spacing: 4 + model: theModel + header: Text { + text: "YAnimator" + } + add: Transition { + NumberAnimation { property: "scale"; from: 0; to: 1; duration: 200 } + NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 200 } + } + displaced: Transition { + YAnimator { duration: 500 } + NumberAnimation { property: "opacity"; to: 1.0; duration: 500 } + NumberAnimation { property: "scale"; to: 1.0; duration: 500 } + } + remove: Transition { + NumberAnimation { property: "opacity"; to: 0; duration: 200 } + NumberAnimation { property: "scale"; to: 0; duration: 200 } + } + delegate: Rectangle { + width: 200 + height: 20 + color:"red" + Text { + anchors.centerIn: parent + text: name + } + } + } +} diff --git a/tests/auto/quick/qquickanimations/qquickanimations.pro b/tests/auto/quick/qquickanimations/qquickanimations.pro index 8bb1f47af5..cf9c87a305 100644 --- a/tests/auto/quick/qquickanimations/qquickanimations.pro +++ b/tests/auto/quick/qquickanimations/qquickanimations.pro @@ -12,6 +12,7 @@ QT += core-private gui-private qml-private quick-private testlib DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 OTHER_FILES += \ + data/animationJobSelfDestructionBug.qml\ data/attached.qml \ data/badproperty1.qml \ data/badproperty2.qml \ diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp index 0f095774e8..1dad0c771c 100644 --- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp +++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp @@ -109,6 +109,7 @@ private slots: void unsetAnimatorProxyJobWindow(); void finished(); void replacingTransitions(); + void animationJobSelfDestruction(); }; #define QTIMED_COMPARE(lhs, rhs) do { \ @@ -1723,6 +1724,26 @@ void tst_qquickanimations::replacingTransitions() QCOMPARE(model->count(), 3); } +void tst_qquickanimations::animationJobSelfDestruction() +{ + // Don't crash + QQmlEngine engine; + engine.clearComponentCache(); + QQmlComponent c(&engine, testFileUrl("animationJobSelfDestructionBug.qml")); + QScopedPointer win(qobject_cast(c.create())); + if (!c.errors().isEmpty()) + qDebug() << c.errorString(); + QVERIFY(win); + win->setTitle(QTest::currentTestFunction()); + win->show(); + QVERIFY(QTest::qWaitForWindowExposed(win.data())); + QQmlTimer *timer = win->property("timer").value(); + QVERIFY(timer); + QCOMPARE(timer->isRunning(), false); + timer->start(); + QTest::qWait(1000); +} + QTEST_MAIN(tst_qquickanimations) #include "tst_qquickanimations.moc" -- cgit v1.2.3