=== modified file 'debian/changelog'
--- debian/changelog	2014-08-04 11:27:03 +0000
+++ debian/changelog	2014-08-13 12:23:14 +0000
@@ -1,3 +1,11 @@
+qtdeclarative-opensource-src (5.3.0-3ubuntu9) utopic; urgency=medium
+
+  * 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)
+
+ -- Timo Jyrinki <timo-jyrinki@ubuntu.com>  Wed, 13 Aug 2014 12:18:47 +0000
+
 qtdeclarative-opensource-src (5.3.0-3ubuntu8) utopic; urgency=medium
 
   [ Michał Sawicz ]

=== added file 'debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch'
--- debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch	1970-01-01 00:00:00 +0000
+++ debian/patches/Fix-crash-with-running-animators-on-re-shown-windows.patch	2014-08-13 12:23:14 +0000
@@ -0,0 +1,372 @@
+From 7640e387030962651f698765b64abbba938b0a82 Mon Sep 17 00:00:00 2001
+From: Gunnar Sletta <gunnar.sletta@jollamobile.com>
+Date: Thu, 15 May 2014 21:01:06 +0200
+Subject: [PATCH] Fix crash with running animators on re-shown windows.
+
+The non-threaded render loops would clean up the nodes for a window
+when it was hidden, but the animators kept running and had a reference
+to the deleted nodes. This was not a problem for the threaded render
+loop as it would wipe the animator controller as well which would
+clean the jobs.
+
+Fix it by triggering a reset of all nodes in the animators when the
+window is told to clean up. If an animator is ticked when it doesn't
+have a node, it will simply do nothing. When the window is made visible
+again, we call initialize on all animators to find the new node.
+
+Task-number: QTBUG-37995
+Change-Id: Ie5609d95db29f4b2b30ca5bf641dce901e528389
+---
+ src/quick/items/qquickwindow.cpp                 |   1 +
+ src/quick/util/qquickanimatorcontroller.cpp      |  42 ++++++++-
+ src/quick/util/qquickanimatorcontroller_p.h      |   4 +
+ src/quick/util/qquickanimatorjob.cpp             |  26 ++++--
+ src/quick/util/qquickanimatorjob_p.h             |   4 +
+ tests/auto/qmltest/animators/tst_multiwindow.qml | 103 +++++++++++++++++++++++
+ 6 files changed, 171 insertions(+), 9 deletions(-)
+ create mode 100644 tests/auto/qmltest/animators/tst_multiwindow.qml
+
+diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
+index 16b48ef..5308d08 100644
+--- a/src/quick/items/qquickwindow.cpp
++++ b/src/quick/items/qquickwindow.cpp
+@@ -2522,6 +2522,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown()
+     QSet<QQuickItem *>::const_iterator it = parentlessItems.begin();
+     for (; it != parentlessItems.end(); ++it)
+         cleanupNodesOnShutdown(*it);
++    animationController->windowNodesDestroyed();
+     q->cleanupSceneGraph();
+ }
+ 
+diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
+index 7991dd8..697c25b 100644
+--- a/src/quick/util/qquickanimatorcontroller.cpp
++++ b/src/quick/util/qquickanimatorcontroller.cpp
+@@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE
+ 
+ QQuickAnimatorController::QQuickAnimatorController()
+     : m_window(0)
++    , m_nodesAreInvalid(false)
+ {
+ }
+ 
+@@ -80,6 +81,26 @@ QQuickAnimatorController::~QQuickAnimatorController()
+     }
+ }
+ 
++static void qquickanimator_invalidate_node(QAbstractAnimationJob *job)
++{
++    if (job->isRenderThreadJob()) {
++        static_cast<QQuickAnimatorJob *>(job)->nodeWasDestroyed();
++    } else if (job->isGroup()) {
++        QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
++        for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
++            qquickanimator_invalidate_node(a);
++    }
++}
++
++void QQuickAnimatorController::windowNodesDestroyed()
++{
++    m_nodesAreInvalid = true;
++    for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
++         it != m_animatorRoots.constEnd(); ++it) {
++        qquickanimator_invalidate_node(it.key());
++    }
++}
++
+ void QQuickAnimatorController::itemDestroyed(QObject *o)
+ {
+     m_deletedSinceLastFrame << (QQuickItem *) o;
+@@ -112,7 +133,7 @@ void QQuickAnimatorController::advance()
+         m_window->update();
+ }
+ 
+-static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c)
++static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c, bool attachListener)
+ {
+     if (job->isRenderThreadJob()) {
+         QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
+@@ -121,13 +142,14 @@ static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorC
+         } else if (c->m_deletedSinceLastFrame.contains(j->target())) {
+             j->targetWasDeleted();
+         } else {
+-            j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange);
++            if (attachListener)
++                j->addAnimationChangeListener(c, QAbstractAnimationJob::StateChange);
+             j->initialize(c);
+         }
+     } else if (job->isGroup()) {
+         QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
+         for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
+-            qquick_initialize_helper(a, c);
++            qquick_initialize_helper(a, c, attachListener);
+     }
+ }
+ 
+@@ -147,7 +169,7 @@ void QQuickAnimatorController::beforeNodeSync()
+     foreach (QQuickAnimatorProxyJob *proxy, m_starting) {
+         QAbstractAnimationJob *job = proxy->job();
+         job->addAnimationChangeListener(this, QAbstractAnimationJob::Completion);
+-        qquick_initialize_helper(job, this);
++        qquick_initialize_helper(job, this, true);
+         m_animatorRoots[job] = proxy;
+         job->start();
+         proxy->startedByController();
+@@ -160,6 +182,18 @@ void QQuickAnimatorController::beforeNodeSync()
+     }
+     m_stopping.clear();
+ 
++    // First sync after a window was hidden or otherwise invalidated.
++    // call initialize again to pick up new nodes..
++    if (m_nodesAreInvalid) {
++        for (QHash<QAbstractAnimationJob *, QQuickAnimatorProxyJob *>::const_iterator it = m_animatorRoots.constBegin();
++             it != m_animatorRoots.constEnd(); ++it) {
++            qquick_initialize_helper(it.key(), this, false);
++        }
++        m_nodesAreInvalid = false;
++    }
++
++
++
+     foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
+         if (!job->target())
+             continue;
+diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h
+index 6223a99..745a494 100644
+--- a/src/quick/util/qquickanimatorcontroller_p.h
++++ b/src/quick/util/qquickanimatorcontroller_p.h
+@@ -76,6 +76,8 @@ public:
+     void lock() { m_mutex.lock(); }
+     void unlock() { m_mutex.unlock(); }
+ 
++    void windowNodesDestroyed();
++
+ public Q_SLOTS:
+     void itemDestroyed(QObject *);
+ 
+@@ -92,6 +94,8 @@ public:
+     QSet<QQuickItem *> m_deletedSinceLastFrame;
+     QQuickWindow *m_window;
+     QMutex m_mutex;
++
++    bool m_nodesAreInvalid;
+ };
+ 
+ QT_END_NAMESPACE
+diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
+index 3bc4cef..0bf95a4 100644
+--- a/src/quick/util/qquickanimatorjob.cpp
++++ b/src/quick/util/qquickanimatorjob.cpp
+@@ -281,6 +281,12 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
+     }
+ }
+ 
++void QQuickTransformAnimatorJob::nodeWasDestroyed()
++{
++    if (m_helper)
++        m_helper->node = 0;
++}
++
+ void QQuickTransformAnimatorJob::Helper::sync()
+ {
+     const quint32 mask = QQuickItemPrivate::Position
+@@ -326,7 +332,7 @@ void QQuickTransformAnimatorJob::Helper::sync()
+ 
+ void QQuickTransformAnimatorJob::Helper::apply()
+ {
+-    if (!wasChanged)
++    if (!wasChanged || !node)
+         return;
+ 
+     QMatrix4x4 m;
+@@ -412,6 +418,11 @@ void QQuickOpacityAnimatorJob::initialize(QQuickAnimatorController *controller)
+     }
+ }
+ 
++void QQuickOpacityAnimatorJob::nodeWasDestroyed()
++{
++    m_opacityNode = 0;
++}
++
+ void QQuickOpacityAnimatorJob::writeBack()
+ {
+     if (m_target)
+@@ -420,7 +431,7 @@ void QQuickOpacityAnimatorJob::writeBack()
+ 
+ void QQuickOpacityAnimatorJob::updateCurrentTime(int time)
+ {
+-    if (!m_controller)
++    if (!m_controller || !m_opacityNode)
+         return;
+     Q_ASSERT(m_controller->m_window->openglContext()->thread() == QThread::currentThread());
+ 
+@@ -504,13 +515,18 @@ void QQuickUniformAnimatorJob::setTarget(QQuickItem *target)
+         m_target = target;
+ }
+ 
++void QQuickUniformAnimatorJob::nodeWasDestroyed()
++{
++    m_node = 0;
++    m_uniformIndex = -1;
++    m_uniformType = -1;
++}
++
+ void QQuickUniformAnimatorJob::afterNodeSync()
+ {
+     m_node = static_cast<QQuickShaderEffectNode *>(QQuickItemPrivate::get(m_target)->paintNode);
+ 
+-    if (m_node) {
+-        m_uniformIndex = -1;
+-        m_uniformType = -1;
++    if (m_node && m_uniformIndex == -1 && m_uniformType == -1) {
+         QQuickShaderEffectMaterial *material =
+                 static_cast<QQuickShaderEffectMaterial *>(m_node->material());
+         bool found = false;
+diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
+index 8aae121..03b13bc 100644
+--- a/src/quick/util/qquickanimatorjob_p.h
++++ b/src/quick/util/qquickanimatorjob_p.h
+@@ -131,6 +131,7 @@ public:
+     void targetWasDeleted();
+     virtual void initialize(QQuickAnimatorController *controller);
+     virtual void writeBack() = 0;
++    virtual void nodeWasDestroyed() = 0;
+ 
+     bool isTransform() const { return m_isTransform; }
+     bool isUniform() const { return m_isUniform; }
+@@ -208,6 +209,7 @@ public:
+ protected:
+     QQuickTransformAnimatorJob();
+     void initialize(QQuickAnimatorController *controller);
++    void nodeWasDestroyed();
+ 
+     Helper *m_helper;
+ };
+@@ -256,6 +258,7 @@ public:
+     void initialize(QQuickAnimatorController *controller);
+     void updateCurrentTime(int time);
+     void writeBack();
++    void nodeWasDestroyed();
+ 
+ private:
+     QSGOpacityNode *m_opacityNode;
+@@ -275,6 +278,7 @@ public:
+ 
+     void updateCurrentTime(int time);
+     void writeBack();
++    void nodeWasDestroyed();
+ 
+ private:
+     QByteArray m_uniform;
+diff --git a/tests/auto/qmltest/animators/tst_multiwindow.qml b/tests/auto/qmltest/animators/tst_multiwindow.qml
+new file mode 100644
+index 0000000..7f7ca25
+--- /dev/null
++++ b/tests/auto/qmltest/animators/tst_multiwindow.qml
+@@ -0,0 +1,103 @@
++/****************************************************************************
++**
++** Copyright (C) 2014 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
++** Contact: http://www.qt-project.org/legal
++**
++** This file is part of the test suite 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 Digia.  For licensing terms and
++** conditions see http://qt.digia.com/licensing.  For further information
++** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
++** Foundation and appearing in the file LICENSE.LGPL included in the
++** packaging of this file.  Please review the following information to
++** ensure the GNU Lesser General Public License version 2.1 requirements
++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
++**
++** In addition, as a special exception, Digia gives you certain additional
++** rights.  These rights are described in the Digia Qt LGPL Exception
++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
++**
++** GNU General Public License Usage
++** Alternatively, this file may be used under the terms of the GNU
++** General Public License version 3.0 as published by the Free Software
++** Foundation and appearing in the file LICENSE.GPL included in the
++** packaging of this file.  Please review the following information to
++** ensure the GNU General Public License version 3.0 requirements will be
++** met: http://www.gnu.org/copyleft/gpl.html.
++**
++**
++** $QT_END_LICENSE$
++**
++****************************************************************************/
++
++import QtQuick 2.2
++import QtTest 1.0
++import QtQuick.Window 2.0
++
++Item {
++    id: root;
++    width: 200
++    height: 200
++
++    TestCase {
++        id: testCase
++        name: "animators-mixed"
++        when: countdown == 0
++        function test_endresult() {
++            verify(true, "Just making sure we didn't crash");
++        }
++    }
++
++    property int countdown: 5;
++
++    Window {
++        id: window
++
++        width: 100
++        height: 100
++
++        ShaderEffect {
++            width: 50
++            height: 50
++
++            property real t;
++            UniformAnimator on t { from: 0; to: 1; duration: 1000; loops: Animation.Infinite }
++            RotationAnimator on rotation { from: 0; to: 360; duration: 1000; loops: Animation.Infinite }
++            ScaleAnimator on scale { from: 0.5; to: 1.5; duration: 1000; loops: Animation.Infinite }
++            XAnimator on x { from: 0; to: 50; duration: 1000; loops: Animation.Infinite }
++            YAnimator on y { from: 0; to: 50; duration: 1000; loops: Animation.Infinite }
++            OpacityAnimator on opacity { from: 1; to: 0.5; duration: 1000; loops: Animation.Infinite }
++
++            fragmentShader: "
++                uniform lowp float t;
++                uniform lowp float qt_Opacity;
++                varying highp vec2 qt_TexCoord0;
++                void main() {
++                    gl_FragColor = vec4(qt_TexCoord0, t, 1) * qt_Opacity;
++                }
++                "
++        }
++
++        visible: true
++    }
++
++    Timer {
++        interval: 250
++        running: true
++        repeat: true
++        onTriggered: {
++            if (window.visible)
++                --countdown
++            window.visible = !window.visible;
++        }
++    }
++}
+-- 
+2.1.0.rc1
+

=== modified file 'debian/patches/series'
--- debian/patches/series	2014-08-04 08:09:32 +0000
+++ debian/patches/series	2014-08-13 12:23:14 +0000
@@ -10,3 +10,4 @@
 Fix-interaction-of-garbage-collector-with-JS-objects.patch
 Support-RFC2822Date-date-format-similar-to-V8.patch
 8454a21b-Flickable-Cancel-interaction-on-interactive-changes.patch
+Fix-crash-with-running-animators-on-re-shown-windows.patch

