1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include <QtQml/qqmlengine.h>
43 #include <QtQml/qqmlcomponent.h>
44 #include <QtQuick/qquickview.h>
45 #include <QtQuick/private/qquickrectangle_p.h>
46 #include <private/qquickimage_p.h>
47 #include <private/qquickanimatedimage_p.h>
49 #include <QtQml/qqmlcontext.h>
51 #include "../../shared/testhttpserver.h"
52 #include "../../shared/util.h"
54 Q_DECLARE_METATYPE(QQuickImageBase::Status)
56 class tst_qquickanimatedimage : public QQmlDataTest
60 tst_qquickanimatedimage() {}
69 void mirror_running();
70 void mirror_notRunning();
71 void mirror_notRunning_data();
75 void sourceSizeChanges();
76 void sourceSizeReadOnly();
79 void progressAndStatusChanges();
80 void playingAndPausedChanges();
83 void tst_qquickanimatedimage::cleanup()
86 window.releaseResources();
89 void tst_qquickanimatedimage::play()
92 QQmlComponent component(&engine, testFileUrl("stickman.qml"));
93 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
95 QVERIFY(anim->isPlaying());
100 void tst_qquickanimatedimage::pause()
103 QQmlComponent component(&engine, testFileUrl("stickmanpause.qml"));
104 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
107 QTRY_VERIFY(anim->isPaused());
108 QTRY_VERIFY(anim->isPlaying());
113 void tst_qquickanimatedimage::stopped()
116 QQmlComponent component(&engine, testFileUrl("stickmanstopped.qml"));
117 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
119 QTRY_VERIFY(!anim->isPlaying());
120 QCOMPARE(anim->currentFrame(), 0);
125 void tst_qquickanimatedimage::setFrame()
128 QQmlComponent component(&engine, testFileUrl("stickmanpause.qml"));
129 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
131 QVERIFY(anim->isPlaying());
132 QCOMPARE(anim->currentFrame(), 2);
137 void tst_qquickanimatedimage::frameCount()
140 QQmlComponent component(&engine, testFileUrl("colors.qml"));
141 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
143 QVERIFY(anim->isPlaying());
144 QCOMPARE(anim->frameCount(), 3);
149 void tst_qquickanimatedimage::mirror_running()
151 // test where mirror is set to true after animation has started
154 window.setSource(testFileUrl("hearts.qml"));
155 window.requestActivate();
157 QTest::qWaitForWindowActive(&window);
159 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(window.rootObject());
162 int width = anim->property("width").toInt();
164 QCOMPARE(anim->frameCount(), 2);
166 QCOMPARE(anim->currentFrame(), 0);
167 QImage frame0 = window.grabWindow();
169 anim->setCurrentFrame(1);
170 QCOMPARE(anim->currentFrame(), 1);
171 QImage frame1 = window.grabWindow();
173 anim->setCurrentFrame(0);
175 QSignalSpy spy(anim, SIGNAL(frameChanged()));
176 QVERIFY(spy.isValid());
177 anim->setPlaying(true);
179 QTRY_VERIFY(spy.count() == 1); spy.clear();
180 anim->setMirror(true);
182 QCOMPARE(anim->currentFrame(), 1);
183 QImage frame1_flipped = window.grabWindow();
185 QTRY_VERIFY(spy.count() == 1); spy.clear();
186 QCOMPARE(anim->currentFrame(), 0); // animation only has 2 frames, should cycle back to first
187 QImage frame0_flipped = window.grabWindow();
189 QTransform transform;
190 transform.translate(width, 0).scale(-1, 1.0);
191 QImage frame0_expected = frame0.transformed(transform);
192 QImage frame1_expected = frame1.transformed(transform);
194 QCOMPARE(frame0_flipped, frame0_expected);
195 QCOMPARE(frame1_flipped, frame1_expected);
200 void tst_qquickanimatedimage::mirror_notRunning()
202 QFETCH(QUrl, fileUrl);
207 window.setSource(fileUrl);
208 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(window.rootObject());
211 int width = anim->property("width").toInt();
212 QPixmap screenshot = QPixmap::fromImage(window.grabWindow());
214 QTransform transform;
215 transform.translate(width, 0).scale(-1, 1.0);
216 QPixmap expected = screenshot.transformed(transform);
218 int frame = anim->currentFrame();
219 bool playing = anim->isPlaying();
220 bool paused = anim->isPlaying();
222 anim->setProperty("mirror", true);
223 screenshot = QPixmap::fromImage(window.grabWindow());
225 QCOMPARE(screenshot, expected);
227 // mirroring should not change the current frame or playing status
228 QCOMPARE(anim->currentFrame(), frame);
229 QCOMPARE(anim->isPlaying(), playing);
230 QCOMPARE(anim->isPaused(), paused);
235 void tst_qquickanimatedimage::mirror_notRunning_data()
237 QTest::addColumn<QUrl>("fileUrl");
239 QTest::newRow("paused") << testFileUrl("stickmanpause.qml");
240 QTest::newRow("stopped") << testFileUrl("stickmanstopped.qml");
243 void tst_qquickanimatedimage::remote_data()
245 QTest::addColumn<QString>("fileName");
246 QTest::addColumn<bool>("paused");
248 QTest::newRow("playing") << "stickman.qml" << false;
249 QTest::newRow("paused") << "stickmanpause.qml" << true;
252 void tst_qquickanimatedimage::remote()
254 QFETCH(QString, fileName);
255 QFETCH(bool, paused);
257 TestHTTPServer server(14449);
258 QVERIFY(server.isValid());
259 server.serveDirectory(dataDirectory());
262 QQmlComponent component(&engine, QUrl("http://127.0.0.1:14449/" + fileName));
263 QTRY_VERIFY(component.isReady());
265 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
268 QTRY_VERIFY(anim->isPlaying());
270 QTRY_VERIFY(anim->isPaused());
271 QCOMPARE(anim->currentFrame(), 2);
273 QVERIFY(anim->status() != QQuickAnimatedImage::Error);
278 void tst_qquickanimatedimage::sourceSize()
281 QQmlComponent component(&engine, testFileUrl("stickmanscaled.qml"));
282 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
284 QCOMPARE(anim->width(),240.0);
285 QCOMPARE(anim->height(),180.0);
286 QCOMPARE(anim->sourceSize(),QSize(160,120));
291 void tst_qquickanimatedimage::sourceSizeReadOnly()
294 QQmlComponent component(&engine, testFileUrl("stickmanerror1.qml"));
295 QVERIFY(component.isError());
296 QCOMPARE(component.errors().at(0).description(), QString("Invalid property assignment: \"sourceSize\" is a read-only property"));
299 void tst_qquickanimatedimage::invalidSource()
302 QQmlComponent component(&engine);
303 component.setData("import QtQuick 2.0\n AnimatedImage { source: \"no-such-file.gif\" }", QUrl::fromLocalFile(""));
304 QVERIFY(component.isReady());
306 QTest::ignoreMessage(QtWarningMsg, "file::2:2: QML AnimatedImage: Error Reading Animated Image File file:no-such-file.gif");
308 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage *>(component.create());
311 QVERIFY(anim->isPlaying());
312 QVERIFY(!anim->isPaused());
313 QCOMPARE(anim->currentFrame(), 0);
314 QCOMPARE(anim->frameCount(), 0);
315 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Error);
320 void tst_qquickanimatedimage::sourceSizeChanges()
322 TestHTTPServer server(14449);
323 QVERIFY(server.isValid());
324 server.serveDirectory(dataDirectory());
327 QQmlComponent component(&engine);
328 component.setData("import QtQuick 2.0\nAnimatedImage { source: srcImage }", QUrl::fromLocalFile(""));
329 QTRY_VERIFY(component.isReady());
330 QQmlContext *ctxt = engine.rootContext();
331 ctxt->setContextProperty("srcImage", "");
332 QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage*>(component.create());
335 QSignalSpy sourceSizeSpy(anim, SIGNAL(sourceSizeChanged()));
338 ctxt->setContextProperty("srcImage", QUrl(""));
339 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Null);
340 QTRY_VERIFY(sourceSizeSpy.count() == 0);
342 ctxt->setContextProperty("srcImage", testFileUrl("hearts.gif"));
343 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
344 QTRY_VERIFY(sourceSizeSpy.count() == 1);
346 ctxt->setContextProperty("srcImage", testFileUrl("hearts.gif"));
347 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
348 QTRY_VERIFY(sourceSizeSpy.count() == 1);
350 ctxt->setContextProperty("srcImage", testFileUrl("hearts_copy.gif"));
351 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
352 QTRY_VERIFY(sourceSizeSpy.count() == 1);
354 ctxt->setContextProperty("srcImage", testFileUrl("colors.gif"));
355 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
356 QTRY_VERIFY(sourceSizeSpy.count() == 2);
358 ctxt->setContextProperty("srcImage", QUrl(""));
359 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Null);
360 QTRY_VERIFY(sourceSizeSpy.count() == 3);
363 ctxt->setContextProperty("srcImage", QUrl("http://127.0.0.1:14449/hearts.gif"));
364 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
365 QTRY_VERIFY(sourceSizeSpy.count() == 4);
367 ctxt->setContextProperty("srcImage", QUrl("http://127.0.0.1:14449/hearts.gif"));
368 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
369 QTRY_VERIFY(sourceSizeSpy.count() == 4);
371 ctxt->setContextProperty("srcImage", QUrl("http://127.0.0.1:14449/hearts_copy.gif"));
372 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
373 QTRY_VERIFY(sourceSizeSpy.count() == 4);
375 ctxt->setContextProperty("srcImage", QUrl("http://127.0.0.1:14449/colors.gif"));
376 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
377 QTRY_VERIFY(sourceSizeSpy.count() == 5);
379 ctxt->setContextProperty("srcImage", QUrl(""));
380 QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Null);
381 QTRY_VERIFY(sourceSizeSpy.count() == 6);
386 void tst_qquickanimatedimage::qtbug_16520()
388 TestHTTPServer server(14449);
389 QVERIFY(server.isValid());
390 server.serveDirectory(dataDirectory());
393 QQmlComponent component(&engine, testFileUrl("qtbug-16520.qml"));
394 QTRY_VERIFY(component.isReady());
396 QQuickRectangle *root = qobject_cast<QQuickRectangle *>(component.create());
398 QQuickAnimatedImage *anim = root->findChild<QQuickAnimatedImage*>("anim");
401 anim->setProperty("source", "http://127.0.0.1:14449/stickman.gif");
402 QTRY_VERIFY(anim->opacity() == 0);
403 QTRY_VERIFY(anim->opacity() == 1);
409 void tst_qquickanimatedimage::progressAndStatusChanges()
411 TestHTTPServer server(14449);
412 QVERIFY(server.isValid());
413 server.serveDirectory(dataDirectory());
416 QString componentStr = "import QtQuick 2.0\nAnimatedImage { source: srcImage }";
417 QQmlContext *ctxt = engine.rootContext();
418 ctxt->setContextProperty("srcImage", testFileUrl("stickman.gif"));
419 QQmlComponent component(&engine);
420 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
421 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
423 QVERIFY(obj->status() == QQuickImage::Ready);
424 QTRY_VERIFY(obj->progress() == 1.0);
426 qRegisterMetaType<QQuickImageBase::Status>();
427 QSignalSpy sourceSpy(obj, SIGNAL(sourceChanged(const QUrl &)));
428 QSignalSpy progressSpy(obj, SIGNAL(progressChanged(qreal)));
429 QSignalSpy statusSpy(obj, SIGNAL(statusChanged(QQuickImageBase::Status)));
432 ctxt->setContextProperty("srcImage", testFileUrl("stickman.gif"));
433 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
434 QTRY_VERIFY(obj->progress() == 1.0);
435 QTRY_COMPARE(sourceSpy.count(), 0);
436 QTRY_COMPARE(progressSpy.count(), 0);
437 QTRY_COMPARE(statusSpy.count(), 0);
439 // Loading local file
440 ctxt->setContextProperty("srcImage", testFileUrl("colors.gif"));
441 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
442 QTRY_VERIFY(obj->progress() == 1.0);
443 QTRY_COMPARE(sourceSpy.count(), 1);
444 QTRY_COMPARE(progressSpy.count(), 0);
445 QTRY_COMPARE(statusSpy.count(), 1);
447 // Loading remote file
448 ctxt->setContextProperty("srcImage", "http://127.0.0.1:14449/stickman.gif");
449 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
450 QTRY_VERIFY(obj->progress() == 0.0);
451 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
452 QTRY_VERIFY(obj->progress() == 1.0);
453 QTRY_COMPARE(sourceSpy.count(), 2);
454 QTRY_VERIFY(progressSpy.count() > 1);
455 QTRY_COMPARE(statusSpy.count(), 3);
457 ctxt->setContextProperty("srcImage", "");
458 QTRY_VERIFY(obj->status() == QQuickImage::Null);
459 QTRY_VERIFY(obj->progress() == 0.0);
460 QTRY_COMPARE(sourceSpy.count(), 3);
461 QTRY_VERIFY(progressSpy.count() > 2);
462 QTRY_COMPARE(statusSpy.count(), 4);
467 void tst_qquickanimatedimage::playingAndPausedChanges()
470 QString componentStr = "import QtQuick 2.0\nAnimatedImage { source: srcImage }";
471 QQmlContext *ctxt = engine.rootContext();
472 ctxt->setContextProperty("srcImage", QUrl(""));
473 QQmlComponent component(&engine);
474 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
475 QQuickAnimatedImage *obj = qobject_cast<QQuickAnimatedImage*>(component.create());
477 QVERIFY(obj->status() == QQuickAnimatedImage::Null);
478 QTRY_VERIFY(obj->isPlaying());
479 QTRY_VERIFY(!obj->isPaused());
480 QSignalSpy playingSpy(obj, SIGNAL(playingChanged()));
481 QSignalSpy pausedSpy(obj, SIGNAL(pausedChanged()));
484 obj->setProperty("playing", true);
485 obj->setProperty("paused", false);
486 QTRY_VERIFY(obj->isPlaying());
487 QTRY_VERIFY(!obj->isPaused());
488 QTRY_COMPARE(playingSpy.count(), 0);
489 QTRY_COMPARE(pausedSpy.count(), 0);
491 obj->setProperty("playing", false);
492 obj->setProperty("paused", true);
493 QTRY_VERIFY(!obj->isPlaying());
494 QTRY_VERIFY(obj->isPaused());
495 QTRY_COMPARE(playingSpy.count(), 1);
496 QTRY_COMPARE(pausedSpy.count(), 1);
498 obj->setProperty("playing", true);
499 obj->setProperty("paused", false);
500 QTRY_VERIFY(obj->isPlaying());
501 QTRY_VERIFY(!obj->isPaused());
502 QTRY_COMPARE(playingSpy.count(), 2);
503 QTRY_COMPARE(pausedSpy.count(), 2);
505 ctxt->setContextProperty("srcImage", testFileUrl("stickman.gif"));
506 QTRY_VERIFY(obj->isPlaying());
507 QTRY_VERIFY(!obj->isPaused());
508 QTRY_COMPARE(playingSpy.count(), 2);
509 QTRY_COMPARE(pausedSpy.count(), 2);
511 obj->setProperty("paused", true);
512 QTRY_VERIFY(obj->isPlaying());
513 QTRY_VERIFY(obj->isPaused());
514 QTRY_COMPARE(playingSpy.count(), 2);
515 QTRY_COMPARE(pausedSpy.count(), 3);
517 obj->setProperty("playing", false);
518 QTRY_VERIFY(!obj->isPlaying());
519 QTRY_VERIFY(!obj->isPaused());
520 QTRY_COMPARE(playingSpy.count(), 3);
521 QTRY_COMPARE(pausedSpy.count(), 4);
523 obj->setProperty("playing", true);
525 // Cannot animate this image, playing will be false
526 ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
527 QTRY_VERIFY(!obj->isPlaying());
528 QTRY_VERIFY(!obj->isPaused());
529 QTRY_COMPARE(playingSpy.count(), 5);
530 QTRY_COMPARE(pausedSpy.count(), 4);
534 QTEST_MAIN(tst_qquickanimatedimage)
536 #include "tst_qquickanimatedimage.moc"