Update obsolete contact address.
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick2 / qquickcanvas / tst_qquickcanvas.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qtest.h>
43 #include <QDebug>
44 #include <QTouchEvent>
45 #include <QtQuick/QQuickItem>
46 #include <QtQuick/QQuickCanvas>
47 #include <QtDeclarative/QDeclarativeEngine>
48 #include <QtDeclarative/QDeclarativeComponent>
49 #include <QtQuick/private/qquickrectangle_p.h>
50 #include <QtGui/QWindowSystemInterface>
51 #include "../../shared/util.h"
52 #include <QSignalSpy>
53
54 struct TouchEventData {
55     QEvent::Type type;
56     QWidget *widget;
57     QWindow *window;
58     Qt::TouchPointStates states;
59     QList<QTouchEvent::TouchPoint> touchPoints;
60 };
61
62 static QTouchEvent::TouchPoint makeTouchPoint(QQuickItem *item, const QPointF &p, const QPointF &lastPoint = QPointF())
63 {
64     QPointF last = lastPoint.isNull() ? p : lastPoint;
65
66     QTouchEvent::TouchPoint tp;
67
68     tp.setPos(p);
69     tp.setLastPos(last);
70     tp.setScenePos(item->mapToScene(p));
71     tp.setLastScenePos(item->mapToScene(last));
72     tp.setScreenPos(item->canvas()->mapToGlobal(tp.scenePos().toPoint()));
73     tp.setLastScreenPos(item->canvas()->mapToGlobal(tp.lastScenePos().toPoint()));
74     return tp;
75 }
76
77 static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states, const QList<QTouchEvent::TouchPoint>& touchPoints)
78 {
79     TouchEventData d = { type, 0, w, states, touchPoints };
80     return d;
81 }
82 static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, Qt::TouchPointStates states, const QTouchEvent::TouchPoint &touchPoint)
83 {
84     QList<QTouchEvent::TouchPoint> points;
85     points << touchPoint;
86     return makeTouchData(type, w, states, points);
87 }
88
89 #define COMPARE_TOUCH_POINTS(tp1, tp2) \
90 { \
91     QCOMPARE(tp1.pos(), tp2.pos()); \
92     QCOMPARE(tp1.lastPos(), tp2.lastPos()); \
93     QCOMPARE(tp1.scenePos(), tp2.scenePos()); \
94     QCOMPARE(tp1.lastScenePos(), tp2.lastScenePos()); \
95     QCOMPARE(tp1.screenPos(), tp2.screenPos()); \
96     QCOMPARE(tp1.lastScreenPos(), tp2.lastScreenPos()); \
97 }
98
99 #define COMPARE_TOUCH_DATA(d1, d2) \
100 { \
101     QCOMPARE((int)d1.type, (int)d2.type); \
102     QCOMPARE(d1.widget, d2.widget); \
103     QCOMPARE((int)d1.states, (int)d2.states); \
104     QCOMPARE(d1.touchPoints.count(), d2.touchPoints.count()); \
105     for (int i=0; i<d1.touchPoints.count(); i++) { \
106         COMPARE_TOUCH_POINTS(d1.touchPoints[i], d2.touchPoints[i]); \
107     } \
108 }
109
110 class TestTouchItem : public QQuickRectangle
111 {
112     Q_OBJECT
113 public:
114     TestTouchItem(QQuickItem *parent = 0)
115         : QQuickRectangle(parent), acceptEvents(true), mousePressId(0)
116     {
117         border()->setWidth(1);
118         setAcceptedMouseButtons(Qt::LeftButton);
119         setFiltersChildMouseEvents(true);
120     }
121
122     void reset() {
123         acceptEvents = true;
124         setEnabled(true);
125         setOpacity(1.0);
126
127         lastEvent = makeTouchData(QEvent::None, canvas(), 0, QList<QTouchEvent::TouchPoint>());//CHECK_VALID
128     }
129
130     static void clearMousePressCounter()
131     {
132         mousePressNum = 0;
133     }
134
135     bool acceptEvents;
136     TouchEventData lastEvent;
137     int mousePressId;
138 protected:
139     virtual void touchEvent(QTouchEvent *event) {
140         if (!acceptEvents) {
141             event->ignore();
142             return;
143         }
144         lastEvent = makeTouchData(event->type(), event->window(), event->touchPointStates(), event->touchPoints());
145         event->accept();
146     }
147
148     virtual void mousePressEvent(QMouseEvent *) {
149         mousePressId = ++mousePressNum;
150     }
151
152     bool childMouseEventFilter(QQuickItem *, QEvent *event) {
153         if (event->type() == QEvent::MouseButtonPress)
154             mousePressId = ++mousePressNum;
155         return false;
156     }
157
158     static int mousePressNum;
159 };
160
161 int TestTouchItem::mousePressNum = 0;
162
163 class ConstantUpdateItem : public QQuickItem
164 {
165 Q_OBJECT
166 public:
167     ConstantUpdateItem(QQuickItem *parent = 0) : QQuickItem(parent), iterations(0) {setFlag(ItemHasContents);}
168
169     int iterations;
170 protected:
171     QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){
172         iterations++;
173         update();
174         return 0;
175     }
176 };
177
178 class tst_qquickcanvas : public QDeclarativeDataTest
179 {
180     Q_OBJECT
181 public:
182
183 private slots:
184     void initTestCase()
185     {
186         QDeclarativeDataTest::initTestCase();
187         touchDevice = new QTouchDevice();
188         touchDevice->setType(QTouchDevice::TouchScreen);
189         QWindowSystemInterface::registerTouchDevice(touchDevice);
190     }
191
192
193     void constantUpdates();
194     void mouseFiltering();
195     void headless();
196
197     void touchEvent_basic();
198     void touchEvent_propagation();
199     void touchEvent_propagation_data();
200
201     void clearCanvas();
202
203     void qmlCreation();
204     void clearColor();
205
206     void grab();
207     void multipleWindows();
208
209     void animationsWhileHidden();
210
211 private:
212     QTouchDevice *touchDevice;
213 };
214
215 //If the item calls update inside updatePaintNode, it should schedule another update
216 void tst_qquickcanvas::constantUpdates()
217 {
218     QQuickCanvas canvas;
219     canvas.resize(250, 250);
220     ConstantUpdateItem item(canvas.rootItem());
221     canvas.show();
222     QTRY_VERIFY(item.iterations > 60);
223 }
224
225 void tst_qquickcanvas::touchEvent_basic()
226 {
227     TestTouchItem::clearMousePressCounter();
228
229     QQuickCanvas *canvas = new QQuickCanvas;
230     canvas->resize(250, 250);
231     canvas->move(100, 100);
232     canvas->show();
233
234     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
235     bottomItem->setObjectName("Bottom Item");
236     bottomItem->setSize(QSizeF(150, 150));
237
238     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
239     middleItem->setObjectName("Middle Item");
240     middleItem->setPos(QPointF(50, 50));
241     middleItem->setSize(QSizeF(150, 150));
242
243     TestTouchItem *topItem = new TestTouchItem(middleItem);
244     topItem->setObjectName("Top Item");
245     topItem->setPos(QPointF(50, 50));
246     topItem->setSize(QSizeF(150, 150));
247
248     QPointF pos(10, 10);
249
250     // press single point
251     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas);
252     QTest::qWait(50);
253
254     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
255
256     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
257     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
258     TouchEventData d = makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem,pos));
259     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
260     topItem->reset();
261
262     // press multiple points
263     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas)
264             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
265     QTest::qWait(50);
266     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
267     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
268     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
269     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
270     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
271     topItem->reset();
272     bottomItem->reset();
273
274     // touch point on top item moves to bottom item, but top item should still receive the event
275     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), canvas);
276     QTest::qWait(50);
277     QTest::touchEvent(canvas, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), canvas);
278     QTest::qWait(50);
279     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
280     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
281             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
282     topItem->reset();
283
284     // touch point on bottom item moves to top item, but bottom item should still receive the event
285     QTest::touchEvent(canvas, touchDevice).press(0, bottomItem->mapToScene(pos).toPoint(), canvas);
286     QTest::qWait(50);
287     QTest::touchEvent(canvas, touchDevice).move(0, topItem->mapToScene(pos).toPoint(), canvas);
288     QTest::qWait(50);
289     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
290     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, canvas, Qt::TouchPointMoved,
291             makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos)));
292     bottomItem->reset();
293
294     // a single stationary press on an item shouldn't cause an event
295     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), canvas);
296     QTest::qWait(50);
297     QTest::touchEvent(canvas, touchDevice).stationary(0)
298             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
299     QTest::qWait(50);
300     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);    // received press only, not stationary
301     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
302     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
303     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
304     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
305     topItem->reset();
306     bottomItem->reset();
307
308     // move touch point from top item to bottom, and release
309     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas);
310     QTest::qWait(50);
311     QTest::touchEvent(canvas, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(),canvas);
312     QTest::qWait(50);
313     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
314     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
315             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
316     topItem->reset();
317
318     // release while another point is pressed
319     QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas)
320             .press(1, bottomItem->mapToScene(pos).toPoint(), canvas);
321     QTest::qWait(50);
322     QTest::touchEvent(canvas, touchDevice).move(0, bottomItem->mapToScene(pos).toPoint(), canvas);
323     QTest::qWait(50);
324     QTest::touchEvent(canvas, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), canvas)
325                              .stationary(1);
326     QTest::qWait(50);
327     QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
328     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
329     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
330     COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, canvas, Qt::TouchPointReleased,
331             makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos))));
332     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
333     topItem->reset();
334     bottomItem->reset();
335
336     delete topItem;
337     delete middleItem;
338     delete bottomItem;
339     delete canvas;
340 }
341
342 void tst_qquickcanvas::touchEvent_propagation()
343 {
344     TestTouchItem::clearMousePressCounter();
345
346     QFETCH(bool, acceptEvents);
347     QFETCH(bool, enableItem);
348     QFETCH(qreal, itemOpacity);
349
350     QQuickCanvas *canvas = new QQuickCanvas;
351     canvas->resize(250, 250);
352     canvas->move(100, 100);
353     canvas->show();
354
355     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
356     bottomItem->setObjectName("Bottom Item");
357     bottomItem->setSize(QSizeF(150, 150));
358
359     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
360     middleItem->setObjectName("Middle Item");
361     middleItem->setPos(QPointF(50, 50));
362     middleItem->setSize(QSizeF(150, 150));
363
364     TestTouchItem *topItem = new TestTouchItem(middleItem);
365     topItem->setObjectName("Top Item");
366     topItem->setPos(QPointF(50, 50));
367     topItem->setSize(QSizeF(150, 150));
368
369     QPointF pos(10, 10);
370     QPoint pointInBottomItem = bottomItem->mapToScene(pos).toPoint();  // (10, 10)
371     QPoint pointInMiddleItem = middleItem->mapToScene(pos).toPoint();  // (60, 60) overlaps with bottomItem
372     QPoint pointInTopItem = topItem->mapToScene(pos).toPoint();  // (110, 110) overlaps with bottom & top items
373
374     // disable topItem
375     topItem->acceptEvents = acceptEvents;
376     topItem->setEnabled(enableItem);
377     topItem->setOpacity(itemOpacity);
378
379     // single touch to top item, should be received by middle item
380     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas);
381     QTest::qWait(50);
382     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
383     QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1);
384     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
385     COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
386             makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))));
387
388     // touch top and middle items, middle item should get both events
389     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas)
390             .press(1, pointInMiddleItem, canvas);
391     QTest::qWait(50);
392     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
393     QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2);
394     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
395     COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
396            (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos))
397                                               << makeTouchPoint(middleItem, pos) )));
398     middleItem->reset();
399
400     // disable middleItem as well
401     middleItem->acceptEvents = acceptEvents;
402     middleItem->setEnabled(enableItem);
403     middleItem->setOpacity(itemOpacity);
404
405     // touch top and middle items, bottom item should get all events
406     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas)
407             .press(1, pointInMiddleItem, canvas);
408     QTest::qWait(50);
409     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
410     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
411     QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
412     COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
413             (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))
414                                               << makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) )));
415     bottomItem->reset();
416
417     // disable bottom item as well
418     bottomItem->acceptEvents = acceptEvents;
419     bottomItem->setEnabled(enableItem);
420     bottomItem->setOpacity(itemOpacity);
421
422     // no events should be received
423     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas)
424             .press(1, pointInMiddleItem, canvas)
425             .press(2, pointInBottomItem, canvas);
426     QTest::qWait(50);
427     QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
428     QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
429     QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
430
431     topItem->reset();
432     middleItem->reset();
433     bottomItem->reset();
434
435     // disable middle item, touch on top item
436     middleItem->acceptEvents = acceptEvents;
437     middleItem->setEnabled(enableItem);
438     middleItem->setOpacity(itemOpacity);
439     QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas);
440     QTest::qWait(50);
441     if (!enableItem || itemOpacity == 0) {
442         // middle item is disabled or has 0 opacity, bottom item receives the event
443         QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
444         QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
445         QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
446         COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
447                 makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))));
448     } else {
449         // middle item ignores event, sends it to the top item (top-most child)
450         QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
451         QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
452         QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
453         COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed,
454                 makeTouchPoint(topItem, pos)));
455     }
456
457     delete topItem;
458     delete middleItem;
459     delete bottomItem;
460     delete canvas;
461 }
462
463 void tst_qquickcanvas::touchEvent_propagation_data()
464 {
465     QTest::addColumn<bool>("acceptEvents");
466     QTest::addColumn<bool>("enableItem");
467     QTest::addColumn<qreal>("itemOpacity");
468
469     QTest::newRow("disable events") << false << true << 1.0;
470     QTest::newRow("disable item") << true << false << 1.0;
471     QTest::newRow("opacity of 0") << true << true << 0.0;
472 }
473
474 void tst_qquickcanvas::clearCanvas()
475 {
476     QQuickCanvas *canvas = new QQuickCanvas;
477     QQuickItem *item = new QQuickItem;
478     item->setParentItem(canvas->rootItem());
479
480     QVERIFY(item->canvas() == canvas);
481
482     delete canvas;
483
484     QVERIFY(item->canvas() == 0);
485
486     delete item;
487 }
488
489 void tst_qquickcanvas::mouseFiltering()
490 {
491     TestTouchItem::clearMousePressCounter();
492
493     QQuickCanvas *canvas = new QQuickCanvas;
494     canvas->resize(250, 250);
495     canvas->move(100, 100);
496     canvas->show();
497
498     TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
499     bottomItem->setObjectName("Bottom Item");
500     bottomItem->setSize(QSizeF(150, 150));
501
502     TestTouchItem *middleItem = new TestTouchItem(bottomItem);
503     middleItem->setObjectName("Middle Item");
504     middleItem->setPos(QPointF(50, 50));
505     middleItem->setSize(QSizeF(150, 150));
506
507     TestTouchItem *topItem = new TestTouchItem(middleItem);
508     topItem->setObjectName("Top Item");
509     topItem->setPos(QPointF(50, 50));
510     topItem->setSize(QSizeF(150, 150));
511
512     QPoint pos(100, 100);
513
514     QTest::mousePress(canvas, Qt::LeftButton, 0, pos);
515
516     // Mouse filtering propagates down the stack, so the
517     // correct order is
518     // 1. middleItem filters event
519     // 2. bottomItem filters event
520     // 3. topItem receives event
521     QTRY_COMPARE(middleItem->mousePressId, 1);
522     QTRY_COMPARE(bottomItem->mousePressId, 2);
523     QTRY_COMPARE(topItem->mousePressId, 3);
524
525     delete canvas;
526 }
527
528 void tst_qquickcanvas::qmlCreation()
529 {
530     QDeclarativeEngine engine;
531     QDeclarativeComponent component(&engine);
532     component.loadUrl(testFileUrl("window.qml"));
533     QObject* created = component.create();
534     QVERIFY(created);
535
536     QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created);
537     QVERIFY(canvas);
538     QCOMPARE(canvas->clearColor(), QColor(Qt::green));
539
540     QQuickItem* item = canvas->findChild<QQuickItem*>("item");
541     QVERIFY(item);
542     QCOMPARE(item->canvas(), canvas);
543
544     delete canvas;
545 }
546
547 void tst_qquickcanvas::clearColor()
548 {
549     //### Can we examine rendering to make sure it is really blue?
550     QQuickCanvas *canvas = new QQuickCanvas;
551     canvas->resize(250, 250);
552     canvas->move(100, 100);
553     canvas->setClearColor(Qt::blue);
554     canvas->show();
555     QTest::qWaitForWindowShown(canvas);
556     QCOMPARE(canvas->clearColor(), QColor(Qt::blue));
557     delete canvas;
558 }
559
560 void tst_qquickcanvas::grab()
561 {
562     QQuickCanvas canvas;
563     canvas.setClearColor(Qt::red);
564
565     canvas.resize(250, 250);
566     canvas.show();
567
568     QImage content = canvas.grabFrameBuffer();
569     QCOMPARE(content.width(), canvas.width());
570     QCOMPARE(content.height(), canvas.height());
571     QCOMPARE((uint) content.convertToFormat(QImage::Format_RGB32).pixel(0, 0), (uint) 0xffff0000);
572 }
573
574 void tst_qquickcanvas::multipleWindows()
575 {
576     QList<QQuickCanvas *> windows;
577     for (int i=0; i<6; ++i) {
578         QQuickCanvas *c = new QQuickCanvas();
579         c->setClearColor(Qt::GlobalColor(Qt::red + i));
580         c->resize(300, 200);
581         c->setPos(100 + i * 30, 100 + i * 20);
582         c->show();
583         windows << c;
584         QVERIFY(c->visible());
585     }
586
587     // move them
588     for (int i=0; i<windows.size(); ++i) {
589         QQuickCanvas *c = windows.at(i);
590         c->setPos(c->x() - 10, c->y() - 10);
591     }
592
593     // resize them
594     for (int i=0; i<windows.size(); ++i) {
595         QQuickCanvas *c = windows.at(i);
596         c->resize(200, 150);
597     }
598
599     qDeleteAll(windows);
600 }
601
602 void tst_qquickcanvas::animationsWhileHidden()
603 {
604     QDeclarativeEngine engine;
605     QDeclarativeComponent component(&engine);
606     component.loadUrl(testFileUrl("AnimationsWhileHidden.qml"));
607     QObject* created = component.create();
608
609     QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created);
610     QVERIFY(canvas);
611     QVERIFY(canvas->visible());
612
613     // Now hide the window and verify that it went off screen
614     canvas->hide();
615     QTest::qWait(10);
616     QVERIFY(!canvas->visible());
617
618     // Running animaiton should cause it to become visible again shortly.
619     QTRY_VERIFY(canvas->visible());
620
621     delete canvas;
622 }
623
624
625 void tst_qquickcanvas::headless()
626 {
627     QDeclarativeEngine engine;
628     QDeclarativeComponent component(&engine);
629     component.loadUrl(testFileUrl("Headless.qml"));
630     QObject* created = component.create();
631
632     QQuickCanvas* canvas = qobject_cast<QQuickCanvas*>(created);
633     QVERIFY(canvas);
634
635     QTest::qWaitForWindowShown(canvas);
636     QVERIFY(canvas->visible());
637
638     QSignalSpy initialized(canvas, SIGNAL(sceneGraphInitialized()));
639     QSignalSpy invalidated(canvas, SIGNAL(sceneGraphInvalidated()));
640
641     // Verify that the canvas is alive and kicking
642     QVERIFY(canvas->openglContext() != 0);
643
644     // Store the visual result
645     QImage originalContent = canvas->grabFrameBuffer();
646
647     // Hide the canvas and verify signal emittion and GL context deletion
648     canvas->hide();
649     QCOMPARE(invalidated.size(), 1);
650     QVERIFY(canvas->openglContext() == 0);
651
652     // Destroy the native windowing system buffers
653     canvas->destroy();
654     QVERIFY(canvas->handle() == 0);
655
656     // Show and verify that we are back and running
657     canvas->show();
658     QTest::qWaitForWindowShown(canvas);
659
660     QCOMPARE(initialized.size(), 1);
661     QVERIFY(canvas->openglContext() != 0);
662
663     // Verify that the visual output is the same
664     QImage newContent = canvas->grabFrameBuffer();
665
666     QCOMPARE(originalContent, newContent);
667
668
669 }
670
671 QTEST_MAIN(tst_qquickcanvas)
672
673 #include "tst_qquickcanvas.moc"