Copy QSGEngine functions to QQuickCanvas.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qquickcanvas.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module 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 "qquickcanvas.h"
43 #include "qquickcanvas_p.h"
44
45 #include "qquickitem.h"
46 #include "qquickitem_p.h"
47
48 #include <private/qsgrenderer_p.h>
49 #include <private/qsgtexture_p.h>
50 #include <private/qsgflashnode_p.h>
51 #include <qsgengine.h>
52
53 #include <private/qguiapplication_p.h>
54 #include <QtGui/QInputPanel>
55
56 #include <private/qabstractanimation_p.h>
57
58 #include <QtGui/qpainter.h>
59 #include <QtGui/qevent.h>
60 #include <QtGui/qmatrix4x4.h>
61 #include <QtCore/qvarlengtharray.h>
62 #include <QtCore/qabstractanimation.h>
63 #include <QtDeclarative/qdeclarativeincubator.h>
64
65 #include <private/qdeclarativedebugtrace_p.h>
66
67 QT_BEGIN_NAMESPACE
68
69 #define QQUICK_CANVAS_TIMING
70 #ifdef QQUICK_CANVAS_TIMING
71 static bool qquick_canvas_timing = !qgetenv("QML_CANVAS_TIMING").isEmpty();
72 static QTime threadTimer;
73 static int syncTime;
74 static int renderTime;
75 static int swapTime;
76 #endif
77
78 DEFINE_BOOL_CONFIG_OPTION(qmlFixedAnimationStep, QML_FIXED_ANIMATION_STEP)
79 DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP)
80
81 extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
82
83 void QQuickCanvasPrivate::updateFocusItemTransform()
84 {
85     Q_Q(QQuickCanvas);
86     QQuickItem *focus = q->activeFocusItem();
87     if (focus && qApp->inputPanel()->inputItem() == focus)
88         qApp->inputPanel()->setInputItemTransform(QQuickItemPrivate::get(focus)->itemToCanvasTransform());
89 }
90
91 class QQuickCanvasIncubationController : public QObject, public QDeclarativeIncubationController
92 {
93 public:
94     QQuickCanvasIncubationController(QQuickCanvasPrivate *canvas)
95     : m_canvas(canvas), m_eventSent(false) {}
96
97 protected:
98     virtual bool event(QEvent *e)
99     {
100         if (e->type() == QEvent::User) {
101             Q_ASSERT(m_eventSent);
102
103             bool *amtp = m_canvas->thread->allowMainThreadProcessing();
104             while (incubatingObjectCount()) {
105                 if (amtp)
106                     incubateWhile(amtp);
107                 else
108                     incubateFor(5);
109                 QCoreApplication::processEvents();
110             }
111
112             m_eventSent = false;
113         }
114         return QObject::event(e);
115     }
116
117     virtual void incubatingObjectCountChanged(int count)
118     {
119         if (count && !m_eventSent) {
120             m_eventSent = true;
121             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
122         }
123     }
124
125 private:
126     QQuickCanvasPrivate *m_canvas;
127     bool m_eventSent;
128 };
129
130 class QQuickCanvasPlainRenderLoop : public QObject, public QQuickCanvasRenderLoop
131 {
132 public:
133     QQuickCanvasPlainRenderLoop()
134         : updatePending(false)
135         , animationRunning(false)
136     {
137     }
138
139     virtual void paint() {
140         updatePending = false;
141         if (animationRunning && animationDriver())
142             animationDriver()->advance();
143         polishItems();
144         syncSceneGraph();
145         makeCurrent();
146         glViewport(0, 0, size.width(), size.height());
147         renderSceneGraph(size);
148         swapBuffers();
149
150         if (animationRunning)
151             maybeUpdate();
152     }
153
154     virtual QImage grab() {
155         return qt_gl_read_framebuffer(size, false, false);
156     }
157
158     virtual void startRendering() {
159         if (!glContext()) {
160             createGLContext();
161             makeCurrent();
162             initializeSceneGraph();
163         } else {
164             makeCurrent();
165         }
166         maybeUpdate();
167     }
168
169     virtual void stopRendering() { }
170
171     virtual void maybeUpdate() {
172         if (!updatePending) {
173             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
174             updatePending = true;
175         }
176     }
177
178     virtual void animationStarted() {
179         animationRunning = true;
180         maybeUpdate();
181     }
182
183     virtual void animationStopped() {
184         animationRunning = false;
185     }
186
187     virtual bool isRunning() const { return glContext(); } // Event loop is always running...
188     virtual void resize(const QSize &s) { size = s; }
189     virtual void setWindowSize(const QSize &s) { size = s; }
190
191     bool event(QEvent *e) {
192         if (e->type() == QEvent::User) {
193             paint();
194             return true;
195         }
196         return QObject::event(e);
197     }
198
199     QSize size;
200
201     uint updatePending : 1;
202     uint animationRunning : 1;
203 };
204
205
206
207 /*
208 Focus behavior
209 ==============
210
211 Prior to being added to a valid canvas items can set and clear focus with no
212 effect.  Only once items are added to a canvas (by way of having a parent set that
213 already belongs to a canvas) do the focus rules apply.  Focus goes back to
214 having no effect if an item is removed from a canvas.
215
216 When an item is moved into a new focus scope (either being added to a canvas
217 for the first time, or having its parent changed), if the focus scope already has
218 a scope focused item that takes precedence over the item being added.  Otherwise,
219 the focus of the added tree is used.  In the case of of a tree of items being
220 added to a canvas for the first time, which may have a conflicted focus state (two
221 or more items in one scope having focus set), the same rule is applied item by item -
222 thus the first item that has focus will get it (assuming the scope doesn't already
223 have a scope focused item), and the other items will have their focus cleared.
224 */
225
226 /*
227   Threaded Rendering
228   ==================
229
230   The threaded rendering uses a number of different variables to track potential
231   states used to handle resizing, initial paint, grabbing and driving animations
232   while ALWAYS keeping the GL context in the rendering thread and keeping the
233   overhead of normal one-shot paints and vblank driven animations at a minimum.
234
235   Resize, initial show and grab suffer slightly in this model as they are locked
236   to the rendering in the rendering thread, but this is a necessary evil for
237   the system to work.
238
239   Variables that are used:
240
241   Private::animationRunning: This is true while the animations are running, and only
242   written to inside locks.
243
244   RenderThread::isGuiBlocked: This is used to indicate that the GUI thread owns the
245   lock. This variable is an integer to allow for recursive calls to lockInGui()
246   without using a recursive mutex. See isGuiBlockPending.
247
248   RenderThread::isPaintComplete: This variable is cleared when rendering starts and
249   set once rendering is complete. It is monitored in the paintEvent(),
250   resizeEvent() and grab() functions to force them to wait for rendering to
251   complete.
252
253   RenderThread::isGuiBlockPending: This variable is set in the render thread just
254   before the sync event is sent to the GUI thread. It is used to avoid deadlocks
255   in the case where render thread waits while waiting for GUI to pick up the sync
256   event and GUI thread gets a resizeEvent, the initial paintEvent or a grab.
257   When this happens, we use the
258   exhaustSyncEvent() function to do the sync right there and mark the coming
259   sync event to be discarded. There can only ever be one sync incoming.
260
261   RenderThread::isRenderBlock: This variable is true when animations are not
262   running and the render thread has gone to sleep, waiting for more to do.
263
264   RenderThread::isExternalUpdatePending: This variable is set to false when
265   a new render pass is started and to true in maybeUpdate(). It is an
266   indication to the render thread that another render pass needs to take
267   place, rather than the render thread going to sleep after completing its swap.
268
269   RenderThread::doGrab: This variable is set by the grab() function and
270   tells the renderer to do a grab after rendering is complete and before
271   swapping happens.
272
273   RenderThread::shouldExit: This variable is used to determine if the render
274   thread should do a nother pass. It is typically set as a result of show()
275   and unset as a result of hide() or during shutdown()
276
277   RenderThread::hasExited: Used by the GUI thread to synchronize the shutdown
278   after shouldExit has been set to true.
279  */
280
281 // #define FOCUS_DEBUG
282 // #define MOUSE_DEBUG
283 // #define TOUCH_DEBUG
284 // #define DIRTY_DEBUG
285 // #define THREAD_DEBUG
286
287 // #define FRAME_TIMING
288
289 #ifdef FRAME_TIMING
290 static QTime frameTimer;
291 int sceneGraphRenderTime;
292 int readbackTime;
293 #endif
294
295 QQuickItem::UpdatePaintNodeData::UpdatePaintNodeData()
296 : transformNode(0)
297 {
298 }
299
300 QQuickRootItem::QQuickRootItem()
301 {
302 }
303
304 void QQuickCanvas::exposeEvent(QExposeEvent *)
305 {
306     Q_D(QQuickCanvas);
307     d->thread->paint();
308 }
309
310 void QQuickCanvas::resizeEvent(QResizeEvent *)
311 {
312     Q_D(QQuickCanvas);
313     d->thread->resize(size());
314 }
315
316 void QQuickCanvas::animationStarted()
317 {
318     d_func()->thread->animationStarted();
319 }
320
321 void QQuickCanvas::animationStopped()
322 {
323     d_func()->thread->animationStopped();
324 }
325
326 void QQuickCanvas::showEvent(QShowEvent *)
327 {
328     Q_D(QQuickCanvas);
329     if (d->vsyncAnimations) {
330         if (!d->animationDriver) {
331             d->animationDriver = d->context->createAnimationDriver(this);
332             connect(d->animationDriver, SIGNAL(started()), this, SLOT(animationStarted()), Qt::DirectConnection);
333             connect(d->animationDriver, SIGNAL(stopped()), this, SLOT(animationStopped()), Qt::DirectConnection);
334         }
335         d->animationDriver->install();
336     }
337
338     if (!d->thread->isRunning()) {
339         d->thread->setWindowSize(size());
340         d->thread->startRendering();
341     }
342 }
343
344 void QQuickCanvas::hideEvent(QHideEvent *)
345 {
346     Q_D(QQuickCanvas);
347     d->thread->stopRendering();
348 }
349
350 void QQuickCanvas::focusOutEvent(QFocusEvent *)
351 {
352     Q_D(QQuickCanvas);
353     d->rootItem->setFocus(false);
354 }
355
356 void QQuickCanvas::focusInEvent(QFocusEvent *)
357 {
358     Q_D(QQuickCanvas);
359     d->rootItem->setFocus(true);
360 }
361
362
363 /*!
364     Sets weither this canvas should use vsync driven animations.
365
366     This option can only be set on one single QQuickCanvas, and that it's
367     vsync signal will then be used to drive all animations in the
368     process.
369
370     This feature is primarily useful for single QQuickCanvas, QML-only
371     applications.
372
373     \warning Enabling vsync on multiple QQuickCanvas instances has
374     undefined behavior.
375  */
376 void QQuickCanvas::setVSyncAnimations(bool enabled)
377 {
378     Q_D(QQuickCanvas);
379     if (visible()) {
380         qWarning("QQuickCanvas::setVSyncAnimations: Cannot be changed when widget is shown");
381         return;
382     }
383     d->vsyncAnimations = enabled;
384 }
385
386
387
388 /*!
389     Returns true if this canvas should use vsync driven animations;
390     otherwise returns false.
391  */
392 bool QQuickCanvas::vsyncAnimations() const
393 {
394     Q_D(const QQuickCanvas);
395     return d->vsyncAnimations;
396 }
397
398 void QQuickCanvasPrivate::initializeSceneGraph()
399 {
400     if (!context)
401         context = QSGContext::createDefaultContext();
402
403     if (context->isReady())
404         return;
405
406     QOpenGLContext *glctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
407     context->initialize(glctx);
408
409     Q_Q(QQuickCanvas);
410     QObject::connect(context->renderer(), SIGNAL(sceneGraphChanged()), q, SLOT(maybeUpdate()),
411                      Qt::DirectConnection);
412
413     if (!QQuickItemPrivate::get(rootItem)->itemNode()->parent()) {
414         context->rootNode()->appendChildNode(QQuickItemPrivate::get(rootItem)->itemNode());
415     }
416
417     engine = new QSGEngine();
418     engine->setCanvas(q);
419
420     emit q_func()->sceneGraphInitialized();
421 }
422
423 void QQuickCanvasPrivate::polishItems()
424 {
425     while (!itemsToPolish.isEmpty()) {
426         QSet<QQuickItem *>::Iterator iter = itemsToPolish.begin();
427         QQuickItem *item = *iter;
428         itemsToPolish.erase(iter);
429         QQuickItemPrivate::get(item)->polishScheduled = false;
430         item->updatePolish();
431     }
432     updateFocusItemTransform();
433 }
434
435
436 void QQuickCanvasPrivate::syncSceneGraph()
437 {
438     updateDirtyNodes();
439
440     // Copy the current state of clearing from canvas into renderer.
441     context->renderer()->setClearColor(clearColor);
442     QSGRenderer::ClearMode mode = QSGRenderer::ClearStencilBuffer | QSGRenderer::ClearDepthBuffer;
443     if (clearBeforeRendering)
444         mode |= QSGRenderer::ClearColorBuffer;
445     context->renderer()->setClearMode(mode);
446 }
447
448
449 void QQuickCanvasPrivate::renderSceneGraph(const QSize &size)
450 {
451     Q_Q(QQuickCanvas);
452     context->renderer()->setDeviceRect(QRect(QPoint(0, 0), size));
453     context->renderer()->setViewportRect(QRect(QPoint(0, 0), renderTarget ? renderTarget->size() : size));
454     context->renderer()->setProjectionMatrixToDeviceRect();
455
456     emit q->beforeRendering();
457     context->renderNextFrame(renderTarget);
458     emit q->afterRendering();
459
460 #ifdef FRAME_TIMING
461     sceneGraphRenderTime = frameTimer.elapsed();
462 #endif
463
464 #ifdef FRAME_TIMING
465 //    int pixel;
466 //    glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
467     readbackTime = frameTimer.elapsed();
468 #endif
469 }
470
471
472 // ### Do we need this?
473 void QQuickCanvas::sceneGraphChanged()
474 {
475 //    Q_D(QQuickCanvas);
476 //    d->needsRepaint = true;
477 }
478
479 QQuickCanvasPrivate::QQuickCanvasPrivate()
480     : rootItem(0)
481     , activeFocusItem(0)
482     , mouseGrabberItem(0)
483     , dirtyItemList(0)
484     , context(0)
485     , clearColor(Qt::white)
486     , vsyncAnimations(false)
487     , clearBeforeRendering(true)
488     , thread(0)
489     , animationDriver(0)
490     , renderTarget(0)
491     , incubationController(0)
492 {
493 }
494
495 QQuickCanvasPrivate::~QQuickCanvasPrivate()
496 {
497 }
498
499 void QQuickCanvasPrivate::init(QQuickCanvas *c)
500 {
501     QUnifiedTimer* ut = QUnifiedTimer::instance(true);
502     if (qmlFixedAnimationStep())
503         ut->setConsistentTiming(true);
504
505     q_ptr = c;
506
507     Q_Q(QQuickCanvas);
508
509     rootItem = new QQuickRootItem;
510     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(rootItem);
511     rootItemPrivate->canvas = q;
512     rootItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
513
514     // In the absence of a focus in event on some platforms assume the window will
515     // be activated immediately and set focus on the rootItem
516     // ### Remove when QTBUG-22415 is resolved.
517     //It is important that this call happens after the rootItem has a canvas..
518     rootItem->setFocus(true);
519
520     bool threaded = !qmlNoThreadedRenderer();
521
522     if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL)) {
523         qWarning("QQuickCanvas: platform does not support threaded rendering!");
524         threaded = false;
525     }
526
527     if (threaded)
528         thread = new QQuickCanvasRenderThread();
529     else
530         thread = new QQuickCanvasPlainRenderLoop();
531
532     thread->renderer = q;
533     thread->d = this;
534
535     context = QSGContext::createDefaultContext();
536     thread->moveContextToThread(context);
537
538     q->setSurfaceType(QWindow::OpenGLSurface);
539     q->setFormat(context->defaultSurfaceFormat());
540 }
541
542 void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
543 {
544     for (int i=0; i<touchPoints.count(); i++) {
545         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
546         touchPoint.setRect(transform.mapRect(touchPoint.sceneRect()));
547         touchPoint.setStartPos(transform.map(touchPoint.startScenePos()));
548         touchPoint.setLastPos(transform.map(touchPoint.lastScenePos()));
549     }
550 }
551
552
553 /*!
554 Translates the data in \a touchEvent to this canvas.  This method leaves the item local positions in
555 \a touchEvent untouched (these are filled in later).
556 */
557 void QQuickCanvasPrivate::translateTouchEvent(QTouchEvent *touchEvent)
558 {
559 //    Q_Q(QQuickCanvas);
560
561 //    touchEvent->setWidget(q); // ### refactor...
562
563     QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
564     for (int i = 0; i < touchPoints.count(); ++i) {
565         QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
566
567         touchPoint.setScreenRect(touchPoint.sceneRect());
568         touchPoint.setStartScreenPos(touchPoint.startScenePos());
569         touchPoint.setLastScreenPos(touchPoint.lastScenePos());
570
571         touchPoint.setSceneRect(touchPoint.rect());
572         touchPoint.setStartScenePos(touchPoint.startPos());
573         touchPoint.setLastScenePos(touchPoint.lastPos());
574
575         if (touchPoint.isPrimary())
576             lastMousePosition = touchPoint.pos().toPoint();
577     }
578     touchEvent->setTouchPoints(touchPoints);
579 }
580
581 void QQuickCanvasPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
582 {
583     Q_Q(QQuickCanvas);
584
585     Q_ASSERT(item);
586     Q_ASSERT(scope || item == rootItem);
587
588 #ifdef FOCUS_DEBUG
589     qWarning() << "QQuickCanvasPrivate::setFocusInScope():";
590     qWarning() << "    scope:" << (QObject *)scope;
591     if (scope)
592         qWarning() << "    scopeSubFocusItem:" << (QObject *)QQuickItemPrivate::get(scope)->subFocusItem;
593     qWarning() << "    item:" << (QObject *)item;
594     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
595 #endif
596
597     QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
598     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
599
600     QQuickItem *oldActiveFocusItem = 0;
601     QQuickItem *newActiveFocusItem = 0;
602
603     QVarLengthArray<QQuickItem *, 20> changed;
604
605     // Does this change the active focus?
606     if (item == rootItem || scopePrivate->activeFocus) {
607         oldActiveFocusItem = activeFocusItem;
608         newActiveFocusItem = item;
609         while (newActiveFocusItem->isFocusScope() && newActiveFocusItem->scopedFocusItem())
610             newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
611
612         if (oldActiveFocusItem) {
613 #ifndef QT_NO_IM
614             qApp->inputPanel()->commit();
615 #endif
616
617             activeFocusItem = 0;
618             QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
619             q->sendEvent(oldActiveFocusItem, &event);
620
621             QQuickItem *afi = oldActiveFocusItem;
622             while (afi != scope) {
623                 if (QQuickItemPrivate::get(afi)->activeFocus) {
624                     QQuickItemPrivate::get(afi)->activeFocus = false;
625                     changed << afi;
626                 }
627                 afi = afi->parentItem();
628             }
629         }
630     }
631
632     if (item != rootItem) {
633         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
634         // Correct focus chain in scope
635         if (oldSubFocusItem) {
636             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
637             while (sfi != scope) {
638                 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
639                 sfi = sfi->parentItem();
640             }
641         }
642         {
643             scopePrivate->subFocusItem = item;
644             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
645             while (sfi != scope) {
646                 QQuickItemPrivate::get(sfi)->subFocusItem = item;
647                 sfi = sfi->parentItem();
648             }
649         }
650
651         if (oldSubFocusItem) {
652             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
653             changed << oldSubFocusItem;
654         }
655     }
656
657     if (!(options & DontChangeFocusProperty)) {
658 //        if (item != rootItem || QGuiApplication::focusWindow() == q) {    // QTBUG-22415
659             itemPrivate->focus = true;
660             changed << item;
661 //        }
662     }
663
664     if (newActiveFocusItem && rootItem->hasFocus()) {
665         activeFocusItem = newActiveFocusItem;
666
667         QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
668         changed << newActiveFocusItem;
669
670         QQuickItem *afi = newActiveFocusItem->parentItem();
671         while (afi && afi != scope) {
672             if (afi->isFocusScope()) {
673                 QQuickItemPrivate::get(afi)->activeFocus = true;
674                 changed << afi;
675             }
676             afi = afi->parentItem();
677         }
678
679         updateInputMethodData();
680
681         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
682         q->sendEvent(newActiveFocusItem, &event);
683     } else {
684         updateInputMethodData();
685     }
686
687     if (!changed.isEmpty())
688         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
689 }
690
691 void QQuickCanvasPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, FocusOptions options)
692 {
693     Q_Q(QQuickCanvas);
694
695     Q_UNUSED(item);
696     Q_ASSERT(item);
697     Q_ASSERT(scope || item == rootItem);
698
699 #ifdef FOCUS_DEBUG
700     qWarning() << "QQuickCanvasPrivate::clearFocusInScope():";
701     qWarning() << "    scope:" << (QObject *)scope;
702     qWarning() << "    item:" << (QObject *)item;
703     qWarning() << "    activeFocusItem:" << (QObject *)activeFocusItem;
704 #endif
705
706     QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
707
708     QQuickItem *oldActiveFocusItem = 0;
709     QQuickItem *newActiveFocusItem = 0;
710
711     QVarLengthArray<QQuickItem *, 20> changed;
712
713     Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
714
715     // Does this change the active focus?
716     if (item == rootItem || scopePrivate->activeFocus) {
717         oldActiveFocusItem = activeFocusItem;
718         newActiveFocusItem = scope;
719
720         Q_ASSERT(oldActiveFocusItem);
721
722 #ifndef QT_NO_IM
723         qApp->inputPanel()->commit();
724 #endif
725
726         activeFocusItem = 0;
727         QFocusEvent event(QEvent::FocusOut, Qt::OtherFocusReason);
728         q->sendEvent(oldActiveFocusItem, &event);
729
730         QQuickItem *afi = oldActiveFocusItem;
731         while (afi != scope) {
732             if (QQuickItemPrivate::get(afi)->activeFocus) {
733                 QQuickItemPrivate::get(afi)->activeFocus = false;
734                 changed << afi;
735             }
736             afi = afi->parentItem();
737         }
738     }
739
740     if (item != rootItem) {
741         QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
742         // Correct focus chain in scope
743         if (oldSubFocusItem) {
744             QQuickItem *sfi = scopePrivate->subFocusItem->parentItem();
745             while (sfi != scope) {
746                 QQuickItemPrivate::get(sfi)->subFocusItem = 0;
747                 sfi = sfi->parentItem();
748             }
749         }
750         scopePrivate->subFocusItem = 0;
751
752         if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
753             QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
754             changed << oldSubFocusItem;
755         }
756     } else if (!(options & DontChangeFocusProperty)) {
757         QQuickItemPrivate::get(item)->focus = false;
758         changed << item;
759     }
760
761     if (newActiveFocusItem) {
762         Q_ASSERT(newActiveFocusItem == scope);
763         activeFocusItem = scope;
764
765         updateInputMethodData();
766
767         QFocusEvent event(QEvent::FocusIn, Qt::OtherFocusReason);
768         q->sendEvent(newActiveFocusItem, &event);
769     } else {
770         updateInputMethodData();
771     }
772
773     if (!changed.isEmpty())
774         notifyFocusChangesRecur(changed.data(), changed.count() - 1);
775 }
776
777 void QQuickCanvasPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
778 {
779     QDeclarativeGuard<QQuickItem> item(*items);
780
781     if (remaining)
782         notifyFocusChangesRecur(items + 1, remaining - 1);
783
784     if (item) {
785         QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
786
787         if (itemPrivate->notifiedFocus != itemPrivate->focus) {
788             itemPrivate->notifiedFocus = itemPrivate->focus;
789             emit item->focusChanged(itemPrivate->focus);
790         }
791
792         if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
793             itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
794             itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
795             emit item->activeFocusChanged(itemPrivate->activeFocus);
796         }
797     }
798 }
799
800 void QQuickCanvasPrivate::updateInputMethodData()
801 {
802     QQuickItem *inputItem = 0;
803     if (activeFocusItem && activeFocusItem->flags() & QQuickItem::ItemAcceptsInputMethod)
804         inputItem = activeFocusItem;
805     qApp->inputPanel()->setInputItem(inputItem);
806 }
807
808 /*!
809   Queries the Input Method.
810 */
811 QVariant QQuickCanvas::inputMethodQuery(Qt::InputMethodQuery query) const
812 {
813     Q_D(const QQuickCanvas);
814     if (!d->activeFocusItem || !(QQuickItemPrivate::get(d->activeFocusItem)->flags & QQuickItem::ItemAcceptsInputMethod))
815         return QVariant();
816     QVariant value = d->activeFocusItem->inputMethodQuery(query);
817
818     //map geometry types
819     QVariant::Type type = value.type();
820     if (type == QVariant::RectF || type == QVariant::Rect) {
821         const QTransform transform = QQuickItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
822         value = transform.mapRect(value.toRectF());
823     } else if (type == QVariant::PointF || type == QVariant::Point) {
824         const QTransform transform = QQuickItemPrivate::get(d->activeFocusItem)->itemToCanvasTransform();
825         value = transform.map(value.toPointF());
826     }
827     return value;
828 }
829
830 void QQuickCanvasPrivate::dirtyItem(QQuickItem *)
831 {
832     Q_Q(QQuickCanvas);
833     q->maybeUpdate();
834 }
835
836 void QQuickCanvasPrivate::cleanup(QSGNode *n)
837 {
838     Q_Q(QQuickCanvas);
839
840     Q_ASSERT(!cleanupNodeList.contains(n));
841     cleanupNodeList.append(n);
842     q->maybeUpdate();
843 }
844
845
846 /*!
847     \class QQuickCanvas
848     \since QtQuick 2.0
849     \brief The QQuickCanvas class provides the canvas for displaying a graphical QML scene
850
851     QQuickCanvas provides the graphical scene management needed to interact with and display
852     a scene of QQuickItems.
853
854     A QQuickCanvas always has a single invisible root item. To add items to this canvas,
855     reparent the items to the root item or to an existing item in the scene.
856
857     For easily displaying a scene from a QML file, see \l{QQuickView}.
858 */
859 QQuickCanvas::QQuickCanvas(QWindow *parent)
860     : QWindow(*(new QQuickCanvasPrivate), parent)
861 {
862     Q_D(QQuickCanvas);
863     d->init(this);
864 }
865
866 QQuickCanvas::QQuickCanvas(QQuickCanvasPrivate &dd, QWindow *parent)
867     : QWindow(dd, parent)
868 {
869     Q_D(QQuickCanvas);
870     d->init(this);
871 }
872
873 QQuickCanvas::~QQuickCanvas()
874 {
875     Q_D(QQuickCanvas);
876
877     /* The threaded renderer will clean up the nodes which will fire
878        sceneGraphChanged events through back to the canvas. This signal
879        is connected to maybeUpdate which should only be called from GUI or during
880        updatePaintNode(), so disconnect them before starting the shutdown
881      */
882     disconnect(d->context->renderer(), SIGNAL(sceneGraphChanged()), this, SLOT(maybeUpdate()));
883     if (d->thread->isRunning())
884         d->thread->stopRendering();
885
886     // ### should we change ~QQuickItem to handle this better?
887     // manually cleanup for the root item (item destructor only handles these when an item is parented)
888     QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem);
889     rootItemPrivate->removeFromDirtyList();
890
891     delete d->incubationController; d->incubationController = 0;
892
893     delete d->rootItem; d->rootItem = 0;
894     d->cleanupNodes();
895
896     delete d->thread; d->thread = 0;
897 }
898
899 /*!
900   Returns the invisible root item of the scene.
901
902   A QQuickCanvas always has a single invisible root item. To add items to this canvas,
903   reparent the items to the root item or to an existing item in the scene.
904 */
905 QQuickItem *QQuickCanvas::rootItem() const
906 {
907     Q_D(const QQuickCanvas);
908
909     return d->rootItem;
910 }
911
912 /*!
913   Returns the item which currently has active focus.
914 */
915 QQuickItem *QQuickCanvas::activeFocusItem() const
916 {
917     Q_D(const QQuickCanvas);
918
919     return d->activeFocusItem;
920 }
921
922 /*!
923   Returns the item which currently has the mouse grab.
924 */
925 QQuickItem *QQuickCanvas::mouseGrabberItem() const
926 {
927     Q_D(const QQuickCanvas);
928
929     return d->mouseGrabberItem;
930 }
931
932
933 bool QQuickCanvasPrivate::clearHover()
934 {
935     if (hoverItems.isEmpty())
936         return false;
937
938     QPointF pos = QCursor::pos(); // ### refactor: q->mapFromGlobal(QCursor::pos());
939
940     bool accepted = false;
941     foreach (QQuickItem* item, hoverItems)
942         accepted = sendHoverEvent(QEvent::HoverLeave, item, pos, pos, QGuiApplication::keyboardModifiers(), true) || accepted;
943     hoverItems.clear();
944     return accepted;
945 }
946
947
948 bool QQuickCanvas::event(QEvent *e)
949 {
950     Q_D(QQuickCanvas);
951
952     switch (e->type()) {
953
954     case QEvent::TouchBegin:
955     case QEvent::TouchUpdate:
956     case QEvent::TouchEnd:
957     {
958         QTouchEvent *touch = static_cast<QTouchEvent *>(e);
959         d->translateTouchEvent(touch);
960         d->deliverTouchEvent(touch);
961         if (!touch->isAccepted())
962             return false;
963         break;
964     }
965     case QEvent::Leave:
966         d->clearHover();
967         d->lastMousePosition = QPoint();
968         break;
969     case QEvent::DragEnter:
970     case QEvent::DragLeave:
971     case QEvent::DragMove:
972     case QEvent::Drop:
973         d->deliverDragEvent(&d->dragGrabber, e);
974         break;
975     case QEvent::WindowDeactivate:
976         rootItem()->windowDeactivateEvent();
977         break;
978     default:
979         break;
980     }
981
982     return QWindow::event(e);
983 }
984
985 void QQuickCanvas::keyPressEvent(QKeyEvent *e)
986 {
987     Q_D(QQuickCanvas);
988
989     if (d->activeFocusItem)
990         sendEvent(d->activeFocusItem, e);
991 }
992
993 void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
994 {
995     Q_D(QQuickCanvas);
996
997     if (d->activeFocusItem)
998         sendEvent(d->activeFocusItem, e);
999 }
1000
1001 void QQuickCanvas::inputMethodEvent(QInputMethodEvent *e)
1002 {
1003     Q_D(QQuickCanvas);
1004
1005     if (d->activeFocusItem)
1006         sendEvent(d->activeFocusItem, e);
1007 }
1008
1009 bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
1010 {
1011     Q_Q(QQuickCanvas);
1012
1013     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1014     if (itemPrivate->opacity == 0.0)
1015         return false;
1016
1017     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1018         QPointF p = item->mapFromScene(event->windowPos());
1019         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1020             return false;
1021     }
1022
1023     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1024     for (int ii = children.count() - 1; ii >= 0; --ii) {
1025         QQuickItem *child = children.at(ii);
1026         if (!child->isVisible() || !child->isEnabled())
1027             continue;
1028         if (deliverInitialMousePressEvent(child, event))
1029             return true;
1030     }
1031
1032     if (itemPrivate->acceptedMouseButtons & event->button()) {
1033         QPointF p = item->mapFromScene(event->windowPos());
1034         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1035             QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
1036                            event->button(), event->buttons(), event->modifiers());
1037             me.accept();
1038             mouseGrabberItem = item;
1039             q->sendEvent(item, &me);
1040             event->setAccepted(me.isAccepted());
1041             if (me.isAccepted())
1042                 return true;
1043             mouseGrabberItem->ungrabMouse();
1044             mouseGrabberItem = 0;
1045         }
1046     }
1047
1048     return false;
1049 }
1050
1051 bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
1052 {
1053     Q_Q(QQuickCanvas);
1054
1055     lastMousePosition = event->windowPos();
1056
1057     if (!mouseGrabberItem &&
1058          event->type() == QEvent::MouseButtonPress &&
1059          (event->button() & event->buttons()) == event->buttons()) {
1060         return deliverInitialMousePressEvent(rootItem, event);
1061     }
1062
1063     if (mouseGrabberItem) {
1064         QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
1065         const QTransform &transform = mgPrivate->canvasToItemTransform();
1066         QMouseEvent me(event->type(), transform.map(event->windowPos()), event->windowPos(), event->screenPos(),
1067                        event->button(), event->buttons(), event->modifiers());
1068         me.accept();
1069         q->sendEvent(mouseGrabberItem, &me);
1070         event->setAccepted(me.isAccepted());
1071         if (me.isAccepted())
1072             return true;
1073     }
1074
1075     return false;
1076 }
1077
1078 void QQuickCanvas::mousePressEvent(QMouseEvent *event)
1079 {
1080     Q_D(QQuickCanvas);
1081
1082 #ifdef MOUSE_DEBUG
1083     qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
1084 #endif
1085
1086     d->deliverMouseEvent(event);
1087 }
1088
1089 void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
1090 {
1091     Q_D(QQuickCanvas);
1092
1093 #ifdef MOUSE_DEBUG
1094     qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
1095 #endif
1096
1097     if (!d->mouseGrabberItem) {
1098         QWindow::mouseReleaseEvent(event);
1099         return;
1100     }
1101
1102     d->deliverMouseEvent(event);
1103     d->mouseGrabberItem = 0;
1104 }
1105
1106 void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
1107 {
1108     Q_D(QQuickCanvas);
1109
1110 #ifdef MOUSE_DEBUG
1111     qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
1112 #endif
1113
1114     if (!d->mouseGrabberItem && (event->button() & event->buttons()) == event->buttons()) {
1115         if (d->deliverInitialMousePressEvent(d->rootItem, event))
1116             event->accept();
1117         else
1118             event->ignore();
1119         return;
1120     }
1121
1122     d->deliverMouseEvent(event);
1123 }
1124
1125 bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1126                                       const QPointF &scenePos, const QPointF &lastScenePos,
1127                                       Qt::KeyboardModifiers modifiers, bool accepted)
1128 {
1129     Q_Q(QQuickCanvas);
1130     const QTransform transform = QQuickItemPrivate::get(item)->canvasToItemTransform();
1131
1132     //create copy of event
1133     QHoverEvent hoverEvent(type, transform.map(scenePos), transform.map(lastScenePos), modifiers);
1134     hoverEvent.setAccepted(accepted);
1135
1136     q->sendEvent(item, &hoverEvent);
1137
1138     return hoverEvent.isAccepted();
1139 }
1140
1141 void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
1142 {
1143     Q_D(QQuickCanvas);
1144
1145 #ifdef MOUSE_DEBUG
1146     qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
1147 #endif
1148
1149     if (!d->mouseGrabberItem) {
1150         if (d->lastMousePosition.isNull())
1151             d->lastMousePosition = event->windowPos();
1152         QPointF last = d->lastMousePosition;
1153         d->lastMousePosition = event->windowPos();
1154
1155         bool accepted = event->isAccepted();
1156         bool delivered = d->deliverHoverEvent(d->rootItem, event->windowPos(), last, event->modifiers(), accepted);
1157         if (!delivered) {
1158             //take care of any exits
1159             accepted = d->clearHover();
1160         }
1161         event->setAccepted(accepted);
1162         return;
1163     }
1164
1165     d->deliverMouseEvent(event);
1166 }
1167
1168 bool QQuickCanvasPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
1169                                          Qt::KeyboardModifiers modifiers, bool &accepted)
1170 {
1171     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1172     if (itemPrivate->opacity == 0.0)
1173         return false;
1174
1175     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1176         QPointF p = item->mapFromScene(scenePos);
1177         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1178             return false;
1179     }
1180
1181     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1182     for (int ii = children.count() - 1; ii >= 0; --ii) {
1183         QQuickItem *child = children.at(ii);
1184         if (!child->isVisible() || !child->isEnabled())
1185             continue;
1186         if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
1187             return true;
1188     }
1189
1190     if (itemPrivate->hoverEnabled) {
1191         QPointF p = item->mapFromScene(scenePos);
1192         if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1193             if (!hoverItems.isEmpty() && hoverItems[0] == item) {
1194                 //move
1195                 accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1196             } else {
1197                 QList<QQuickItem *> itemsToHover;
1198                 QQuickItem* parent = item;
1199                 itemsToHover << item;
1200                 while ((parent = parent->parentItem()))
1201                     itemsToHover << parent;
1202
1203                 // Leaving from previous hovered items until we reach the item or one of its ancestors.
1204                 while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
1205                     sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
1206                     hoverItems.removeFirst();
1207                 }
1208
1209                 if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
1210                     // ### Shouldn't we send moves for the parent items as well?
1211                     accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, accepted);
1212                 } else {
1213                     // Enter items that are not entered yet.
1214                     int startIdx = -1;
1215                     if (!hoverItems.isEmpty())
1216                         startIdx = itemsToHover.indexOf(hoverItems[0]) - 1;
1217                     if (startIdx == -1)
1218                         startIdx = itemsToHover.count() - 1;
1219
1220                     for (int i = startIdx; i >= 0; i--) {
1221                         QQuickItem *itemToHover = itemsToHover[i];
1222                         if (QQuickItemPrivate::get(itemToHover)->hoverEnabled) {
1223                             hoverItems.prepend(itemToHover);
1224                             sendHoverEvent(QEvent::HoverEnter, itemToHover, scenePos, lastScenePos, modifiers, accepted);
1225                         }
1226                     }
1227                 }
1228             }
1229             return true;
1230         }
1231     }
1232
1233     return false;
1234 }
1235
1236 bool QQuickCanvasPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event)
1237 {
1238     Q_Q(QQuickCanvas);
1239     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1240     if (itemPrivate->opacity == 0.0)
1241         return false;
1242
1243     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1244         QPointF p = item->mapFromScene(event->posF());
1245         if (!QRectF(0, 0, item->width(), item->height()).contains(p))
1246             return false;
1247     }
1248
1249     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1250     for (int ii = children.count() - 1; ii >= 0; --ii) {
1251         QQuickItem *child = children.at(ii);
1252         if (!child->isVisible() || !child->isEnabled())
1253             continue;
1254         if (deliverWheelEvent(child, event))
1255             return true;
1256     }
1257
1258     QPointF p = item->mapFromScene(event->posF());
1259     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1260         QWheelEvent wheel(p, event->delta(), event->buttons(), event->modifiers(), event->orientation());
1261         wheel.accept();
1262         q->sendEvent(item, &wheel);
1263         if (wheel.isAccepted()) {
1264             event->accept();
1265             return true;
1266         }
1267     }
1268
1269     return false;
1270 }
1271
1272 #ifndef QT_NO_WHEELEVENT
1273 void QQuickCanvas::wheelEvent(QWheelEvent *event)
1274 {
1275     Q_D(QQuickCanvas);
1276 #ifdef MOUSE_DEBUG
1277     qWarning() << "QQuickCanvas::wheelEvent()" << event->pos() << event->delta() << event->orientation();
1278 #endif
1279     event->ignore();
1280     d->deliverWheelEvent(d->rootItem, event);
1281 }
1282 #endif // QT_NO_WHEELEVENT
1283
1284 bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
1285 {
1286 #ifdef TOUCH_DEBUG
1287     if (event->type() == QEvent::TouchBegin)
1288         qWarning("touchBeginEvent");
1289     else if (event->type() == QEvent::TouchUpdate)
1290         qWarning("touchUpdateEvent");
1291     else if (event->type() == QEvent::TouchEnd)
1292         qWarning("touchEndEvent");
1293 #endif
1294
1295     QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
1296
1297     if (event->type() == QTouchEvent::TouchBegin) {     // all points are new touch points
1298         QSet<int> acceptedNewPoints;
1299         deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
1300         if (acceptedNewPoints.count() > 0)
1301             event->accept();
1302         return event->isAccepted();
1303     }
1304
1305     const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1306     QList<QTouchEvent::TouchPoint> newPoints;
1307     QQuickItem *item = 0;
1308     for (int i=0; i<touchPoints.count(); i++) {
1309         const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
1310         switch (touchPoint.state()) {
1311             case Qt::TouchPointPressed:
1312                 newPoints << touchPoint;
1313                 break;
1314             case Qt::TouchPointMoved:
1315             case Qt::TouchPointStationary:
1316             case Qt::TouchPointReleased:
1317                 if (itemForTouchPointId.contains(touchPoint.id())) {
1318                     item = itemForTouchPointId[touchPoint.id()];
1319                     if (item)
1320                         updatedPoints[item].append(touchPoint);
1321                 }
1322                 break;
1323             default:
1324                 break;
1325         }
1326     }
1327
1328     if (newPoints.count() > 0 || updatedPoints.count() > 0) {
1329         QSet<int> acceptedNewPoints;
1330         int prevCount = updatedPoints.count();
1331         deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
1332         if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
1333             event->accept();
1334     }
1335
1336     if (event->touchPointStates() & Qt::TouchPointReleased) {
1337         for (int i=0; i<touchPoints.count(); i++) {
1338             if (touchPoints[i].state() == Qt::TouchPointReleased)
1339                 itemForTouchPointId.remove(touchPoints[i].id());
1340         }
1341     }
1342
1343     return event->isAccepted();
1344 }
1345
1346 bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
1347 {
1348     Q_Q(QQuickCanvas);
1349     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1350
1351     if (itemPrivate->opacity == 0.0)
1352         return false;
1353
1354     if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1355         QRectF bounds(0, 0, item->width(), item->height());
1356         for (int i=0; i<newPoints.count(); i++) {
1357             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1358             if (!bounds.contains(p))
1359                 return false;
1360         }
1361     }
1362
1363     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1364     for (int ii = children.count() - 1; ii >= 0; --ii) {
1365         QQuickItem *child = children.at(ii);
1366         if (!child->isEnabled())
1367             continue;
1368         if (deliverTouchPoints(child, event, newPoints, acceptedNewPoints, updatedPoints))
1369             return true;
1370     }
1371
1372     QList<QTouchEvent::TouchPoint> matchingPoints;
1373     if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
1374         QRectF bounds(0, 0, item->width(), item->height());
1375         for (int i=0; i<newPoints.count(); i++) {
1376             if (acceptedNewPoints->contains(newPoints[i].id()))
1377                 continue;
1378             QPointF p = item->mapFromScene(newPoints[i].scenePos());
1379             if (bounds.contains(p))
1380                 matchingPoints << newPoints[i];
1381         }
1382     }
1383
1384     if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
1385         QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
1386         eventPoints.append(matchingPoints);
1387         transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
1388
1389         Qt::TouchPointStates eventStates;
1390         for (int i=0; i<eventPoints.count(); i++)
1391             eventStates |= eventPoints[i].state();
1392         // if all points have the same state, set the event type accordingly
1393         QEvent::Type eventType;
1394         switch (eventStates) {
1395             case Qt::TouchPointPressed:
1396                 eventType = QEvent::TouchBegin;
1397                 break;
1398             case Qt::TouchPointReleased:
1399                 eventType = QEvent::TouchEnd;
1400                 break;
1401             default:
1402                 eventType = QEvent::TouchUpdate;
1403                 break;
1404         }
1405
1406         if (eventStates != Qt::TouchPointStationary) {
1407             QTouchEvent touchEvent(eventType);
1408             // touchEvent.setWidget(q); // ### refactor: what is the consequence of not setting the widget?
1409             touchEvent.setDeviceType(event->deviceType());
1410             touchEvent.setModifiers(event->modifiers());
1411             touchEvent.setTouchPointStates(eventStates);
1412             touchEvent.setTouchPoints(eventPoints);
1413             touchEvent.setTimestamp(event->timestamp());
1414
1415             touchEvent.accept();
1416             q->sendEvent(item, &touchEvent);
1417
1418             if (touchEvent.isAccepted()) {
1419                 for (int i=0; i<matchingPoints.count(); i++) {
1420                     itemForTouchPointId[matchingPoints[i].id()] = item;
1421                     acceptedNewPoints->insert(matchingPoints[i].id());
1422                 }
1423             }
1424         }
1425     }
1426
1427     updatedPoints->remove(item);
1428     if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
1429         return true;
1430
1431     return false;
1432 }
1433
1434 void QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
1435 {
1436     Q_Q(QQuickCanvas);
1437     grabber->resetTarget();
1438     QQuickDragGrabber::iterator grabItem = grabber->begin();
1439     if (grabItem != grabber->end()) {
1440         Q_ASSERT(event->type() != QEvent::DragEnter);
1441         if (event->type() == QEvent::Drop) {
1442             QDropEvent *e = static_cast<QDropEvent *>(event);
1443             for (e->setAccepted(false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1444                 QPointF p = (**grabItem)->mapFromScene(e->pos());
1445                 QDropEvent translatedEvent(
1446                         p.toPoint(),
1447                         e->possibleActions(),
1448                         e->mimeData(),
1449                         e->mouseButtons(),
1450                         e->keyboardModifiers());
1451                 QQuickDropEventEx::copyActions(&translatedEvent, *e);
1452                 q->sendEvent(**grabItem, &translatedEvent);
1453                 e->setAccepted(translatedEvent.isAccepted());
1454                 e->setDropAction(translatedEvent.dropAction());
1455                 grabber->setTarget(**grabItem);
1456             }
1457         }
1458         if (event->type() != QEvent::DragMove) {    // Either an accepted drop or a leave.
1459             QDragLeaveEvent leaveEvent;
1460             for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
1461                 q->sendEvent(**grabItem, &leaveEvent);
1462             return;
1463         } else for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
1464             QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
1465             if (deliverDragEvent(grabber, **grabItem, moveEvent)) {
1466                 moveEvent->setAccepted(true);
1467                 for (++grabItem; grabItem != grabber->end();) {
1468                     QPointF p = (**grabItem)->mapFromScene(moveEvent->pos());
1469                     if (QRectF(0, 0, (**grabItem)->width(), (**grabItem)->height()).contains(p)) {
1470                         QDragMoveEvent translatedEvent(
1471                                 p.toPoint(),
1472                                 moveEvent->possibleActions(),
1473                                 moveEvent->mimeData(),
1474                                 moveEvent->mouseButtons(),
1475                                 moveEvent->keyboardModifiers());
1476                         QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
1477                         q->sendEvent(**grabItem, &translatedEvent);
1478                         ++grabItem;
1479                     } else {
1480                         QDragLeaveEvent leaveEvent;
1481                         q->sendEvent(**grabItem, &leaveEvent);
1482                         grabItem = grabber->release(grabItem);
1483                     }
1484                 }
1485                 return;
1486             } else {
1487                 QDragLeaveEvent leaveEvent;
1488                 q->sendEvent(**grabItem, &leaveEvent);
1489             }
1490         }
1491     }
1492     if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
1493         QDragMoveEvent *e = static_cast<QDragMoveEvent *>(event);
1494         QDragEnterEvent enterEvent(
1495                 e->pos(),
1496                 e->possibleActions(),
1497                 e->mimeData(),
1498                 e->mouseButtons(),
1499                 e->keyboardModifiers());
1500         QQuickDropEventEx::copyActions(&enterEvent, *e);
1501         event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
1502     }
1503 }
1504
1505 bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event)
1506 {
1507     Q_Q(QQuickCanvas);
1508     bool accepted = false;
1509     QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1510     if (itemPrivate->opacity == 0.0 || !item->isVisible() || !item->isEnabled())
1511         return false;
1512
1513     QPointF p = item->mapFromScene(event->pos());
1514     if (QRectF(0, 0, item->width(), item->height()).contains(p)) {
1515         if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
1516             QDragMoveEvent translatedEvent(
1517                     p.toPoint(),
1518                     event->possibleActions(),
1519                     event->mimeData(),
1520                     event->mouseButtons(),
1521                     event->keyboardModifiers(),
1522                     event->type());
1523             QQuickDropEventEx::copyActions(&translatedEvent, *event);
1524             q->sendEvent(item, &translatedEvent);
1525             if (event->type() == QEvent::DragEnter) {
1526                 if (translatedEvent.isAccepted()) {
1527                     grabber->grab(item);
1528                     accepted = true;
1529                 }
1530             } else {
1531                 accepted = true;
1532             }
1533         }
1534     } else if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
1535         return false;
1536     }
1537
1538     QDragEnterEvent enterEvent(
1539             event->pos(),
1540             event->possibleActions(),
1541             event->mimeData(),
1542             event->mouseButtons(),
1543             event->keyboardModifiers());
1544     QQuickDropEventEx::copyActions(&enterEvent, *event);
1545     QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1546     for (int ii = children.count() - 1; ii >= 0; --ii) {
1547         if (deliverDragEvent(grabber, children.at(ii), &enterEvent))
1548             return true;
1549     }
1550
1551     return accepted;
1552 }
1553
1554 bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
1555 {
1556     if (!target)
1557         return false;
1558
1559     QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
1560     if (targetPrivate->filtersChildMouseEvents)
1561         if (target->childMouseEventFilter(item, event))
1562             return true;
1563
1564     if (sendFilteredMouseEvent(target->parentItem(), item, event))
1565         return true;
1566
1567     return false;
1568 }
1569
1570 /*!
1571     Propagates an event to a QQuickItem on the canvas
1572 */
1573 bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
1574 {
1575     Q_D(QQuickCanvas);
1576
1577     if (!item) {
1578         qWarning("QQuickCanvas::sendEvent: Cannot send event to a null item");
1579         return false;
1580     }
1581
1582     Q_ASSERT(e);
1583
1584     switch (e->type()) {
1585     case QEvent::KeyPress:
1586     case QEvent::KeyRelease:
1587         e->accept();
1588         QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1589         while (!e->isAccepted() && (item = item->parentItem())) {
1590             e->accept();
1591             QQuickItemPrivate::get(item)->deliverKeyEvent(static_cast<QKeyEvent *>(e));
1592         }
1593         break;
1594     case QEvent::InputMethod:
1595         e->accept();
1596         QQuickItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1597         while (!e->isAccepted() && (item = item->parentItem())) {
1598             e->accept();
1599             QQuickItemPrivate::get(item)->deliverInputMethodEvent(static_cast<QInputMethodEvent *>(e));
1600         }
1601         break;
1602     case QEvent::FocusIn:
1603     case QEvent::FocusOut:
1604         QQuickItemPrivate::get(item)->deliverFocusEvent(static_cast<QFocusEvent *>(e));
1605         break;
1606     case QEvent::MouseButtonPress:
1607     case QEvent::MouseButtonRelease:
1608     case QEvent::MouseButtonDblClick:
1609     case QEvent::MouseMove:
1610         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1611         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1612             e->accept();
1613             QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
1614         }
1615         break;
1616     case QEvent::Wheel:
1617         QQuickItemPrivate::get(item)->deliverWheelEvent(static_cast<QWheelEvent *>(e));
1618         break;
1619     case QEvent::HoverEnter:
1620     case QEvent::HoverLeave:
1621     case QEvent::HoverMove:
1622         QQuickItemPrivate::get(item)->deliverHoverEvent(static_cast<QHoverEvent *>(e));
1623         break;
1624     case QEvent::TouchBegin:
1625     case QEvent::TouchUpdate:
1626     case QEvent::TouchEnd:
1627         // XXX todo - should sendEvent be doing this?  how does it relate to forwarded events?
1628         if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
1629             e->accept();
1630             QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
1631         }
1632         break;
1633     case QEvent::DragEnter:
1634     case QEvent::DragMove:
1635     case QEvent::DragLeave:
1636     case QEvent::Drop:
1637         QQuickItemPrivate::get(item)->deliverDragEvent(e);
1638         break;
1639     default:
1640         break;
1641     }
1642
1643     return false;
1644 }
1645
1646 void QQuickCanvasPrivate::cleanupNodes()
1647 {
1648     for (int ii = 0; ii < cleanupNodeList.count(); ++ii)
1649         delete cleanupNodeList.at(ii);
1650     cleanupNodeList.clear();
1651 }
1652
1653 void QQuickCanvasPrivate::cleanupNodesOnShutdown(QQuickItem *item)
1654 {
1655     QQuickItemPrivate *p = QQuickItemPrivate::get(item);
1656     if (p->itemNodeInstance) {
1657         delete p->itemNodeInstance;
1658         p->itemNodeInstance = 0;
1659         p->opacityNode = 0;
1660         p->clipNode = 0;
1661         p->groupNode = 0;
1662         p->paintNode = 0;
1663     }
1664
1665     for (int ii = 0; ii < p->childItems.count(); ++ii)
1666         cleanupNodesOnShutdown(p->childItems.at(ii));
1667 }
1668
1669 // This must be called from the render thread, with the main thread frozen
1670 void QQuickCanvasPrivate::cleanupNodesOnShutdown()
1671 {
1672     cleanupNodes();
1673
1674     cleanupNodesOnShutdown(rootItem);
1675 }
1676
1677 void QQuickCanvasPrivate::updateDirtyNodes()
1678 {
1679 #ifdef DIRTY_DEBUG
1680     qWarning() << "QQuickCanvasPrivate::updateDirtyNodes():";
1681 #endif
1682
1683     cleanupNodes();
1684
1685     QQuickItem *updateList = dirtyItemList;
1686     dirtyItemList = 0;
1687     if (updateList) QQuickItemPrivate::get(updateList)->prevDirtyItem = &updateList;
1688
1689     while (updateList) {
1690         QQuickItem *item = updateList;
1691         QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1692         itemPriv->removeFromDirtyList();
1693
1694 #ifdef DIRTY_DEBUG
1695         qWarning() << "   QSGNode:" << item << qPrintable(itemPriv->dirtyToString());
1696 #endif
1697         updateDirtyNode(item);
1698     }
1699 }
1700
1701 void QQuickCanvasPrivate::updateDirtyNode(QQuickItem *item)
1702 {
1703 #ifdef QML_RUNTIME_TESTING
1704     bool didFlash = false;
1705 #endif
1706
1707     QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item);
1708     quint32 dirty = itemPriv->dirtyAttributes;
1709     itemPriv->dirtyAttributes = 0;
1710
1711     if ((dirty & QQuickItemPrivate::TransformUpdateMask) ||
1712         (dirty & QQuickItemPrivate::Size && itemPriv->origin != QQuickItem::TopLeft &&
1713          (itemPriv->scale != 1. || itemPriv->rotation != 0.))) {
1714
1715         QMatrix4x4 matrix;
1716
1717         if (itemPriv->x != 0. || itemPriv->y != 0.)
1718             matrix.translate(itemPriv->x, itemPriv->y);
1719
1720         for (int ii = itemPriv->transforms.count() - 1; ii >= 0; --ii)
1721             itemPriv->transforms.at(ii)->applyTo(&matrix);
1722
1723         if (itemPriv->scale != 1. || itemPriv->rotation != 0.) {
1724             QPointF origin = item->transformOriginPoint();
1725             matrix.translate(origin.x(), origin.y());
1726             if (itemPriv->scale != 1.)
1727                 matrix.scale(itemPriv->scale, itemPriv->scale);
1728             if (itemPriv->rotation != 0.)
1729                 matrix.rotate(itemPriv->rotation, 0, 0, 1);
1730             matrix.translate(-origin.x(), -origin.y());
1731         }
1732
1733         itemPriv->itemNode()->setMatrix(matrix);
1734     }
1735
1736     bool clipEffectivelyChanged = dirty & QQuickItemPrivate::Clip &&
1737                                   ((item->clip() == false) != (itemPriv->clipNode == 0));
1738     bool effectRefEffectivelyChanged = dirty & QQuickItemPrivate::EffectReference &&
1739                                   ((itemPriv->effectRefCount == 0) != (itemPriv->rootNode == 0));
1740
1741     if (clipEffectivelyChanged) {
1742         QSGNode *parent = itemPriv->opacityNode ? (QSGNode *) itemPriv->opacityNode : (QSGNode *)itemPriv->itemNode();
1743         QSGNode *child = itemPriv->rootNode ? (QSGNode *)itemPriv->rootNode : (QSGNode *)itemPriv->groupNode;
1744
1745         if (item->clip()) {
1746             Q_ASSERT(itemPriv->clipNode == 0);
1747             itemPriv->clipNode = new QQuickDefaultClipNode(item->boundingRect());
1748             itemPriv->clipNode->update();
1749
1750             if (child)
1751                 parent->removeChildNode(child);
1752             parent->appendChildNode(itemPriv->clipNode);
1753             if (child)
1754                 itemPriv->clipNode->appendChildNode(child);
1755
1756         } else {
1757             Q_ASSERT(itemPriv->clipNode != 0);
1758             parent->removeChildNode(itemPriv->clipNode);
1759             if (child)
1760                 itemPriv->clipNode->removeChildNode(child);
1761             delete itemPriv->clipNode;
1762             itemPriv->clipNode = 0;
1763             if (child)
1764                 parent->appendChildNode(child);
1765         }
1766     }
1767
1768     if (dirty & QQuickItemPrivate::ChildrenUpdateMask)
1769         itemPriv->childContainerNode()->removeAllChildNodes();
1770
1771     if (effectRefEffectivelyChanged) {
1772         QSGNode *parent = itemPriv->clipNode;
1773         if (!parent)
1774             parent = itemPriv->opacityNode;
1775         if (!parent)
1776             parent = itemPriv->itemNode();
1777         QSGNode *child = itemPriv->groupNode;
1778
1779         if (itemPriv->effectRefCount) {
1780             Q_ASSERT(itemPriv->rootNode == 0);
1781             itemPriv->rootNode = new QSGRootNode;
1782
1783             if (child)
1784                 parent->removeChildNode(child);
1785             parent->appendChildNode(itemPriv->rootNode);
1786             if (child)
1787                 itemPriv->rootNode->appendChildNode(child);
1788         } else {
1789             Q_ASSERT(itemPriv->rootNode != 0);
1790             parent->removeChildNode(itemPriv->rootNode);
1791             if (child)
1792                 itemPriv->rootNode->removeChildNode(child);
1793             delete itemPriv->rootNode;
1794             itemPriv->rootNode = 0;
1795             if (child)
1796                 parent->appendChildNode(child);
1797         }
1798     }
1799
1800     if (dirty & QQuickItemPrivate::ChildrenUpdateMask) {
1801         QSGNode *groupNode = itemPriv->groupNode;
1802         if (groupNode)
1803             groupNode->removeAllChildNodes();
1804
1805         QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems();
1806         int ii = 0;
1807
1808         for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) {
1809             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1810             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1811                 continue;
1812             if (childPrivate->itemNode()->parent())
1813                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1814
1815             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1816         }
1817         itemPriv->beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0;
1818
1819         if (itemPriv->paintNode)
1820             itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode);
1821
1822         for (; ii < orderedChildren.count(); ++ii) {
1823             QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii));
1824             if (!childPrivate->explicitVisible && !childPrivate->effectRefCount)
1825                 continue;
1826             if (childPrivate->itemNode()->parent())
1827                 childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode());
1828
1829             itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode());
1830         }
1831     }
1832
1833     if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode) {
1834         itemPriv->clipNode->setRect(item->boundingRect());
1835         itemPriv->clipNode->update();
1836     }
1837
1838     if (dirty & (QQuickItemPrivate::OpacityValue | QQuickItemPrivate::Visible | QQuickItemPrivate::HideReference)) {
1839         qreal opacity = itemPriv->explicitVisible && itemPriv->hideRefCount == 0
1840                       ? itemPriv->opacity : qreal(0);
1841
1842         if (opacity != 1 && !itemPriv->opacityNode) {
1843             itemPriv->opacityNode = new QSGOpacityNode;
1844
1845             QSGNode *parent = itemPriv->itemNode();
1846             QSGNode *child = itemPriv->clipNode;
1847             if (!child)
1848                 child = itemPriv->rootNode;
1849             if (!child)
1850                 child = itemPriv->groupNode;
1851
1852             if (child)
1853                 parent->removeChildNode(child);
1854             parent->appendChildNode(itemPriv->opacityNode);
1855             if (child)
1856                 itemPriv->opacityNode->appendChildNode(child);
1857         }
1858         if (itemPriv->opacityNode)
1859             itemPriv->opacityNode->setOpacity(opacity);
1860     }
1861
1862     if (dirty & QQuickItemPrivate::ContentUpdateMask) {
1863
1864         if (itemPriv->flags & QQuickItem::ItemHasContents) {
1865             updatePaintNodeData.transformNode = itemPriv->itemNode();
1866             itemPriv->paintNode = item->updatePaintNode(itemPriv->paintNode, &updatePaintNodeData);
1867
1868             Q_ASSERT(itemPriv->paintNode == 0 ||
1869                      itemPriv->paintNode->parent() == 0 ||
1870                      itemPriv->paintNode->parent() == itemPriv->childContainerNode());
1871
1872             if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) {
1873                 if (itemPriv->beforePaintNode)
1874                     itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->beforePaintNode);
1875                 else
1876                     itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode);
1877             }
1878         } else if (itemPriv->paintNode) {
1879             delete itemPriv->paintNode;
1880             itemPriv->paintNode = 0;
1881         }
1882     }
1883
1884 #ifndef QT_NO_DEBUG
1885     // Check consistency.
1886     const QSGNode *nodeChain[] = {
1887         itemPriv->itemNodeInstance,
1888         itemPriv->opacityNode,
1889         itemPriv->clipNode,
1890         itemPriv->rootNode,
1891         itemPriv->groupNode,
1892         itemPriv->paintNode,
1893     };
1894
1895     int ip = 0;
1896     for (;;) {
1897         while (ip < 5 && nodeChain[ip] == 0)
1898             ++ip;
1899         if (ip == 5)
1900             break;
1901         int ic = ip + 1;
1902         while (ic < 5 && nodeChain[ic] == 0)
1903             ++ic;
1904         const QSGNode *parent = nodeChain[ip];
1905         const QSGNode *child = nodeChain[ic];
1906         if (child == 0) {
1907             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0);
1908         } else {
1909             Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1);
1910             Q_ASSERT(child->parent() == parent);
1911             bool containsChild = false;
1912             for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling())
1913                 containsChild |= (n == child);
1914             Q_ASSERT(containsChild);
1915         }
1916         ip = ic;
1917     }
1918 #endif
1919
1920 #ifdef QML_RUNTIME_TESTING
1921     if (itemPriv->sceneGraphContext()->isFlashModeEnabled()) {
1922         QSGFlashNode *flash = new QSGFlashNode();
1923         flash->setRect(item->boundingRect());
1924         itemPriv->childContainerNode()->appendChildNode(flash);
1925         didFlash = true;
1926     }
1927     Q_Q(QQuickCanvas);
1928     if (didFlash) {
1929         q->maybeUpdate();
1930     }
1931 #endif
1932
1933 }
1934
1935 void QQuickCanvas::maybeUpdate()
1936 {
1937     Q_D(QQuickCanvas);
1938
1939     if (d->thread && d->thread->isRunning())
1940         d->thread->maybeUpdate();
1941 }
1942
1943 /*!
1944     \fn void QSGEngine::sceneGraphInitialized();
1945
1946     This signal is emitted when the scene graph has been initialized.
1947
1948     This signal will be emitted from the scene graph rendering thread.
1949  */
1950
1951 /*!
1952     Returns the QSGEngine used for this scene.
1953
1954     The engine will only be available once the scene graph has been
1955     initialized. Register for the sceneGraphEngine() signal to get
1956     notification about this.
1957
1958     \deprecated
1959  */
1960
1961 QSGEngine *QQuickCanvas::sceneGraphEngine() const
1962 {
1963     Q_D(const QQuickCanvas);
1964     qWarning("QQuickCanvas::sceneGraphEngine() is deprecated, use members of QQuickCanvas instead");
1965     if (d->context && d->context->isReady())
1966         return d->engine;
1967     return 0;
1968 }
1969
1970
1971
1972 /*!
1973     Sets the render target for this canvas to be \a fbo.
1974
1975     The specified fbo must be created in the context of the canvas
1976     or one that shares with it.
1977
1978     \warning
1979     This function can only be called from the thread doing
1980     the rendering.
1981  */
1982
1983 void QQuickCanvas::setRenderTarget(QOpenGLFramebufferObject *fbo)
1984 {
1985     Q_D(QQuickCanvas);
1986     if (d->context && d->context && QThread::currentThread() != d->context->thread()) {
1987         qWarning("QQuickCanvas::setRenderThread: Cannot set render target from outside the rendering thread");
1988         return;
1989     }
1990
1991     d->renderTarget = fbo;
1992 }
1993
1994
1995
1996 /*!
1997     Returns the render target for this canvas.
1998
1999     The default is to render to the surface of the canvas, in which
2000     case the render target is 0.
2001  */
2002 QOpenGLFramebufferObject *QQuickCanvas::renderTarget() const
2003 {
2004     Q_D(const QQuickCanvas);
2005     return d->renderTarget;
2006 }
2007
2008
2009 /*!
2010     Grabs the contents of the framebuffer and returns it as an image.
2011
2012     This function might not work if the view is not visible.
2013
2014     \warning Calling this function will cause performance problems.
2015
2016     \warning This function can only be called from the GUI thread.
2017  */
2018 QImage QQuickCanvas::grabFrameBuffer()
2019 {
2020     Q_D(QQuickCanvas);
2021     return d->thread ? d->thread->grab() : QImage();
2022 }
2023
2024 /*!
2025     Returns an incubation controller that splices incubation between frames
2026     for this canvas. QQuickView automatically installs this controller for you,
2027     otherwise you will need to install it yourself using \l{QDeclarativeEngine::setIncubationController}
2028
2029     The controller is owned by the canvas and will be destroyed when the canvas
2030     is deleted.
2031 */
2032 QDeclarativeIncubationController *QQuickCanvas::incubationController() const
2033 {
2034     Q_D(const QQuickCanvas);
2035
2036     if (!d->incubationController)
2037         d->incubationController = new QQuickCanvasIncubationController(const_cast<QQuickCanvasPrivate *>(d));
2038     return d->incubationController;
2039 }
2040
2041
2042
2043 /*!
2044     \enum QQuickCanvas::CreateTextureOption
2045
2046     The CreateTextureOption enums are used to customize a texture is wrapped.
2047
2048     \value TextureHasAlphaChannel The texture has an alpha channel and should
2049     be drawn using blending.
2050
2051     \value TextureHasMipmaps The texture has mipmaps and can be drawn with
2052     mipmapping enabled.
2053
2054     \value TextureOwnsGLTexture The texture object owns the texture id and
2055     will delete the GL texture when the texture object is deleted.
2056  */
2057
2058 /*!
2059     \fn void QQuickCanvas::beforeRendering()
2060
2061     This signal is emitted before the scene starts rendering.
2062
2063     Combined with the modes for clearing the background, this option
2064     can be used to paint using raw GL under QML content.
2065
2066     The GL context used for rendering the scene graph will be bound
2067     at this point.
2068
2069     Since this signal is emitted from the scene graph rendering thread, the receiver should
2070     be on the scene graph thread or the connection should be Qt::DirectConnection.
2071
2072 */
2073
2074 /*!
2075     \fn void QQuickCanvas::afterRendering()
2076
2077     This signal is emitted after the scene has completed rendering, before swapbuffers is called.
2078
2079     This signal can be used to paint using raw GL on top of QML content,
2080     or to do screen scraping of the current frame buffer.
2081
2082     The GL context used for rendering the scene graph will be bound at this point.
2083
2084     Since this signal is emitted from the scene graph rendering thread, the receiver should
2085     be on the scene graph thread or the connection should be Qt::DirectConnection.
2086  */
2087
2088
2089
2090 /*!
2091     Sets weither the scene graph rendering of QML should clear the color buffer
2092     before it starts rendering to \a enbled.
2093
2094     By disabling clearing of the color buffer, it is possible to do GL painting
2095     under the scene graph.
2096
2097     The color buffer is cleared by default.
2098
2099     \sa beforeRendering()
2100  */
2101
2102 void QQuickCanvas::setClearBeforeRendering(bool enabled)
2103 {
2104     Q_D(QQuickCanvas);
2105     d->clearBeforeRendering = enabled;
2106 }
2107
2108
2109
2110 /*!
2111     Returns weither clearing of the color buffer is done before rendering or not.
2112  */
2113
2114 bool QQuickCanvas::clearBeforeRendering() const
2115 {
2116     Q_D(const QQuickCanvas);
2117     return d->clearBeforeRendering;
2118 }
2119
2120
2121
2122 /*!
2123     Creates a new QSGTexture from the supplied \a image. If the image has an
2124     alpha channel, the corresponding texture will have an alpha channel.
2125
2126     The caller of the function is responsible for deleting the returned texture.
2127     The actual GL texture will be deleted when the texture object is deleted.
2128
2129     \warning This function will return 0 if the scene graph has not yet been
2130     initialized.
2131
2132     This function can be called both from the GUI thread and the rendering thread.
2133
2134     \sa sceneGraphInitialized()
2135  */
2136
2137 QSGTexture *QQuickCanvas::createTextureFromImage(const QImage &image) const
2138 {
2139     Q_D(const QQuickCanvas);
2140     if (d->context)
2141         return d->context->createTexture(image);
2142     else
2143         return 0;
2144 }
2145
2146
2147
2148 /*!
2149     Creates a new QSGTexture object from an existing GL texture \a id.
2150
2151     The caller of the function is responsible for deleting the returned texture.
2152
2153     Use \a options to customize the texture attributes.
2154
2155     \warning This function will return 0 if the scenegraph has not yet been
2156     initialized.
2157
2158     \sa sceneGraphInitialized()
2159  */
2160 QSGTexture *QQuickCanvas::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
2161 {
2162     Q_D(const QQuickCanvas);
2163     if (d->context) {
2164         QSGPlainTexture *texture = new QSGPlainTexture();
2165         texture->setTextureId(id);
2166         texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
2167         texture->setHasMipmaps(options & TextureHasMipmaps);
2168         texture->setOwnsTexture(options & TextureOwnsGLTexture);
2169         texture->setTextureSize(size);
2170         return texture;
2171     }
2172     return 0;
2173 }
2174
2175
2176 /*!
2177     Sets the color used to clear the opengl context to \a color.
2178
2179     Setting the clear color has no effect when clearing is disabled.
2180
2181     \sa setClearBeforeRendering()
2182  */
2183
2184 void QQuickCanvas::setClearColor(const QColor &color)
2185 {
2186     d_func()->clearColor = color;
2187 }
2188
2189
2190
2191 /*!
2192     Returns the color used to clear the opengl context.
2193  */
2194
2195 QColor QQuickCanvas::clearColor() const
2196 {
2197     return d_func()->clearColor;
2198 }
2199
2200
2201
2202 void QQuickCanvasRenderLoop::createGLContext()
2203 {
2204     gl = new QOpenGLContext();
2205     gl->setFormat(renderer->requestedFormat());
2206     gl->create();
2207 }
2208
2209 void QQuickCanvasRenderThread::run()
2210 {
2211 #ifdef THREAD_DEBUG
2212     qDebug("QML Rendering Thread Started");
2213 #endif
2214
2215     if (!glContext()) {
2216         createGLContext();
2217         makeCurrent();
2218         initializeSceneGraph();
2219     } else {
2220         makeCurrent();
2221     }
2222
2223     while (!shouldExit) {
2224         lock();
2225
2226         bool sizeChanged = false;
2227         isExternalUpdatePending = false;
2228
2229         if (renderedSize != windowSize) {
2230 #ifdef THREAD_DEBUG
2231             printf("                RenderThread: window has changed size...\n");
2232 #endif
2233             glViewport(0, 0, windowSize.width(), windowSize.height());
2234             sizeChanged = true;
2235         }
2236
2237 #ifdef THREAD_DEBUG
2238         printf("                RenderThread: preparing to sync...\n");
2239 #endif
2240
2241         if (!isGuiBlocked) {
2242             isGuiBlockPending = true;
2243
2244 #ifdef THREAD_DEBUG
2245             printf("                RenderThread: aquired sync lock...\n");
2246 #endif
2247             allowMainThreadProcessingFlag = false;
2248             QCoreApplication::postEvent(this, new QEvent(QEvent::User));
2249 #ifdef THREAD_DEBUG
2250             printf("                RenderThread: going to sleep...\n");
2251 #endif
2252             wait();
2253
2254             isGuiBlockPending = false;
2255         }
2256
2257 #ifdef THREAD_DEBUG
2258         printf("                RenderThread: Doing locked sync\n");
2259 #endif
2260 #ifdef QQUICK_CANVAS_TIMING
2261         if (qquick_canvas_timing)
2262             threadTimer.start();
2263 #endif
2264         inSync = true;
2265         syncSceneGraph();
2266         inSync = false;
2267
2268         // Wake GUI after sync to let it continue animating and event processing.
2269         allowMainThreadProcessingFlag = true;
2270         wake();
2271         unlock();
2272 #ifdef THREAD_DEBUG
2273         printf("                RenderThread: sync done\n");
2274 #endif
2275 #ifdef QQUICK_CANVAS_TIMING
2276         if (qquick_canvas_timing)
2277             syncTime = threadTimer.elapsed();
2278 #endif
2279
2280 #ifdef THREAD_DEBUG
2281         printf("                RenderThread: rendering... %d x %d\n", windowSize.width(), windowSize.height());
2282 #endif
2283
2284         renderSceneGraph(windowSize);
2285 #ifdef QQUICK_CANVAS_TIMING
2286         if (qquick_canvas_timing)
2287             renderTime = threadTimer.elapsed() - syncTime;
2288 #endif
2289
2290         // The content of the target buffer is undefined after swap() so grab needs
2291         // to happen before swap();
2292         if (doGrab) {
2293 #ifdef THREAD_DEBUG
2294             printf("                RenderThread: doing a grab...\n");
2295 #endif
2296             grabContent = qt_gl_read_framebuffer(windowSize, false, false);
2297             doGrab = false;
2298         }
2299
2300 #ifdef THREAD_DEBUG
2301         printf("                RenderThread: wait for swap...\n");
2302 #endif
2303
2304         swapBuffers();
2305 #ifdef THREAD_DEBUG
2306         printf("                RenderThread: swap complete...\n");
2307 #endif
2308 #ifdef QQUICK_CANVAS_TIMING
2309         if (qquick_canvas_timing) {
2310             swapTime = threadTimer.elapsed() - renderTime;
2311             qDebug() << "- Breakdown of frame time: sync:" << syncTime
2312                      << "ms render:" << renderTime << "ms swap:" << swapTime
2313                      << "ms total:" << swapTime + renderTime << "ms";
2314         }
2315 #endif
2316
2317         lock();
2318         isPaintCompleted = true;
2319         if (sizeChanged)
2320             renderedSize = windowSize;
2321
2322         // Wake the GUI thread now that rendering is complete, to signal that painting
2323         // is done, resizing is done or grabbing is completed. For grabbing, we're
2324         // signalling this much later than needed (we could have done it before swap)
2325         // but we don't want to lock an extra time.
2326         wake();
2327
2328         if (!animationRunning && !isExternalUpdatePending && !shouldExit && !doGrab) {
2329 #ifdef THREAD_DEBUG
2330             printf("                RenderThread: nothing to do, going to sleep...\n");
2331 #endif
2332             isRenderBlocked = true;
2333             wait();
2334             isRenderBlocked = false;
2335         }
2336
2337         unlock();
2338
2339         QCoreApplication::processEvents();
2340
2341         // Process any "deleteLater" objects...
2342         QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
2343     }
2344
2345 #ifdef THREAD_DEBUG
2346     printf("                RenderThread: deleting all outstanding nodes\n");
2347 #endif
2348     cleanupNodesOnShutdown();
2349
2350 #ifdef THREAD_DEBUG
2351     printf("                RenderThread: render loop exited... Good Night!\n");
2352 #endif
2353
2354     doneCurrent();
2355
2356     lock();
2357     hasExited = true;
2358 #ifdef THREAD_DEBUG
2359     printf("                RenderThread: waking GUI for final sleep..\n");
2360 #endif
2361     wake();
2362     unlock();
2363
2364 #ifdef THREAD_DEBUG
2365     printf("                RenderThread: All done...\n");
2366 #endif
2367 }
2368
2369
2370
2371 bool QQuickCanvasRenderThread::event(QEvent *e)
2372 {
2373     Q_ASSERT(QThread::currentThread() == qApp->thread());
2374
2375     if (e->type() == QEvent::User) {
2376         if (!syncAlreadyHappened)
2377             sync(false);
2378
2379         syncAlreadyHappened = false;
2380
2381         if (animationRunning && animationDriver()) {
2382 #ifdef THREAD_DEBUG
2383             qDebug("GUI: Advancing animations...\n");
2384 #endif
2385
2386             animationDriver()->advance();
2387
2388 #ifdef THREAD_DEBUG
2389             qDebug("GUI: Animations advanced...\n");
2390 #endif
2391         }
2392
2393         return true;
2394     }
2395
2396     return QThread::event(e);
2397 }
2398
2399
2400
2401 void QQuickCanvasRenderThread::exhaustSyncEvent()
2402 {
2403     if (isGuiBlockPending) {
2404         sync(true);
2405         syncAlreadyHappened = true;
2406     }
2407 }
2408
2409
2410
2411 void QQuickCanvasRenderThread::sync(bool guiAlreadyLocked)
2412 {
2413 #ifdef THREAD_DEBUG
2414     printf("GUI: sync - %s\n", guiAlreadyLocked ? "outside event" : "inside event");
2415 #endif
2416     if (!guiAlreadyLocked)
2417         lockInGui();
2418
2419     renderThreadAwakened = false;
2420
2421     polishItems();
2422
2423     wake();
2424     wait();
2425
2426     if (!guiAlreadyLocked)
2427         unlockInGui();
2428 }
2429
2430
2431
2432
2433 /*!
2434     Acquires the mutex for the GUI thread. The function uses the isGuiBlocked
2435     variable to keep track of how many recursion levels the gui is locked with.
2436     We only actually acquire the mutex for the first level to avoid deadlocking
2437     ourselves.
2438  */
2439
2440 void QQuickCanvasRenderThread::lockInGui()
2441 {
2442     // We must avoid recursive locking in the GUI thread, hence we
2443     // only lock when we are the first one to try to block.
2444     if (!isGuiBlocked)
2445         lock();
2446
2447     isGuiBlocked++;
2448
2449 #ifdef THREAD_DEBUG
2450     printf("GUI: aquired lock... %d\n", isGuiBlocked);
2451 #endif
2452 }
2453
2454
2455
2456 void QQuickCanvasRenderThread::unlockInGui()
2457 {
2458 #ifdef THREAD_DEBUG
2459     printf("GUI: releasing lock... %d\n", isGuiBlocked);
2460 #endif
2461     --isGuiBlocked;
2462     if (!isGuiBlocked)
2463         unlock();
2464 }
2465
2466
2467
2468
2469 void QQuickCanvasRenderThread::animationStarted()
2470 {
2471 #ifdef THREAD_DEBUG
2472     printf("GUI: animationStarted()\n");
2473 #endif
2474
2475     lockInGui();
2476
2477     animationRunning = true;
2478
2479     if (isRenderBlocked)
2480         wake();
2481
2482     unlockInGui();
2483 }
2484
2485
2486
2487 void QQuickCanvasRenderThread::animationStopped()
2488 {
2489 #ifdef THREAD_DEBUG
2490     printf("GUI: animationStopped()...\n");
2491 #endif
2492
2493     lockInGui();
2494     animationRunning = false;
2495     unlockInGui();
2496 }
2497
2498
2499 void QQuickCanvasRenderThread::paint()
2500 {
2501 #ifdef THREAD_DEBUG
2502     printf("GUI: paint called..\n");
2503 #endif
2504
2505     lockInGui();
2506     exhaustSyncEvent();
2507
2508     isPaintCompleted = false;
2509     while (isRunning() && !isPaintCompleted) {
2510         if (isRenderBlocked)
2511             wake();
2512         wait();
2513     }
2514     unlockInGui();
2515 }
2516
2517
2518
2519 void QQuickCanvasRenderThread::resize(const QSize &size)
2520 {
2521 #ifdef THREAD_DEBUG
2522     printf("GUI: Resize Event: %dx%d\n", size.width(), size.height());
2523 #endif
2524
2525     if (!isRunning()) {
2526         windowSize = size;
2527         return;
2528     }
2529
2530     lockInGui();
2531     exhaustSyncEvent();
2532
2533     windowSize = size;
2534
2535     while (isRunning() && renderedSize != windowSize) {
2536         if (isRenderBlocked)
2537             wake();
2538         wait();
2539     }
2540     unlockInGui();
2541 }
2542
2543
2544
2545 void QQuickCanvasRenderThread::startRendering()
2546 {
2547 #ifdef THREAD_DEBUG
2548     printf("GUI: Starting Render Thread\n");
2549 #endif
2550     hasExited = false;
2551     shouldExit = false;
2552     isGuiBlocked = 0;
2553     isGuiBlockPending = false;
2554     start();
2555 }
2556
2557
2558
2559 void QQuickCanvasRenderThread::stopRendering()
2560 {
2561 #ifdef THREAD_DEBUG
2562     printf("GUI: stopping render thread\n");
2563 #endif
2564
2565     lockInGui();
2566     exhaustSyncEvent();
2567     shouldExit = true;
2568
2569     if (isRenderBlocked) {
2570 #ifdef THREAD_DEBUG
2571         printf("GUI: waking up render thread\n");
2572 #endif
2573         wake();
2574     }
2575
2576     while (!hasExited) {
2577 #ifdef THREAD_DEBUG
2578         printf("GUI: waiting for render thread to have exited..\n");
2579 #endif
2580         wait();
2581     }
2582
2583     unlockInGui();
2584
2585 #ifdef THREAD_DEBUG
2586     printf("GUI: waiting for render thread to terminate..\n");
2587 #endif
2588     // Actually wait for the thread to terminate.  Otherwise we can delete it
2589     // too early and crash.
2590     QThread::wait();
2591
2592 #ifdef THREAD_DEBUG
2593     printf("GUI: thread has terminated and we're all good..\n");
2594 #endif
2595
2596 }
2597
2598
2599
2600 QImage QQuickCanvasRenderThread::grab()
2601 {
2602     if (!isRunning())
2603         return QImage();
2604
2605     if (QThread::currentThread() != qApp->thread()) {
2606         qWarning("QQuickCanvas::grabFrameBuffer: can only be called from the GUI thread");
2607         return QImage();
2608     }
2609
2610 #ifdef THREAD_DEBUG
2611     printf("GUI: doing a pixelwise grab..\n");
2612 #endif
2613
2614     lockInGui();
2615     exhaustSyncEvent();
2616
2617     doGrab = true;
2618     isPaintCompleted = false;
2619     while (isRunning() && !isPaintCompleted) {
2620         if (isRenderBlocked)
2621             wake();
2622         wait();
2623     }
2624
2625     QImage grabbed = grabContent;
2626     grabContent = QImage();
2627
2628     unlockInGui();
2629
2630     return grabbed;
2631 }
2632
2633
2634
2635 void QQuickCanvasRenderThread::maybeUpdate()
2636 {
2637     Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || inSync,
2638                "QQuickCanvas::update",
2639                "Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
2640
2641     if (inSync) {
2642         isExternalUpdatePending = true;
2643
2644     } else if (!renderThreadAwakened) {
2645 #ifdef THREAD_DEBUG
2646         printf("GUI: doing update...\n");
2647 #endif
2648         renderThreadAwakened = true;
2649         lockInGui();
2650         isExternalUpdatePending = true;
2651         if (isRenderBlocked)
2652             wake();
2653         unlockInGui();
2654     }
2655 }
2656
2657
2658 #include "moc_qquickcanvas.cpp"
2659
2660 QT_END_NAMESPACE