From abd8ff8b03038f349c8b54f094e500516e249f1b Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 4 Jan 2012 11:08:24 +1000 Subject: [PATCH] Prevent PathAnimation from hanging when jumping backwards to beginning. Task-number: QTBUG-23076 Change-Id: I2aecdfd28f0c3d45b3b805640edaecbd5be2e6fd Reviewed-by: Yunqiao Yin Reviewed-by: Michael Brasser --- src/quick/items/qquickanimation.cpp | 1 + src/quick/util/qdeclarativepath.cpp | 12 +++- src/quick/util/qdeclarativepath_p.h | 1 + .../data/pathInterpolatorBack2.qml | 10 +++ .../tst_qdeclarativeanimations.cpp | 81 +++++++++++++------- 5 files changed, 76 insertions(+), 29 deletions(-) create mode 100644 tests/auto/qtquick2/qdeclarativeanimations/data/pathInterpolatorBack2.qml diff --git a/src/quick/items/qquickanimation.cpp b/src/quick/items/qquickanimation.cpp index 34377e9..b64095d 100644 --- a/src/quick/items/qquickanimation.cpp +++ b/src/quick/items/qquickanimation.cpp @@ -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)); diff --git a/src/quick/util/qdeclarativepath.cpp b/src/quick/util/qdeclarativepath.cpp index 842b546..52d0245 100644 --- a/src/quick/util/qdeclarativepath.cpp +++ b/src/quick/util/qdeclarativepath.cpp @@ -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; } diff --git a/src/quick/util/qdeclarativepath_p.h b/src/quick/util/qdeclarativepath_p.h index 93e132e..fd8be57 100644 --- a/src/quick/util/qdeclarativepath_p.h +++ b/src/quick/util/qdeclarativepath_p.h @@ -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 index 0000000..eb3d4c3 --- /dev/null +++ b/tests/auto/qtquick2/qdeclarativeanimations/data/pathInterpolatorBack2.qml @@ -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 } + } +} diff --git a/tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp b/tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp index f580109..bc4e132 100644 --- a/tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp +++ b/tests/auto/qtquick2/qdeclarativeanimations/tst_qdeclarativeanimations.cpp @@ -322,34 +322,61 @@ void tst_qdeclarativeanimations::pathInterpolator() void tst_qdeclarativeanimations::pathInterpolatorBackwardJump() { - QDeclarativeEngine engine; - QDeclarativeComponent c(&engine, testFileUrl("pathInterpolatorBack.qml")); - QDeclarativePathInterpolator *interpolator = qobject_cast(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(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(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() -- 1.7.2.5