Merge lp:~timo-jyrinki/kubuntu-packaging/qtdeclarative-opensource-src_530ubuntu9 into lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src

Proposed by Timo Jyrinki
Status: Merged
Approved by: Timo Jyrinki
Approved revision: 165
Merged at revision: 163
Proposed branch: lp:~timo-jyrinki/kubuntu-packaging/qtdeclarative-opensource-src_530ubuntu9
Merge into: lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src
Diff against target: 401 lines (+381/-0)
3 files modified
debian/changelog (+8/-0)
debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch (+372/-0)
debian/patches/series (+1/-0)
To merge this branch: bzr merge lp:~timo-jyrinki/kubuntu-packaging/qtdeclarative-opensource-src_530ubuntu9
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Kubuntu Packagers Pending
Review via email: mp+230615@code.launchpad.net

Commit message

* debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch:
  - Cherry-pick a fix from Qt 5.3.1 to fix crash in RotationAnimator
    (LP: #1356279)

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2014-08-04 11:27:03 +0000
3+++ debian/changelog 2014-08-13 12:23:14 +0000
4@@ -1,3 +1,11 @@
5+qtdeclarative-opensource-src (5.3.0-3ubuntu9) utopic; urgency=medium
6+
7+ * debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch:
8+ - Cherry-pick a fix from Qt 5.3.1 to fix crash in RotationAnimator
9+ (LP: #1356279)
10+
11+ -- Timo Jyrinki <timo-jyrinki@ubuntu.com> Wed, 13 Aug 2014 12:18:47 +0000
12+
13 qtdeclarative-opensource-src (5.3.0-3ubuntu8) utopic; urgency=medium
14
15 [ MichaƂ Sawicz ]
16
17=== added file 'debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch'
18--- debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch 1970-01-01 00:00:00 +0000
19+++ debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch 2014-08-13 12:23:14 +0000
20@@ -0,0 +1,372 @@
21+From 7640e387030962651f698765b64abbba938b0a82 Mon Sep 17 00:00:00 2001
22+From: Gunnar Sletta <gunnar.sletta@jollamobile.com>
23+Date: Thu, 15 May 2014 21:01:06 +0200
24+Subject: [PATCH] Fix crash with running animators on re-shown windows.
25+
26+The non-threaded render loops would clean up the nodes for a window
27+when it was hidden, but the animators kept running and had a reference
28+to the deleted nodes. This was not a problem for the threaded render
29+loop as it would wipe the animator controller as well which would
30+clean the jobs.
31+
32+Fix it by triggering a reset of all nodes in the animators when the
33+window is told to clean up. If an animator is ticked when it doesn't
34+have a node, it will simply do nothing. When the window is made visible
35+again, we call initialize on all animators to find the new node.
36+
37+Task-number: QTBUG-37995
38+Change-Id: Ie5609d95db29f4b2b30ca5bf641dce901e528389
39+---
40+ src/quick/items/qquickwindow.cpp | 1 +
41+ src/quick/util/qquickanimatorcontroller.cpp | 42 ++++++++-
42+ src/quick/util/qquickanimatorcontroller_p.h | 4 +
43+ src/quick/util/qquickanimatorjob.cpp | 26 ++++--
44+ src/quick/util/qquickanimatorjob_p.h | 4 +
45+ tests/auto/qmltest/animators/tst_multiwindow.qml | 103 +++++++++++++++++++++++
46+ 6 files changed, 171 insertions(+), 9 deletions(-)
47+ create mode 100644 tests/auto/qmltest/animators/tst_multiwindow.qml
48+
49+diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
50+index 16b48ef..5308d08 100644
51+--- a/src/quick/items/qquickwindow.cpp
52++++ b/src/quick/items/qquickwindow.cpp
53+@@ -2522,6 +2522,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown()
54+ QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
55+ for (; it != parentlessItems.end(); ++it)
56+ cleanupNodesOnShutdown(*it);
57++ animationController->windowNodesDestroyed();
58+ q->cleanupSceneGraph();
59+ }
60+
61+diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
62+index 7991dd8..697c25b 100644
63+--- a/src/quick/util/qquickanimatorcontroller.cpp
64++++ b/src/quick/util/qquickanimatorcontroller.cpp
65+@@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE
66+
67+ QQuickAnimatorController::QQuickAnimatorController()
68+ : m_window(0)
69++ , m_nodesAreInvalid(false)
70+ {
71+ }
72+
73+@@ -80,6 +81,26 @@ QQuickAnimatorController::~QQuickAnimatorController()
74+ }
75+ }
76+
77++static void qquickanimator_invalidate_node(QAbstractAnimationJob *job)
78++{
79++ if (job->isRenderThreadJob()) {
80++ static_cast<QQuickAnimatorJob *>(job)->nodeWasDestroyed();
81++ } else if (job->isGroup()) {
82++ QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
83++ for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
84++ qquickanimator_invalidate_node(a);
85++ }
86++}
87++
88++void QQuickAnimatorController::windowNodesDestroyed()
89++{
90++ m_nodesAreInvalid = true;
91++ for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
92++ it != m_animatorRoots.constEnd(); ++it) {
93++ qquickanimator_invalidate_node(it.key());
94++ }
95++}
96++
97+ void QQuickAnimatorController::itemDestroyed(QObject *o)
98+ {
99+ m_deletedSinceLastFrame << (QQuickItem *) o;
100+@@ -112,7 +133,7 @@ void QQuickAnimatorController::advance()
101+ m_window->update();
102+ }
103+
104+-static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c)
105++static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c, bool attachListener)
106+ {
107+ if (job->isRenderThreadJob()) {
108+ QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
109+@@ -121,13 +142,14 @@ static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorC
110+ } else if (c->m_deletedSinceLastFrame.contains(j->target())) {
111+ j->targetWasDeleted();
112+ } else {
113+- j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange);
114++ if (attachListener)
115++ j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange);
116+ j->initialize(c);
117+ }
118+ } else if (job->isGroup()) {
119+ QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
120+ for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
121+- qquick_initialize_helper(a, c);
122++ qquick_initialize_helper(a, c, attachListener);
123+ }
124+ }
125+
126+@@ -147,7 +169,7 @@ void QQuickAnimatorController::beforeNodeSync()
127+ foreach (QQuickAnimatorProxyJob *proxy, m_starting) {
128+ QAbstractAnimationJob *job = proxy->job();
129+ job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
130+- qquick_initialize_helper(job, this);
131++ qquick_initialize_helper(job, this, true);
132+ m_animatorRoots[job] = proxy;
133+ job->start();
134+ proxy->startedByController();
135+@@ -160,6 +182,18 @@ void QQuickAnimatorController::beforeNodeSync()
136+ }
137+ m_stopping.clear();
138+
139++ // First sync after a window was hidden or otherwise invalidated.
140++ // call initialize again to pick up new nodes..
141++ if (m_nodesAreInvalid) {
142++ for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
143++ it != m_animatorRoots.constEnd(); ++it) {
144++ qquick_initialize_helper(it.key(), this, false);
145++ }
146++ m_nodesAreInvalid = false;
147++ }
148++
149++
150++
151+ foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
152+ if (!job->target())
153+ continue;
154+diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h
155+index 6223a99..745a494 100644
156+--- a/src/quick/util/qquickanimatorcontroller_p.h
157++++ b/src/quick/util/qquickanimatorcontroller_p.h
158+@@ -76,6 +76,8 @@ public:
159+ void lock() { m_mutex.lock(); }
160+ void unlock() { m_mutex.unlock(); }
161+
162++ void windowNodesDestroyed();
163++
164+ public Q_SLOTS:
165+ void itemDestroyed(QObject *);
166+
167+@@ -92,6 +94,8 @@ public:
168+ QSet<QQuickItem *> m_deletedSinceLastFrame;
169+ QQuickWindow *m_window;
170+ QMutex m_mutex;
171++
172++ bool m_nodesAreInvalid;
173+ };
174+
175+ QT_END_NAMESPACE
176+diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
177+index 3bc4cef..0bf95a4 100644
178+--- a/src/quick/util/qquickanimatorjob.cpp
179++++ b/src/quick/util/qquickanimatorjob.cpp
180+@@ -281,6 +281,12 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
181+ }
182+ }
183+
184++void QQuickTransformAnimatorJob::nodeWasDestroyed()
185++{
186++ if (m_helper)
187++ m_helper->node = 0;
188++}
189++
190+ void QQuickTransformAnimatorJob::Helper::sync()
191+ {
192+ const quint32 mask = QQuickItemPrivate::Position
193+@@ -326,7 +332,7 @@ void QQuickTransformAnimatorJob::Helper::sync()
194+
195+ void QQuickTransformAnimatorJob::Helper::apply()
196+ {
197+- if (!wasChanged)
198++ if (!wasChanged || !node)
199+ return;
200+
201+ QMatrix4x4 m;
202+@@ -412,6 +418,11 @@ void QQuickOpacityAnimatorJob::initialize(QQuickAnimatorController *controller)
203+ }
204+ }
205+
206++void QQuickOpacityAnimatorJob::nodeWasDestroyed()
207++{
208++ m_opacityNode = 0;
209++}
210++
211+ void QQuickOpacityAnimatorJob::writeBack()
212+ {
213+ if (m_target)
214+@@ -420,7 +431,7 @@ void QQuickOpacityAnimatorJob::writeBack()
215+
216+ void QQuickOpacityAnimatorJob::updateCurrentTime(int time)
217+ {
218+- if (!m_controller)
219++ if (!m_controller || !m_opacityNode)
220+ return;
221+ Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
222+
223+@@ -504,13 +515,18 @@ void QQuickUniformAnimatorJob::setTarget(QQuickItem *target)
224+ m_target = target;
225+ }
226+
227++void QQuickUniformAnimatorJob::nodeWasDestroyed()
228++{
229++ m_node = 0;
230++ m_uniformIndex = -1;
231++ m_uniformType = -1;
232++}
233++
234+ void QQuickUniformAnimatorJob::afterNodeSync()
235+ {
236+ m_node = static_cast<QQuickShaderEffectNode *>(QQuickItemPrivate::get(m_target)->paintNode);
237+
238+- if (m_node) {
239+- m_uniformIndex = -1;
240+- m_uniformType = -1;
241++ if (m_node && m_uniformIndex == -1 && m_uniformType == -1) {
242+ QQuickShaderEffectMaterial *material =
243+ static_cast<QQuickShaderEffectMaterial *>(m_node->material());
244+ bool found = false;
245+diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
246+index 8aae121..03b13bc 100644
247+--- a/src/quick/util/qquickanimatorjob_p.h
248++++ b/src/quick/util/qquickanimatorjob_p.h
249+@@ -131,6 +131,7 @@ public:
250+ void targetWasDeleted();
251+ virtual void initialize(QQuickAnimatorController *controller);
252+ virtual void writeBack() = 0;
253++ virtual void nodeWasDestroyed() = 0;
254+
255+ bool isTransform() const { return m_isTransform; }
256+ bool isUniform() const { return m_isUniform; }
257+@@ -208,6 +209,7 @@ public:
258+ protected:
259+ QQuickTransformAnimatorJob();
260+ void initialize(QQuickAnimatorController *controller);
261++ void nodeWasDestroyed();
262+
263+ Helper *m_helper;
264+ };
265+@@ -256,6 +258,7 @@ public:
266+ void initialize(QQuickAnimatorController *controller);
267+ void updateCurrentTime(int time);
268+ void writeBack();
269++ void nodeWasDestroyed();
270+
271+ private:
272+ QSGOpacityNode *m_opacityNode;
273+@@ -275,6 +278,7 @@ public:
274+
275+ void updateCurrentTime(int time);
276+ void writeBack();
277++ void nodeWasDestroyed();
278+
279+ private:
280+ QByteArray m_uniform;
281+diff --git a/tests/auto/qmltest/animators/tst_multiwindow.qml b/tests/auto/qmltest/animators/tst_multiwindow.qml
282+new file mode 100644
283+index 0000000..7f7ca25
284+--- /dev/null
285++++ b/tests/auto/qmltest/animators/tst_multiwindow.qml
286+@@ -0,0 +1,103 @@
287++/****************************************************************************
288++**
289++** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
290++** Contact: http://www.qt-project.org/legal
291++**
292++** This file is part of the test suite of the Qt Toolkit.
293++**
294++** $QT_BEGIN_LICENSE:LGPL$
295++** Commercial License Usage
296++** Licensees holding valid commercial Qt licenses may use this file in
297++** accordance with the commercial license agreement provided with the
298++** Software or, alternatively, in accordance with the terms contained in
299++** a written agreement between you and Digia. For licensing terms and
300++** conditions see http://qt.digia.com/licensing. For further information
301++** use the contact form at http://qt.digia.com/contact-us.
302++**
303++** GNU Lesser General Public License Usage
304++** Alternatively, this file may be used under the terms of the GNU Lesser
305++** General Public License version 2.1 as published by the Free Software
306++** Foundation and appearing in the file LICENSE.LGPL included in the
307++** packaging of this file. Please review the following information to
308++** ensure the GNU Lesser General Public License version 2.1 requirements
309++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
310++**
311++** In addition, as a special exception, Digia gives you certain additional
312++** rights. These rights are described in the Digia Qt LGPL Exception
313++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
314++**
315++** GNU General Public License Usage
316++** Alternatively, this file may be used under the terms of the GNU
317++** General Public License version 3.0 as published by the Free Software
318++** Foundation and appearing in the file LICENSE.GPL included in the
319++** packaging of this file. Please review the following information to
320++** ensure the GNU General Public License version 3.0 requirements will be
321++** met: http://www.gnu.org/copyleft/gpl.html.
322++**
323++**
324++** $QT_END_LICENSE$
325++**
326++****************************************************************************/
327++
328++import QtQuick 2.2
329++import QtTest 1.0
330++import QtQuick.Window 2.0
331++
332++Item {
333++ id: root;
334++ width: 200
335++ height: 200
336++
337++ TestCase {
338++ id: testCase
339++ name: "animators-mixed"
340++ when: countdown == 0
341++ function test_endresult() {
342++ verify(true, "Just making sure we didn't crash");
343++ }
344++ }
345++
346++ property int countdown: 5;
347++
348++ Window {
349++ id: window
350++
351++ width: 100
352++ height: 100
353++
354++ ShaderEffect {
355++ width: 50
356++ height: 50
357++
358++ property real t;
359++ UniformAnimator on t { from: 0; to: 1; duration: 1000; loops: Animation.Infinite }
360++ RotationAnimator on rotation { from: 0; to: 360; duration: 1000; loops: Animation.Infinite }
361++ ScaleAnimator on scale { from: 0.5; to: 1.5; duration: 1000; loops: Animation.Infinite }
362++ XAnimator on x { from: 0; to: 50; duration: 1000; loops: Animation.Infinite }
363++ YAnimator on y { from: 0; to: 50; duration: 1000; loops: Animation.Infinite }
364++ OpacityAnimator on opacity { from: 1; to: 0.5; duration: 1000; loops: Animation.Infinite }
365++
366++ fragmentShader: "
367++ uniform lowp float t;
368++ uniform lowp float qt_Opacity;
369++ varying highp vec2 qt_TexCoord0;
370++ void main() {
371++ gl_FragColor = vec4(qt_TexCoord0, t, 1) * qt_Opacity;
372++ }
373++ "
374++ }
375++
376++ visible: true
377++ }
378++
379++ Timer {
380++ interval: 250
381++ running: true
382++ repeat: true
383++ onTriggered: {
384++ if (window.visible)
385++ --countdown
386++ window.visible = !window.visible;
387++ }
388++ }
389++}
390+--
391+2.1.0.rc1
392+
393
394=== modified file 'debian/patches/series'
395--- debian/patches/series 2014-08-04 08:09:32 +0000
396+++ debian/patches/series 2014-08-13 12:23:14 +0000
397@@ -10,3 +10,4 @@
398 Fix-interaction-of-garbage-collector-with-JS-objects.patch
399 Support-RFC2822Date-date-format-similar-to-V8.patch
400 8454a21b-Flickable-Cancel-interaction-on-interactive-changes.patch
401+Fix-crash-with-running-animators-on-re-shown-windows.patch

Subscribers

People subscribed via source and target branches