Prevent PathAnimation from hanging when jumping backwards to beginning.
authorMichael Brasser <michael.brasser@nokia.com>
Wed, 4 Jan 2012 01:08:24 +0000 (11:08 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 27 Jan 2012 05:23:00 +0000 (06:23 +0100)
Task-number: QTBUG-23076
Change-Id: I2aecdfd28f0c3d45b3b805640edaecbd5be2e6fd
Reviewed-by: Yunqiao Yin <charles.yin@nokia.com>
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
src/quick/items/qquickanimation.cpp
src/quick/util/qdeclarativepath.cpp
src/quick/util/qdeclarativepath_p.h
tests/auto/qtquick2/qdeclarativeanimations/data/pathInterpolatorBack2.qml [new file with mode: 0644]
tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp

index 34377e9..b64095d 100644 (file)
@@ -645,6 +645,7 @@ void QQuickPathAnimation::transition(QDeclarativeStateActions &actions,
         (modified.count() > origModifiedSize || data->toDefined)) {
         data->target = d->target;
         data->path = d->path;
+        data->path->invalidateSequentialHistory();
         if (!d->rangeIsSet) {
             d->pa->setStartValue(qreal(0));
             d->pa->setEndValue(qreal(1));
index 842b546..52d0245 100644 (file)
@@ -513,6 +513,12 @@ void QDeclarativePath::createPointCache() const
     }
 }
 
+void QDeclarativePath::invalidateSequentialHistory() const
+{
+    Q_D(const QDeclarativePath);
+    d->prevBez.isValid = false;
+}
+
 QPointF QDeclarativePath::sequentialPointAt(qreal p, qreal *angle) const
 {
     Q_D(const QDeclarativePath);
@@ -590,7 +596,7 @@ QPointF QDeclarativePath::backwardsPointAt(const QPainterPath &path, const qreal
     if (pathLength <= 0 || qIsNaN(pathLength))
         return path.pointAtPercent(0);
 
-    const int firstElement = 0;
+    const int firstElement = 1; //element 0 is always a MoveTo, which we ignore
     bool haveCachedBez = prevBez.isValid;
     int currElement = haveCachedBez ? prevBez.element : path.elementCount();
     qreal bezLength = haveCachedBez ? prevBez.bezLength : 0;
@@ -612,7 +618,9 @@ QPointF QDeclarativePath::backwardsPointAt(const QPainterPath &path, const qreal
                 Q_ASSERT(!(currElement < firstElement));
                 Q_UNUSED(firstElement);
                 currBez = nextBezier(path, &currElement, &bezLength, true /*reverse*/);
-                currLength = prevLength;
+                //special case for first element is to avoid floating point math
+                //causing an epc that never hits 0.
+                currLength = (currElement == firstElement) ? bezLength : prevLength;
                 prevLength = currLength - bezLength;
                 epc = prevLength / pathLength;
             }
index 93e132e..fd8be57 100644 (file)
@@ -385,6 +385,7 @@ public:
     qreal attributeAt(const QString &, qreal) const;
     QPointF pointAt(qreal) const;
     QPointF sequentialPointAt(qreal p, qreal *angle = 0) const;
+    void invalidateSequentialHistory() const;
 
 Q_SIGNALS:
     void changed();
diff --git a/tests/auto/qtquick2/qdeclarativeanimations/data/pathInterpolatorBack2.qml b/tests/auto/qtquick2/qdeclarativeanimations/data/pathInterpolatorBack2.qml
new file mode 100644 (file)
index 0000000..eb3d4c3
--- /dev/null
@@ -0,0 +1,10 @@
+import QtQuick 2.0
+
+PathInterpolator {
+    path: Path {
+        startX: 200; startY: 280
+        PathCurve { x: 150; y: 280 }
+        PathCurve { x: 150; y: 80 }
+        PathCurve { x: 0; y: 80 }
+    }
+}
index f580109..bc4e132 100644 (file)
@@ -322,34 +322,61 @@ void tst_qdeclarativeanimations::pathInterpolator()
 
 void tst_qdeclarativeanimations::pathInterpolatorBackwardJump()
 {
-    QDeclarativeEngine engine;
-    QDeclarativeComponent c(&engine, testFileUrl("pathInterpolatorBack.qml"));
-    QDeclarativePathInterpolator *interpolator = qobject_cast<QDeclarativePathInterpolator*>(c.create());
-    QVERIFY(interpolator);
-
-    QCOMPARE(interpolator->progress(), qreal(0));
-    QCOMPARE(interpolator->x(), qreal(50));
-    QCOMPARE(interpolator->y(), qreal(50));
-    QCOMPARE(interpolator->angle(), qreal(270));
-
-    interpolator->setProgress(.5);
-    QCOMPARE(interpolator->progress(), qreal(.5));
-    QCOMPARE(interpolator->x(), qreal(100));
-    QCOMPARE(interpolator->y(), qreal(75));
-    QCOMPARE(interpolator->angle(), qreal(90));
-
-    interpolator->setProgress(1);
-    QCOMPARE(interpolator->progress(), qreal(1));
-    QCOMPARE(interpolator->x(), qreal(200));
-    QCOMPARE(interpolator->y(), qreal(50));
-    QCOMPARE(interpolator->angle(), qreal(0));
+    {
+        QDeclarativeEngine engine;
+        QDeclarativeComponent c(&engine, testFileUrl("pathInterpolatorBack.qml"));
+        QDeclarativePathInterpolator *interpolator = qobject_cast<QDeclarativePathInterpolator*>(c.create());
+        QVERIFY(interpolator);
+
+        QCOMPARE(interpolator->progress(), qreal(0));
+        QCOMPARE(interpolator->x(), qreal(50));
+        QCOMPARE(interpolator->y(), qreal(50));
+        QCOMPARE(interpolator->angle(), qreal(270));
+
+        interpolator->setProgress(.5);
+        QCOMPARE(interpolator->progress(), qreal(.5));
+        QCOMPARE(interpolator->x(), qreal(100));
+        QCOMPARE(interpolator->y(), qreal(75));
+        QCOMPARE(interpolator->angle(), qreal(90));
+
+        interpolator->setProgress(1);
+        QCOMPARE(interpolator->progress(), qreal(1));
+        QCOMPARE(interpolator->x(), qreal(200));
+        QCOMPARE(interpolator->y(), qreal(50));
+        QCOMPARE(interpolator->angle(), qreal(0));
+
+        //make sure we don't get caught in infinite loop here
+        interpolator->setProgress(0);
+        QCOMPARE(interpolator->progress(), qreal(0));
+        QCOMPARE(interpolator->x(), qreal(50));
+        QCOMPARE(interpolator->y(), qreal(50));
+        QCOMPARE(interpolator->angle(), qreal(270));
+    }
 
-    //make sure we don't get caught in infinite loop here
-    interpolator->setProgress(0);
-    QCOMPARE(interpolator->progress(), qreal(0));
-    QCOMPARE(interpolator->x(), qreal(50));
-    QCOMPARE(interpolator->y(), qreal(50));
-    QCOMPARE(interpolator->angle(), qreal(270));
+    {
+        QDeclarativeEngine engine;
+        QDeclarativeComponent c(&engine, testFileUrl("pathInterpolatorBack2.qml"));
+        QDeclarativePathInterpolator *interpolator = qobject_cast<QDeclarativePathInterpolator*>(c.create());
+        QVERIFY(interpolator);
+
+        QCOMPARE(interpolator->progress(), qreal(0));
+        QCOMPARE(interpolator->x(), qreal(200));
+        QCOMPARE(interpolator->y(), qreal(280));
+        QCOMPARE(interpolator->angle(), qreal(180));
+
+        interpolator->setProgress(1);
+        QCOMPARE(interpolator->progress(), qreal(1));
+        QCOMPARE(interpolator->x(), qreal(0));
+        QCOMPARE(interpolator->y(), qreal(80));
+        QCOMPARE(interpolator->angle(), qreal(180));
+
+        //make sure we don't get caught in infinite loop here
+        interpolator->setProgress(0);
+        QCOMPARE(interpolator->progress(), qreal(0));
+        QCOMPARE(interpolator->x(), qreal(200));
+        QCOMPARE(interpolator->y(), qreal(280));
+        QCOMPARE(interpolator->angle(), qreal(180));
+    }
 }
 
 void tst_qdeclarativeanimations::pathWithNoStart()