1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <private/qsgadaptationlayer_p.h>
43 #include "qquickcanvasitem_p.h"
44 #include <private/qquickitem_p.h>
45 #include <private/qquickcanvascontext_p.h>
46 #include <private/qquickcontext2d_p.h>
47 #include <qsgsimpletexturenode.h>
48 #include <QtQuick/private/qquickpixmapcache_p.h>
51 #include <private/qqmlengine_p.h>
52 #include <QtCore/QBuffer>
56 QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image, QQuickWindow *window)
65 QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *window)
73 QQuickCanvasPixmap::~QQuickCanvasPixmap()
77 m_texture->deleteLater();
80 qreal QQuickCanvasPixmap::width() const
83 return m_pixmap->width();
85 return m_image.width();
88 qreal QQuickCanvasPixmap::height() const
91 return m_pixmap->height();
93 return m_image.height();
96 bool QQuickCanvasPixmap::isValid() const
99 return m_pixmap->isReady();
100 return !m_image.isNull();
103 QSGTexture *QQuickCanvasPixmap::texture()
107 Q_ASSERT(m_pixmap->textureFactory());
108 m_texture = m_pixmap->textureFactory()->createTexture(m_window);
110 m_texture = QQuickWindowPrivate::get(m_window)->context->createTexture(m_image);
115 QImage QQuickCanvasPixmap::image()
117 if (m_image.isNull() && m_pixmap)
118 m_image = m_pixmap->image();
123 QHash<QQmlEngine *,QQuickContext2DRenderThread*> QQuickContext2DRenderThread::renderThreads;
124 QMutex QQuickContext2DRenderThread::renderThreadsMutex;
126 QQuickContext2DRenderThread::QQuickContext2DRenderThread(QQmlEngine *eng)
127 : QThread(eng), m_engine(eng), m_eventLoopQuitHack(0)
130 m_eventLoopQuitHack = new QObject;
131 m_eventLoopQuitHack->moveToThread(this);
132 connect(m_eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection);
133 start(QThread::IdlePriority);
136 QQuickContext2DRenderThread::~QQuickContext2DRenderThread()
138 renderThreadsMutex.lock();
139 renderThreads.remove(m_engine);
140 renderThreadsMutex.unlock();
142 m_eventLoopQuitHack->deleteLater();
146 QQuickContext2DRenderThread *QQuickContext2DRenderThread::instance(QQmlEngine *engine)
148 QQuickContext2DRenderThread *thread = 0;
149 renderThreadsMutex.lock();
150 if (renderThreads.contains(engine))
151 thread = renderThreads.value(engine);
153 thread = new QQuickContext2DRenderThread(engine);
154 renderThreads.insert(engine, thread);
156 renderThreadsMutex.unlock();
160 class QQuickCanvasItemPrivate : public QQuickItemPrivate
163 QQuickCanvasItemPrivate();
164 ~QQuickCanvasItemPrivate();
165 QQuickCanvasContext *context;
170 uint hasCanvasSize :1;
172 uint hasCanvasWindow :1;
174 uint contextInitialized :1;
175 QQuickCanvasItem::RenderTarget renderTarget;
176 QQuickCanvasItem::RenderStrategy renderStrategy;
178 QHash<QUrl, QQmlRefPointer<QQuickCanvasPixmap> > pixmaps;
180 QMap<int, v8::Persistent<v8::Function> > animationCallbacks;
183 QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
184 : QQuickItemPrivate()
188 , hasCanvasSize(false)
190 , hasCanvasWindow(false)
192 , contextInitialized(false)
193 , renderTarget(QQuickCanvasItem::FramebufferObject)
194 , renderStrategy(QQuickCanvasItem::Cooperative)
198 QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
206 \instantiates QQuickCanvasItem
207 \inqmlmodule QtQuick 2
210 \ingroup qtquick-canvas
211 \ingroup qtquick-visual
212 \brief Provides a 2D canvas item enabling drawing via JavaScript
214 The Canvas item allows drawing of straight and curved lines, simple and
215 complex shapes, graphs, and referenced graphic images. It can also add
216 text, colors, shadows, gradients, and patterns, and do low level pixel
217 operations. The Canvas output may be saved as an image file or serialized
220 To define a drawing area in the Canvas item set the \c width and \c height
221 properties. For example, the following code creates a Canvas item which
222 has a drawing area with a height of 100 pixels and width of 200 pixels:
232 Currently the Canvas item only supports the two-dimensional rendering context.
234 \section1 Threaded Rendering and Render Target
236 The Canvas item supports two render targets: \c Canvas.Image and
237 \c Canvas.FramebufferObject.
239 The \c Canvas.Image render target is a \a QImage object. This render
240 target supports background thread rendering, allowing complex or long
241 running painting to be executed without blocking the UI.
243 The Canvas.FramebufferObject render target utilizes OpenGL hardware
244 acceleration rather than rendering into system memory, which in many cases
245 results in faster rendering.
247 The default render target is Canvas.Image and the default renderStrategy is
250 \section1 Tiled Canvas
251 The Canvas item supports tiled rendering by setting \l canvasSize, \l tileSize
252 and \l canvasWindow properties.
254 Tiling allows efficient display of a very large virtual canvas via a smaller
255 canvas window. The actual memory consumption is in relation to the canvas
256 window size. The painting code can draw within the virtual canvas without
257 handling coordinate system transformations.
259 The tiles overlapping with the canvas window may be cached eliminating the
260 need to redraw, which can lead to significantly improved performance in
263 \section1 Pixel Operations
264 All HTML5 2D context pixel operations are supported. In order to ensure
265 improved pixel reading/writing performance the \a Canvas.Image render
266 target should be chosen. The \a Canvas.FramebufferObject render target
267 requires the pixel data to be exchanged between the system memory and the
268 graphic card, which is significantly more expensive. Rendering may also be
269 synchronized with the V-sync signal (to avoid
270 {en.wikipedia.org/wiki/Screen_tearing}{screen tearing}) which will further
271 impact pixel operations with \c Canvas.FrambufferObject render target.
273 \section1 Tips for Porting Existing HTML5 Canvas applications
275 Although the Canvas item is provides a HTML5 like API, HTML5 canvas
276 applications need to be modified to run in the Canvas item:
278 \li Replace all DOM API calls with QML property bindings or Canvas item methods.
279 \li Replace all HTML event handlers with the \a MouseArea item.
280 \li Change setInterval/setTimeout function calls with the \a Timer item or
281 the use of requestAnimationFrame.
282 \li Place painting code into the \a QtQuick2::Canvas::onPaint handler and trigger
283 painting by calling the \c markDirty or \c requestPaint methods.
284 \li To draw images, load them by calling the Canvas's loadImage method and then request to paint
285 them in the onImageLoaded handler.
288 \sa QtQuick2::Context2D
291 QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
292 : QQuickItem(*(new QQuickCanvasItemPrivate), parent)
294 setFlag(ItemHasContents);
297 QQuickCanvasItem::~QQuickCanvasItem()
299 Q_D(QQuickCanvasItem);
304 \qmlproperty size QtQuick2::Canvas::available
306 Indicates when Canvas is able to provide a drawing context to operate on.
309 bool QQuickCanvasItem::isAvailable() const
311 return d_func()->available;
315 \qmlproperty string QtQuick2::Canvas::contextType
316 The type of drawing context to use.
318 This property is set to the name of the active context type.
320 If set explicitly the canvas will attempt to create a context of the
321 named type after becoming available.
323 The type name is the same as used in the getContext() call, for the 2d
324 canvas the value will be "2d".
326 \sa QtQuick2::Canvas::getContext, QtQuick2::Canvas::available
329 QString QQuickCanvasItem::contextType() const
331 return d_func()->contextType;
334 void QQuickCanvasItem::setContextType(const QString &contextType)
336 Q_D(QQuickCanvasItem);
338 if (contextType.compare(d->contextType, Qt::CaseInsensitive) == 0)
341 if (d->contextInitialized) {
342 qmlInfo(this) << "Canvas already initialized with a different context type";
346 d->contextType = contextType;
349 createContext(contextType);
351 emit contextTypeChanged();
355 \qmlproperty object QtQuick2::Canvas::context
356 Holds the active drawing context.
358 If the canvas is ready and there has been a successful call to getContext()
359 or the contextType property has been set with a supported context type,
360 this property will contain the current drawing context, otherwise null.
363 QQmlV8Handle QQuickCanvasItem::context() const
365 Q_D(const QQuickCanvasItem);
366 if (d->contextInitialized)
367 return QQmlV8Handle::fromHandle(d->context->v8value());
369 return QQmlV8Handle::fromHandle(v8::Null());
373 \qmlproperty size QtQuick2::Canvas::canvasSize
374 Holds the logical canvas size that the context paints on.
376 By default, the canvas size is the same size as the current canvas item
379 By setting the canvasSize, tileSize and canvasWindow, the Canvas item can
380 act as a large virtual canvas with many separately rendered tile rectangles
381 Only those tiles within the current canvas window are painted by the Canvas
384 \sa QtQuick2::Canvas::tileSize, QtQuick2::Canvas::canvasWindow
386 QSizeF QQuickCanvasItem::canvasSize() const
388 Q_D(const QQuickCanvasItem);
389 return d->canvasSize;
392 void QQuickCanvasItem::setCanvasSize(const QSizeF & size)
394 Q_D(QQuickCanvasItem);
395 if (d->canvasSize != size) {
396 d->hasCanvasSize = true;
397 d->canvasSize = size;
398 emit canvasSizeChanged();
400 if (d->contextInitialized)
406 \qmlproperty size QtQuick2::Canvas::tileSize
407 Holds the canvas rendering tile size.
409 The Canvas item enters tiled mode by setting canvasSize, tileSize and the
410 canvasWindow. This can improve rendering performance by rendering and
411 caching tiles instead of rendering the whole canvas every time.
413 Memory will be consumed only by those tiles within the current visible
416 By default the tileSize is the same as the canvasSize.
418 \sa QtQuick2::Canvas::canvaasSize, QtQuick2::Canvas::canvasWindow
420 QSize QQuickCanvasItem::tileSize() const
422 Q_D(const QQuickCanvasItem);
426 void QQuickCanvasItem::setTileSize(const QSize & size)
428 Q_D(QQuickCanvasItem);
429 if (d->tileSize != size) {
430 d->hasTileSize = true;
433 emit tileSizeChanged();
435 if (d->contextInitialized)
441 \qmlproperty rect QtQuick2::Canvas::canvasWindow
442 Holds the current canvas visible window.
444 By default the canvasWindow size is the same as the Canvas item size with
445 the top-left point as (0, 0).
447 If the canvasSize is different to the Canvas item size, the Canvas item
448 can display different visible areas by changing the canvas windowSize
451 \sa QtQuick2::Canvas::canvasSize, QtQuick2::Canvas::tileSize
453 QRectF QQuickCanvasItem::canvasWindow() const
455 Q_D(const QQuickCanvasItem);
456 return d->canvasWindow;
459 void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
461 Q_D(QQuickCanvasItem);
462 if (d->canvasWindow != rect) {
463 d->canvasWindow = rect;
465 d->hasCanvasWindow = true;
466 emit canvasWindowChanged();
468 if (d->contextInitialized)
474 \qmlproperty enumeration QtQuick2::Canvas::renderTarget
475 Holds the current canvas render target.
478 \li Canvas.Image - render to an in memory image buffer.
479 \li Canvas.FramebufferObject - render to an OpenGL frame buffer
482 This hint is supplied along with renderStrategy to the graphics context to
483 determine the method of rendering. A renderStrategy, renderTarget or a
484 combination may not be supported by a graphics context, in which case the
485 context will choose appropriate options and Canvas will signal the change
488 The default render target is \c Canvas.FramebufferObject.
490 QQuickCanvasItem::RenderTarget QQuickCanvasItem::renderTarget() const
492 Q_D(const QQuickCanvasItem);
493 return d->renderTarget;
496 void QQuickCanvasItem::setRenderTarget(QQuickCanvasItem::RenderTarget target)
498 Q_D(QQuickCanvasItem);
499 if (d->renderTarget != target) {
500 if (d->contextInitialized) {
501 qmlInfo(this) << "Canvas:renderTarget not changeble once context is active.";
505 d->renderTarget = target;
506 emit renderTargetChanged();
511 \qmlproperty enumeration QtQuick2::Canvas::renderStrategy
512 Holds the current canvas rendering strategy.
515 \li Canvas.Immediate - context will perform graphics commands immediately in the main UI thread.
516 \li Canvas.Threaded - context will defer graphics commands to a private rendering thread.
517 \li Canvas.Cooperative - context will defer graphics commands to the applications global render thread.
520 This hint is supplied along with renderTarget to the graphics context to
521 determine the method of rendering. A renderStrategy, renderTarget or a
522 combination may not be supported by a graphics context, in which case the
523 context will choose appropriate options and Canvas will signal the change
526 Configuration or runtime tests may cause the QML Scene Graph to render in
527 the GUI thread. Selecting \c Canvas.Cooperative, does not guarantee
528 rendering will occur on a thread separate from the GUI thread.
530 The default value is \c Canvas.Cooperative.
532 \sa QtQuick2::Canvas::renderTarget
535 QQuickCanvasItem::RenderStrategy QQuickCanvasItem::renderStrategy() const
537 return d_func()->renderStrategy;
540 void QQuickCanvasItem::setRenderStrategy(QQuickCanvasItem::RenderStrategy strategy)
542 Q_D(QQuickCanvasItem);
543 if (d->renderStrategy != strategy) {
544 if (d->contextInitialized) {
545 qmlInfo(this) << "Canvas:renderStrategy not changeable once context is active.";
549 d->renderStrategy = strategy;
550 emit renderStrategyChanged();
554 QQuickCanvasContext* QQuickCanvasItem::rawContext() const
556 return d_func()->context;
559 bool QQuickCanvasItem::isPaintConnected()
561 IS_SIGNAL_CONNECTED(this, QQuickCanvasItem, paint, (const QRect &));
564 void QQuickCanvasItem::sceneGraphInitialized()
566 Q_D(QQuickCanvasItem);
569 connect(this, SIGNAL(visibleChanged()), SLOT(checkAnimationCallbacks()));
570 QMetaObject::invokeMethod(this, "availableChanged", Qt::QueuedConnection);
572 if (!d->contextType.isNull())
573 QMetaObject::invokeMethod(this, "delayedCreate", Qt::QueuedConnection);
574 else if (isPaintConnected())
575 QMetaObject::invokeMethod(this, "requestPaint", Qt::QueuedConnection);
578 void QQuickCanvasItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
580 Q_D(QQuickCanvasItem);
582 QQuickItem::geometryChanged(newGeometry, oldGeometry);
584 QSizeF newSize = newGeometry.size();
585 if (!d->hasCanvasSize && d->canvasSize != newSize) {
586 d->canvasSize = newSize;
587 emit canvasSizeChanged();
590 if (!d->hasTileSize && d->tileSize != newSize) {
591 d->tileSize = newSize.toSize();
592 emit tileSizeChanged();
595 const QRectF rect = QRectF(QPointF(0, 0), newSize);
597 if (!d->hasCanvasWindow && d->canvasWindow != rect) {
598 d->canvasWindow = rect;
599 emit canvasWindowChanged();
606 void QQuickCanvasItem::componentComplete()
608 QQuickItem::componentComplete();
610 Q_D(QQuickCanvasItem);
611 d->baseUrl = qmlEngine(this)->contextForObject(this)->baseUrl();
614 void QQuickCanvasItem::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
616 QQuickItem::itemChange(change, value);
617 if (change != QQuickItem::ItemSceneChange)
620 Q_D(QQuickCanvasItem);
624 if (value.window== 0)
627 d->window = value.window;
628 if (d->window->openglContext() != 0) // available context == initialized
629 sceneGraphInitialized();
631 connect(d->window, SIGNAL(sceneGraphInitialized()), SLOT(sceneGraphInitialized()));
634 void QQuickCanvasItem::updatePolish()
636 QQuickItem::updatePolish();
638 Q_D(QQuickCanvasItem);
640 if (d->contextInitialized)
641 d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth);
643 if (d->animationCallbacks.size() > 0 && isVisible()) {
644 QMap<int, v8::Persistent<v8::Function> > animationCallbacks = d->animationCallbacks;
645 d->animationCallbacks.clear();
647 foreach (int key, animationCallbacks.keys()) {
648 v8::HandleScope handle_scope;
649 v8::Handle<v8::Object> self = QQmlEnginePrivate::getV8Engine(qmlEngine(this))->newQObject(this).As<v8::Object>();
650 v8::Handle<v8::Value> args[] = { v8::Uint32::New(QDateTime::currentDateTimeUtc().toTime_t()) };
651 v8::Persistent<v8::Function> f = animationCallbacks.value(key);
652 f->Call(self, 1, args);
657 if (d->dirtyRect.isValid()) {
658 if (d->hasTileSize && d->hasCanvasWindow)
659 emit paint(tiledRect(d->canvasWindow.intersected(d->dirtyRect.toAlignedRect()), d->tileSize));
661 emit paint(d->dirtyRect.toRect());
662 d->dirtyRect = QRectF();
666 if (d->contextInitialized) {
667 if (d->renderStrategy == QQuickCanvasItem::Cooperative)
674 QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
676 Q_D(QQuickCanvasItem);
678 if (!d->contextInitialized)
681 class CanvasTextureNode : public QSGSimpleTextureNode
684 CanvasTextureNode() : QSGSimpleTextureNode() {}
685 ~CanvasTextureNode() {delete texture();}
688 CanvasTextureNode *node = static_cast<CanvasTextureNode*>(oldNode);
690 node = new CanvasTextureNode;
693 if (d->renderStrategy == QQuickCanvasItem::Cooperative)
696 node->setTexture(d->context->texture());
697 node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
702 \qmlmethod object QtQuick2::Canvas::getContext(string contextId, any... args)
704 Returns a drawing context or null if no context available.
706 The \a contextId parameter names the required context. The Canvas item
707 will return a context that implements the required drawing mode. After the
708 first call to getContext any subsequent call to getContext with the same
709 contextId will return the same context object.
711 If the context type is not supported or the canvas has previously been
712 requested to provide a different and incompatible context type, null will
715 Canvas only supports a 2d context.
718 void QQuickCanvasItem::getContext(QQmlV8Function *args)
720 Q_D(QQuickCanvasItem);
722 if (args->Length() < 1 || !(*args)[0]->IsString()) {
723 qmlInfo(this) << "getContext should be called with a string naming the required context type";
724 args->returnValue(v8::Null());
729 qmlInfo(this) << "Unable to use getContext() at this time, please wait for available: true";
730 args->returnValue(v8::Null());
734 QString contextId = QString::fromUtf16(*v8::String::Value((*args)[0]));
736 if (d->context != 0) {
737 if (d->context->contextNames().contains(contextId, Qt::CaseInsensitive)) {
738 args->returnValue(d->context->v8value());
742 qmlInfo(this) << "Canvas already initialized with a different context type";
743 args->returnValue(v8::Null());
747 if (createContext(contextId))
748 args->returnValue(d->context->v8value());
750 args->returnValue(v8::Null());
754 \qmlmethod long QtQuick2::Canvas::requestAnimationFrame(callback)
756 This function schedules callback to be invoked before composing the QtQuick
760 void QQuickCanvasItem::requestAnimationFrame(QQmlV8Function *args)
762 if (args->Length() < 1 || !(*args)[0]->IsFunction()) {
763 qmlInfo(this) << "requestAnimationFrame should be called with an animation callback function";
764 args->returnValue(v8::Null());
768 Q_D(QQuickCanvasItem);
772 d->animationCallbacks.insert(++id, v8::Persistent<v8::Function>::New(((*args)[0]).As<v8::Function>()));
777 args->returnValue(v8::Int32::New(id));
781 \qmlmethod void QtQuick2::Canvas::cancelRequestAnimationFrmae(long handle)
783 This function will cancel the animation callback referenced by \a handle.
786 void QQuickCanvasItem::cancelRequestAnimationFrame(QQmlV8Function *args)
788 if (args->Length() < 1 || !(*args)[0]->IsInt32()) {
789 qmlInfo(this) << "cancelRequestAnimationFrame should be called with an animation callback id";
790 args->returnValue(v8::Null());
794 d_func()->animationCallbacks.remove((*args)[0]->Int32Value());
799 \qmlmethod void QtQuick2::Canvas::requestPaint()
801 Request the entire visible region be re-drawn.
803 \sa QtQuick::Canvas::markDirty
806 void QQuickCanvasItem::requestPaint()
808 markDirty(d_func()->canvasWindow);
812 \qmlmethod void QtQuick2::Canvas::markDirty(rect area)
814 Mark the given \a area as dirty, so that when this area is visible the
815 canvas renderer will redraw it. This will trigger the "onPaint" signal
818 \sa QtQuick2::Canvas::paint, QtQuick2::Canvas::requestPaint
821 void QQuickCanvasItem::markDirty(const QRectF& rect)
823 Q_D(QQuickCanvasItem);
827 d->dirtyRect |= rect;
832 void QQuickCanvasItem::checkAnimationCallbacks()
834 if (d_func()->animationCallbacks.size() > 0 && isVisible())
839 \qmlmethod bool QtQuick2::Canvas::save(string filename)
841 Save the current canvas content into an image file \a filename.
842 The saved image format is automatically decided by the \a filename's
845 Note: calling this method will force painting the whole canvas, not just the
846 current canvas visible window.
848 \sa canvasWindow, canvasSize, toDataURL
850 bool QQuickCanvasItem::save(const QString &filename) const
852 Q_D(const QQuickCanvasItem);
853 QUrl url = d->baseUrl.resolved(QUrl::fromLocalFile(filename));
854 return toImage().save(url.toLocalFile());
857 QQmlRefPointer<QQuickCanvasPixmap> QQuickCanvasItem::loadedPixmap(const QUrl& url)
859 Q_D(QQuickCanvasItem);
860 QUrl fullPathUrl = d->baseUrl.resolved(url);
861 if (!d->pixmaps.contains(fullPathUrl)) {
864 return d->pixmaps.value(fullPathUrl);
868 \qmlmethod void QtQuick2::Canvas::loadImage(url image)
869 Loads the given \c image asynchronously.
871 When the image is ready, onImageLoaded will be emitted.
872 The loaded image can be unloaded by the \a QtQuick2::Canvas::unloadImage method.
874 Note: Only loaded images can be painted on the Canvas item.
875 \sa QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::imageLoaded, QtQuick2::Canvas::isImageLoaded,
876 QtQuick2::Context2D::createImageData, QtQuick2::Context2D::drawImage
878 void QQuickCanvasItem::loadImage(const QUrl& url)
880 Q_D(QQuickCanvasItem);
881 QUrl fullPathUrl = d->baseUrl.resolved(url);
882 if (!d->pixmaps.contains(fullPathUrl)) {
883 QQuickPixmap* pix = new QQuickPixmap();
884 QQmlRefPointer<QQuickCanvasPixmap> canvasPix;
885 canvasPix.take(new QQuickCanvasPixmap(pix, d->window));
886 d->pixmaps.insert(fullPathUrl, canvasPix);
888 pix->load(qmlEngine(this)
890 , QQuickPixmap::Cache | QQuickPixmap::Asynchronous);
891 if (pix->isLoading())
892 pix->connectFinished(this, SIGNAL(imageLoaded()));
896 \qmlmethod void QtQuick2::Canvas::unloadImage(url image)
897 Unloads the \c image.
899 Once an image is unloaded it cannot be painted by the canvas context
900 unless it is loaded again.
902 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::imageLoaded, QtQuick2::Canvas::isImageLoaded,
903 QtQuick2::Context2D::createImageData, QtQuick2::Context2D::drawImage
905 void QQuickCanvasItem::unloadImage(const QUrl& url)
907 Q_D(QQuickCanvasItem);
908 d->pixmaps.remove(d->baseUrl.resolved(url));
912 \qmlmethod void QtQuick2::Canvas::isImageError(url image)
913 Returns true if the \a image failed to load.
915 \sa QtQuick2::Canvas::loadImage
917 bool QQuickCanvasItem::isImageError(const QUrl& url) const
919 Q_D(const QQuickCanvasItem);
920 QUrl fullPathUrl = d->baseUrl.resolved(url);
921 return d->pixmaps.contains(fullPathUrl)
922 && d->pixmaps.value(fullPathUrl)->pixmap()->isError();
926 \qmlmethod void QtQuick2::Canvas::isImageLoading(url image)
927 Returns true if the \a image is currently loading.
929 \sa QtQuick2::Canvas::loadImage
931 bool QQuickCanvasItem::isImageLoading(const QUrl& url) const
933 Q_D(const QQuickCanvasItem);
934 QUrl fullPathUrl = d->baseUrl.resolved(url);
935 return d->pixmaps.contains(fullPathUrl)
936 && d->pixmaps.value(fullPathUrl)->pixmap()->isLoading();
939 \qmlmethod void QtQuick2::Canvas::isImageLoaded(url image)
940 Returns true if the \a image is sucessfully loaded and ready to use.
942 \sa QtQuick2::Canvas::loadImage
944 bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const
946 Q_D(const QQuickCanvasItem);
947 QUrl fullPathUrl = d->baseUrl.resolved(url);
948 return d->pixmaps.contains(fullPathUrl)
949 && d->pixmaps.value(fullPathUrl)->pixmap()->isReady();
952 QImage QQuickCanvasItem::toImage(const QRectF& rect) const
954 Q_D(const QQuickCanvasItem);
955 if (d->contextInitialized) {
957 return d->context->toImage(canvasWindow());
959 return d->context->toImage(rect);
966 \qmlmethod string QtQuick2::Canvas::toDataURL(string mimeType)
968 Returns a data URL for the image in the canvas.
970 The default \a mimeType is "image/png".
972 \sa QtQuick2::Canvas::save
974 QString QQuickCanvasItem::toDataURL(const QString& mimeType) const
976 QImage image = toImage();
978 if (!image.isNull()) {
981 buffer.open(QIODevice::WriteOnly);
982 QString mime = mimeType.toLower();
984 if (mime == QLatin1String("image/png")) {
985 type = QStringLiteral("PNG");
986 } else if (mime == QLatin1String("image/bmp"))
987 type = QStringLiteral("BMP");
988 else if (mime == QLatin1String("image/jpeg"))
989 type = QStringLiteral("JPEG");
990 else if (mime == QLatin1String("image/x-portable-pixmap"))
991 type = QStringLiteral("PPM");
992 else if (mime == QLatin1String("image/tiff"))
993 type = QStringLiteral("TIFF");
994 else if (mime == QLatin1String("image/xpm"))
995 type = QStringLiteral("XPM");
997 return QStringLiteral("data:,");
999 image.save(&buffer, type.toLatin1());
1001 QString dataUrl = QStringLiteral("data:%1;base64,%2");
1002 return dataUrl.arg(mime).arg(QLatin1String(ba.toBase64().constData()));
1004 return QStringLiteral("data:,");
1007 void QQuickCanvasItem::delayedCreate()
1009 Q_D(QQuickCanvasItem);
1011 if (!d->contextInitialized && !d->contextType.isNull())
1012 createContext(d->contextType);
1017 bool QQuickCanvasItem::createContext(const QString &contextType)
1019 Q_D(QQuickCanvasItem);
1021 if (contextType == QLatin1String("2d")) {
1022 if (d->contextType.compare(QLatin1String("2d"), Qt::CaseInsensitive) != 0) {
1023 d->contextType = QLatin1String("2d");
1024 emit contextTypeChanged(); // XXX: can't be in setContextType()
1026 initializeContext(new QQuickContext2D(this));
1033 void QQuickCanvasItem::initializeContext(QQuickCanvasContext *context, const QVariantMap &args)
1035 Q_D(QQuickCanvasItem);
1037 d->context = context;
1038 d->context->init(this, args);
1039 d->context->setV8Engine(QQmlEnginePrivate::getV8Engine(qmlEngine(this)));
1040 d->contextInitialized = true;
1041 connect(d->context, SIGNAL(textureChanged()), SLOT(update()));
1042 connect(d->context, SIGNAL(textureChanged()), SIGNAL(painted()));
1043 emit contextChanged();
1046 QRect QQuickCanvasItem::tiledRect(const QRectF &window, const QSize &tileSize)
1048 if (window.isEmpty())
1051 const int tw = tileSize.width();
1052 const int th = tileSize.height();
1053 const int h1 = window.left() / tw;
1054 const int v1 = window.top() / th;
1056 const int htiles = ((window.right() - h1 * tw) + tw - 1)/tw;
1057 const int vtiles = ((window.bottom() - v1 * th) + th - 1)/th;
1059 return QRect(h1 * tw, v1 * th, htiles * tw, vtiles * th);
1063 \qmlsignal QtQuick2::Canvas::onPaint(rect region)
1065 This handler is called to render the \a region. If a context is active it
1066 can be referenced from the context property.
1068 This signal can be triggered by QtQuick2::Canvas::markdirty,
1069 QtQuick2::Canvas::requestPaint or by changing the current canvas window.
1073 \qmlsignal QtQuick2::Canvas::onPainted()
1075 This handler is called after all context painting commands are executed and
1076 the Canvas has been rendered.