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 QHash<QQmlEngine *,QQuickContext2DRenderThread*> QQuickContext2DRenderThread::renderThreads;
57 QMutex QQuickContext2DRenderThread::renderThreadsMutex;
59 QQuickContext2DRenderThread::QQuickContext2DRenderThread(QQmlEngine *eng)
60 : QThread(eng), m_engine(eng), m_eventLoopQuitHack(0)
63 m_eventLoopQuitHack = new QObject;
64 m_eventLoopQuitHack->moveToThread(this);
65 connect(m_eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection);
66 start(QThread::IdlePriority);
69 QQuickContext2DRenderThread::~QQuickContext2DRenderThread()
71 renderThreadsMutex.lock();
72 renderThreads.remove(m_engine);
73 renderThreadsMutex.unlock();
75 m_eventLoopQuitHack->deleteLater();
79 QQuickContext2DRenderThread *QQuickContext2DRenderThread::instance(QQmlEngine *engine)
81 QQuickContext2DRenderThread *thread = 0;
82 renderThreadsMutex.lock();
83 if (renderThreads.contains(engine))
84 thread = renderThreads.value(engine);
86 thread = new QQuickContext2DRenderThread(engine);
87 renderThreads.insert(engine, thread);
89 renderThreadsMutex.unlock();
93 class QQuickCanvasItemPrivate : public QQuickItemPrivate
96 QQuickCanvasItemPrivate();
97 ~QQuickCanvasItemPrivate();
98 QQuickCanvasContext* context;
103 uint hasCanvasSize :1;
105 uint hasCanvasWindow :1;
107 uint contextInitialized :1;
108 QQuickCanvasItem::RenderTarget renderTarget;
109 QQuickCanvasItem::RenderStrategy renderStrategy;
111 QHash<QUrl, QQuickPixmap*> images;
113 QMap<int, v8::Persistent<v8::Function> > animationCallbacks;
116 QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
117 : QQuickItemPrivate()
121 , hasCanvasSize(false)
123 , hasCanvasWindow(false)
125 , contextInitialized(false)
126 , renderTarget(QQuickCanvasItem::FramebufferObject)
127 , renderStrategy(QQuickCanvasItem::Cooperative)
131 QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
138 \qmlclass Canvas QQuickCanvasItem
139 \inqmlmodule QtQuick 2
141 \brief The Canvas item provides a 2D canvas element which enables drawing via Javascript.
143 \ingroup qml-basic-visual-elements
145 The Canvas item allows drawing of straight and curved lines, simple and
146 complex shapes, graphs, and referenced graphic images. It can also add
147 text, colors, shadows, gradients, and patterns, and do low level pixel
148 operations. The Canvas output may be saved as an image file or serialized
151 To define a drawing area in the Canvas item set the \c width and \c height
152 properties. For example, the following code creates a Canvas item which
153 has a drawing area with a height of 100 pixels and width of 200 pixels:
163 Currently the Canvas item only supports the two-dimensional rendering context.
165 \section1 Threaded Rendering and Render Target
167 The Canvas item supports two render targets: \c Canvas.Image and
168 \c Canvas.FramebufferObject.
170 The \c Canvas.Image render target is a \a QImage object. This render
171 target supports background thread rendering, allowing complex or long
172 running painting to be executed without blocking the UI.
174 The Canvas.FramebufferObject render target utilizes OpenGL hardware
175 acceleration rather than rendering into system memory, which in many cases
176 results in faster rendering.
178 The default render target is Canvas.Image and the default renderStrategy is
181 \section1 Tiled Canvas
182 The Canvas item supports tiled rendering by setting \l canvasSize, \l tileSize
183 and \l canvasWindow properties.
185 Tiling allows efficient display of a very large virtual canvas via a smaller
186 canvas window. The actual memory consumption is in relation to the canvas
187 window size. The painting code can draw within the virtual canvas without
188 handling coordinate system transformations.
190 The tiles overlapping with the canvas window may be cached eliminating the
191 need to redraw, which can lead to significantly improved performance in
194 \section1 Pixel Operations
195 All HTML5 2D context pixel operations are supported. In order to ensure
196 improved pixel reading/writing performance the \a Canvas.Image render
197 target should be chosen. The \a Canvas.FramebufferObject render target
198 requires the pixel data to be exchanged between the system memory and the
199 graphic card, which is significantly more expensive. Rendering may also be
200 synchronized with the V-sync signal (to avoid
201 {en.wikipedia.org/wiki/Screen_tearing}{screen tearing}) which will further
202 impact pixel operations with \c Canvas.FrambufferObject render target.
204 \section1 Tips for Porting Existing HTML5 Canvas applications
206 Although the Canvas item is provides a HTML5 like API, HTML5 canvas
207 applications need to be modified to run in the Canvas item:
209 \li Replace all DOM API calls with QML property bindings or Canvas item methods.
210 \li Replace all HTML event handlers with the \a MouseArea item.
211 \li Change setInterval/setTimeout function calls with the \a Timer item or
212 the use of requestAnimationFrame.
213 \li Place painting code into the \a QtQuick2::Canvas::onPaint handler and trigger
214 painting by calling the \c markDirty or \c requestPaint methods.
215 \li To draw images, load them by calling the Canvas's loadImage method and then request to paint
216 them in the onImageLoaded handler.
219 \sa QtQuick2::Context2D
222 QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
223 : QQuickItem(*(new QQuickCanvasItemPrivate), parent)
225 setFlag(ItemHasContents);
228 QQuickCanvasItem::~QQuickCanvasItem()
230 Q_D(QQuickCanvasItem);
235 \qmlproperty size QtQuick2::Canvas::available
237 Indicates when Canvas is able to provide a drawing context to operate on.
240 bool QQuickCanvasItem::isAvailable() const
242 return d_func()->available;
246 \qmlproperty string QtQuick2::Canvas::contextType
247 The type of drawing context to use.
249 This property is set to the name of the active context type.
251 If set explicitly the canvas will attempt to create a context of the
252 named type after becoming available.
254 The type name is the same as used in the getContext() call, for the 2d
255 canvas the value will be "2d".
257 \sa QtQuick2::Canvas::getContext QtQuick2::Canvas::available
260 QString QQuickCanvasItem::contextType() const
262 return d_func()->contextType;
265 void QQuickCanvasItem::setContextType(const QString &contextType)
267 Q_D(QQuickCanvasItem);
269 if (contextType.compare(d->contextType, Qt::CaseInsensitive) == 0)
272 if (d->contextInitialized) {
273 qmlInfo(this) << "Canvas already initialized with a different context type";
277 d->contextType = contextType;
280 createContext(contextType);
282 emit contextTypeChanged();
286 \qmlproperty object QtQuick2::Canvas::context
287 Holds the active drawing context.
289 If the canvas is ready and there has been a successful call to getContext()
290 or the contextType property has been set with a supported context type,
291 this property will contain the current drawing context, otherwise null.
294 QQmlV8Handle QQuickCanvasItem::context() const
296 Q_D(const QQuickCanvasItem);
297 if (d->contextInitialized)
298 return QQmlV8Handle::fromHandle(d->context->v8value());
300 return QQmlV8Handle::fromHandle(v8::Null());
304 \qmlproperty size QtQuick2::Canvas::canvasSize
305 Holds the logical canvas size that the context paints on.
307 By default, the canvas size is the same size as the current canvas item
310 By setting the canvasSize, tileSize and canvasWindow, the Canvas item can
311 act as a large virtual canvas with many separately rendered tile rectangles
312 Only those tiles within the current canvas window are painted by the Canvas
315 \sa QtQuick2::Canvas::tileSize QtQuick2::Canvas::canvasWindow
317 QSizeF QQuickCanvasItem::canvasSize() const
319 Q_D(const QQuickCanvasItem);
320 return d->canvasSize;
323 void QQuickCanvasItem::setCanvasSize(const QSizeF & size)
325 Q_D(QQuickCanvasItem);
326 if (d->canvasSize != size) {
327 d->hasCanvasSize = true;
328 d->canvasSize = size;
329 emit canvasSizeChanged();
331 if (d->contextInitialized)
337 \qmlproperty size QtQuick2::Canvas::tileSize
338 Holds the canvas rendering tile size.
340 The Canvas item enters tiled mode by setting canvasSize, tileSize and the
341 canvasWindow. This can improve rendering performance by rendering and
342 caching tiles instead of rendering the whole canvas every time.
344 Memory will be consumed only by those tiles within the current visible
347 By default the tileSize is the same as the canvasSize.
349 \sa QtQuick2::Canvas::canvaasSize QtQuick2::Canvas::canvasWindow
351 QSize QQuickCanvasItem::tileSize() const
353 Q_D(const QQuickCanvasItem);
357 void QQuickCanvasItem::setTileSize(const QSize & size)
359 Q_D(QQuickCanvasItem);
360 if (d->tileSize != size) {
361 d->hasTileSize = true;
364 emit tileSizeChanged();
366 if (d->contextInitialized)
372 \qmlproperty rect QtQuick2::Canvas::canvasWindow
373 Holds the current canvas visible window.
375 By default the canvasWindow size is the same as the Canvas item size with
376 the top-left point as (0, 0).
378 If the canvasSize is different to the Canvas item size, the Canvas item
379 can display different visible areas by changing the canvas windowSize
382 \sa QtQuick2::Canvas::canvasSize QtQuick2::Canvas::tileSize
384 QRectF QQuickCanvasItem::canvasWindow() const
386 Q_D(const QQuickCanvasItem);
387 return d->canvasWindow;
390 void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
392 Q_D(QQuickCanvasItem);
393 if (d->canvasWindow != rect) {
394 d->canvasWindow = rect;
396 d->hasCanvasWindow = true;
397 emit canvasWindowChanged();
399 if (d->contextInitialized)
405 \qmlproperty bool QtQuick2::Canvas::renderTarget
406 Holds the current canvas render target.
409 \li Canvas.Image - render to an in memory image buffer.
410 \li Canvas.FramebufferObject - render to an OpenGL frame buffer
413 This hint is supplied along with renderStrategy to the graphics context to
414 determine the method of rendering. A renderStrategy, renderTarget or a
415 combination may not be supported by a graphics context, in which case the
416 context will choose appropriate options and Canvas will signal the change
419 The default render target is \c Canvas.FramebufferObject.
421 QQuickCanvasItem::RenderTarget QQuickCanvasItem::renderTarget() const
423 Q_D(const QQuickCanvasItem);
424 return d->renderTarget;
427 void QQuickCanvasItem::setRenderTarget(QQuickCanvasItem::RenderTarget target)
429 Q_D(QQuickCanvasItem);
430 if (d->renderTarget != target) {
431 if (d->contextInitialized) // target not changeable once context is active
434 d->renderTarget = target;
435 emit renderTargetChanged();
440 \qmlproperty bool QtQuick2::Canvas::renderStrategy
441 Holds the current canvas rendering strategy.
444 \li Canvas.Immediate - context will perform graphics commands immediately in the main UI thread.
445 \li Canvas.Threaded - context will defer graphics commands to a private rendering thread.
446 \li Canvas.Cooperative - context will defer graphics commands to the applications global render thread.
449 This hint is supplied along with renderTarget to the graphics context to
450 determine the method of rendering. A renderStrategy, renderTarget or a
451 combination may not be supported by a graphics context, in which case the
452 context will choose appropriate options and Canvas will signal the change
455 Configuration or runtime tests may cause the QML Scene Graph to render in
456 the GUI thread. Selecting \c Canvas.Cooperative, does not guarantee
457 rendering will occur on a thread separate from the GUI thread.
459 The default value is \c Canvas.Cooperative.
461 \sa QtQuick2::Canvas::renderTarget
464 QQuickCanvasItem::RenderStrategy QQuickCanvasItem::renderStrategy() const
466 return d_func()->renderStrategy;
469 void QQuickCanvasItem::setRenderStrategy(QQuickCanvasItem::RenderStrategy strategy)
471 Q_D(QQuickCanvasItem);
472 if (d->renderStrategy != strategy) {
473 if (d->contextInitialized) // Render strategy not changeable once context is active
476 d->renderStrategy = strategy;
477 emit renderStrategyChanged();
481 QQuickCanvasContext* QQuickCanvasItem::rawContext() const
483 return d_func()->context;
486 bool QQuickCanvasItem::isPaintConnected()
488 IS_SIGNAL_CONNECTED(this, "paint(QRect)");
491 void QQuickCanvasItem::sceneGraphInitialized()
493 Q_D(QQuickCanvasItem);
496 connect(this, SIGNAL(visibleChanged()), SLOT(checkAnimationCallbacks()));
497 QMetaObject::invokeMethod(this, "availableChanged", Qt::QueuedConnection);
499 if (!d->contextType.isNull())
500 QMetaObject::invokeMethod(this, "delayedCreate", Qt::QueuedConnection);
501 else if (isPaintConnected())
502 QMetaObject::invokeMethod(this, "requestPaint", Qt::QueuedConnection);
505 void QQuickCanvasItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
507 Q_D(QQuickCanvasItem);
509 QQuickItem::geometryChanged(newGeometry, oldGeometry);
511 QSizeF newSize = newGeometry.size();
512 if (!d->hasCanvasSize && d->canvasSize != newSize) {
513 d->canvasSize = newSize;
514 emit canvasSizeChanged();
517 if (!d->hasTileSize && d->tileSize != newSize) {
518 d->tileSize = newSize.toSize();
519 emit tileSizeChanged();
522 const QRectF rect = QRectF(QPointF(0, 0), newSize);
524 if (!d->hasCanvasWindow && d->canvasWindow != rect) {
525 d->canvasWindow = rect;
526 emit canvasWindowChanged();
533 void QQuickCanvasItem::componentComplete()
535 QQuickItem::componentComplete();
537 Q_D(QQuickCanvasItem);
538 d->baseUrl = qmlEngine(this)->contextForObject(this)->baseUrl();
541 void QQuickCanvasItem::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
543 QQuickItem::itemChange(change, value);
544 if (change != QQuickItem::ItemSceneChange)
547 Q_D(QQuickCanvasItem);
551 if (value.canvas == 0)
554 d->canvas = value.canvas;
555 if (d->canvas->openglContext() != 0) // available context == initialized
556 sceneGraphInitialized();
558 connect(d->canvas, SIGNAL(sceneGraphInitialized()), SLOT(sceneGraphInitialized()));
561 void QQuickCanvasItem::updatePolish()
563 QQuickItem::updatePolish();
565 Q_D(QQuickCanvasItem);
567 if (d->contextInitialized)
568 d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth);
570 if (d->animationCallbacks.size() > 0 && isVisible()) {
571 QMap<int, v8::Persistent<v8::Function> > animationCallbacks = d->animationCallbacks;
572 d->animationCallbacks.clear();
574 foreach (int key, animationCallbacks.keys()) {
575 v8::HandleScope handle_scope;
576 v8::Handle<v8::Object> self = QQmlEnginePrivate::getV8Engine(qmlEngine(this))->newQObject(this).As<v8::Object>();
577 v8::Handle<v8::Value> args[] = { v8::Uint32::New(QDateTime::currentDateTimeUtc().toTime_t()) };
578 v8::Persistent<v8::Function> f = animationCallbacks.value(key);
579 f->Call(self, 1, args);
584 if (d->dirtyRect.isValid()) {
585 if (d->hasTileSize && d->hasCanvasWindow)
586 emit paint(tiledRect(d->canvasWindow.intersected(d->dirtyRect.toAlignedRect()), d->tileSize));
588 emit paint(d->dirtyRect.toRect());
589 d->dirtyRect = QRectF();
593 if (d->contextInitialized) {
594 if (d->renderStrategy == QQuickCanvasItem::Cooperative)
601 QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
603 Q_D(QQuickCanvasItem);
605 if (!d->contextInitialized)
608 class CanvasTextureNode : public QSGSimpleTextureNode
611 CanvasTextureNode() : QSGSimpleTextureNode() {}
612 ~CanvasTextureNode() {delete texture();}
615 CanvasTextureNode *node = static_cast<CanvasTextureNode*>(oldNode);
617 node = new CanvasTextureNode;
620 if (d->renderStrategy == QQuickCanvasItem::Cooperative)
623 node->setTexture(d->context->texture());
624 node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
629 \qmlmethod object QtQuick2::Canvas::getContext(string contextId, any... args)
631 Returns a drawing context or null if no context available.
633 The \a contextId parameter names the required context. The Canvas element
634 will return a context that implements the required drawing mode. After the
635 first call to getContext any subsequent call to getContext with the same
636 contextId will return the same context object.
638 If the context type is not supported or the canvas has previously been
639 requested to provide a different and incompatible context type, null will
642 Canvas only supports a 2d context.
645 void QQuickCanvasItem::getContext(QQmlV8Function *args)
647 Q_D(QQuickCanvasItem);
649 if (args->Length() < 1 || !(*args)[0]->IsString()) {
650 qmlInfo(this) << "getContext should be called with a string naming the required context type";
651 args->returnValue(v8::Null());
656 qmlInfo(this) << "Unable to use getContext() at this time, please wait for available: true";
657 args->returnValue(v8::Null());
661 QString contextId = QString::fromUtf16(*v8::String::Value((*args)[0]));
663 if (d->context != 0) {
664 if (d->context->contextNames().contains(contextId, Qt::CaseInsensitive)) {
665 args->returnValue(d->context->v8value());
669 qmlInfo(this) << "Canvas already initialized with a different context type";
670 args->returnValue(v8::Null());
674 if (createContext(contextId))
675 args->returnValue(d->context->v8value());
677 args->returnValue(v8::Null());
681 \qmlmethod long QtQuick2::Canvas::requestAnimationFrame(callback)
683 This function schedules callback to be invoked before composing the QtQuick
687 void QQuickCanvasItem::requestAnimationFrame(QQmlV8Function *args)
689 if (args->Length() < 1 || !(*args)[0]->IsFunction()) {
690 qmlInfo(this) << "requestAnimationFrame should be called with an animation callback function";
691 args->returnValue(v8::Null());
695 Q_D(QQuickCanvasItem);
699 d->animationCallbacks.insert(++id, v8::Persistent<v8::Function>::New(((*args)[0]).As<v8::Function>()));
704 args->returnValue(v8::Int32::New(id));
708 \qmlmethod void QtQuick2::Canvas::cancelRequestAnimationFrmae(long handle)
710 This function will cancel the animation callback referenced by \a handle.
713 void QQuickCanvasItem::cancelRequestAnimationFrame(QQmlV8Function *args)
715 if (args->Length() < 1 || !(*args)[0]->IsInt32()) {
716 qmlInfo(this) << "cancelRequestAnimationFrame should be called with an animation callback id";
717 args->returnValue(v8::Null());
721 d_func()->animationCallbacks.remove((*args)[0]->Int32Value());
726 \qmlmethod void QtQuick2::Canvas::requestPaint()
728 Request the entire visible region be re-drawn.
730 \sa QtQuick::Canvas::markDirty
733 void QQuickCanvasItem::requestPaint()
735 markDirty(d_func()->canvasWindow);
739 \qmlmethod void QtQuick2::Canvas::markDirty(rect area)
741 Mark the given \a area as dirty, so that when this area is visible the
742 canvas renderer will redraw it. This will trigger the "onPaint" signal
745 \sa QtQuick2::Canvas::paint QtQuick2::Canvas::requestPaint
748 void QQuickCanvasItem::markDirty(const QRectF& rect)
750 Q_D(QQuickCanvasItem);
754 d->dirtyRect |= rect;
759 void QQuickCanvasItem::checkAnimationCallbacks()
761 if (d_func()->animationCallbacks.size() > 0 && isVisible())
766 \qmlmethod bool QtQuick2::Canvas::save(string filename)
768 Save the current canvas content into an image file \a filename.
769 The saved image format is automatically decided by the \a filename's
772 Note: calling this method will force painting the whole canvas, not just the
773 current canvas visible window.
775 \sa canvasWindow canvasSize toDataURL
777 bool QQuickCanvasItem::save(const QString &filename) const
779 Q_D(const QQuickCanvasItem);
780 QUrl url = d->baseUrl.resolved(QUrl::fromLocalFile(filename));
781 return toImage().save(url.toLocalFile());
784 QImage QQuickCanvasItem::loadedImage(const QUrl& url)
786 Q_D(QQuickCanvasItem);
787 QUrl fullPathUrl = d->baseUrl.resolved(url);
788 if (!d->images.contains(fullPathUrl)) {
791 QQuickPixmap* pix = d->images.value(fullPathUrl);
792 if (pix->isLoading() || pix->isError()) {
799 \qmlmethod void QtQuick2::Canvas::loadImage(url image)
800 Loads the given \c image asynchronously.
802 When the image is ready, onImageLoaded will be emitted.
803 The loaded image can be unloaded by the \a QtQuick2::Canvas::unloadImage method.
805 Note: Only loaded images can be painted on the Canvas item.
806 \sa QtQuick2::Canvas::unloadImage QtQuick2::Canvas::imageLoaded QtQuick2::Canvas::isImageLoaded
807 \sa QtQuick2::Context2D::createImageData QtQuick2::Context2D::drawImage
809 void QQuickCanvasItem::loadImage(const QUrl& url)
811 Q_D(QQuickCanvasItem);
812 QUrl fullPathUrl = d->baseUrl.resolved(url);
813 if (!d->images.contains(fullPathUrl)) {
814 QQuickPixmap* pix = new QQuickPixmap();
815 d->images.insert(fullPathUrl, pix);
817 pix->load(qmlEngine(this)
819 , QQuickPixmap::Cache | QQuickPixmap::Asynchronous);
820 if (pix->isLoading())
821 pix->connectFinished(this, SIGNAL(imageLoaded()));
825 \qmlmethod void QtQuick2::Canvas::unloadImage(url image)
826 Unloads the \c image.
828 Once an image is unloaded it cannot be painted by the canvas context
829 unless it is loaded again.
831 \sa QtQuick2::Canvas::loadImage QtQuick2::Canvas::imageLoaded QtQuick2::Canvas::isImageLoaded
832 \sa QtQuick2::Context2D::createImageData QtQuick2::Context2D::drawImage
834 void QQuickCanvasItem::unloadImage(const QUrl& url)
836 Q_D(QQuickCanvasItem);
837 QUrl removeThis = d->baseUrl.resolved(url);
838 if (d->images.contains(removeThis)) {
839 delete d->images.value(removeThis);
840 d->images.remove(removeThis);
845 \qmlmethod void QtQuick2::Canvas::isImageError(url image)
846 Returns true if the \a image failed to load.
848 \sa QtQuick2::Canvas::loadImage
850 bool QQuickCanvasItem::isImageError(const QUrl& url) const
852 Q_D(const QQuickCanvasItem);
853 QUrl fullPathUrl = d->baseUrl.resolved(url);
854 return d->images.contains(fullPathUrl)
855 && d->images.value(fullPathUrl)->isError();
859 \qmlmethod void QtQuick2::Canvas::isImageLoading(url image)
860 Returns true if the \a image is currently loading.
862 \sa QtQuick2::Canvas::loadImage
864 bool QQuickCanvasItem::isImageLoading(const QUrl& url) const
866 Q_D(const QQuickCanvasItem);
867 QUrl fullPathUrl = d->baseUrl.resolved(url);
868 return d->images.contains(fullPathUrl)
869 && d->images.value(fullPathUrl)->isLoading();
872 \qmlmethod void QtQuick2::Canvas::isImageLoaded(url image)
873 Returns true if the \a image is sucessfully loaded and ready to use.
875 \sa QtQuick2::Canvas::loadImage
877 bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const
879 Q_D(const QQuickCanvasItem);
880 QUrl fullPathUrl = d->baseUrl.resolved(url);
881 return d->images.contains(fullPathUrl)
882 && d->images.value(fullPathUrl)->isReady();
885 QImage QQuickCanvasItem::toImage(const QRectF& rect) const
887 Q_D(const QQuickCanvasItem);
888 if (d->contextInitialized) {
890 return d->context->toImage(canvasWindow());
892 return d->context->toImage(rect);
899 \qmlmethod string QtQuick2::Canvas::toDataURL(string mimeType)
901 Returns a data URL for the image in the canvas.
903 The default \a mimeType is "image/png".
905 \sa QtQuick2::Canvas::save
907 QString QQuickCanvasItem::toDataURL(const QString& mimeType) const
909 QImage image = toImage();
911 if (!image.isNull()) {
914 buffer.open(QIODevice::WriteOnly);
915 QString mime = mimeType.toLower();
917 if (mime == QLatin1Literal("image/png")) {
918 type = QLatin1Literal("PNG");
919 } else if (mime == QLatin1Literal("image/bmp"))
920 type = QLatin1Literal("BMP");
921 else if (mime == QLatin1Literal("image/jpeg"))
922 type = QLatin1Literal("JPEG");
923 else if (mime == QLatin1Literal("image/x-portable-pixmap"))
924 type = QLatin1Literal("PPM");
925 else if (mime == QLatin1Literal("image/tiff"))
926 type = QLatin1Literal("TIFF");
927 else if (mime == QLatin1Literal("image/xpm"))
928 type = QLatin1Literal("XPM");
930 return QLatin1Literal("data:,");
932 image.save(&buffer, type.toAscii());
934 QString dataUrl = QLatin1Literal("data:%1;base64,%2");
935 return dataUrl.arg(mime).arg(QLatin1String(ba.toBase64().constData()));
937 return QLatin1Literal("data:,");
940 void QQuickCanvasItem::delayedCreate()
942 Q_D(QQuickCanvasItem);
944 if (!d->contextInitialized && !d->contextType.isNull())
945 createContext(d->contextType);
950 bool QQuickCanvasItem::createContext(const QString &contextType)
952 Q_D(QQuickCanvasItem);
954 if (contextType == QLatin1String("2d")) {
955 if (d->contextType.compare(QLatin1String("2d"), Qt::CaseInsensitive) != 0) {
956 d->contextType = QLatin1String("2d");
957 emit contextTypeChanged(); // XXX: can't be in setContextType()
959 initializeContext(new QQuickContext2D(this));
966 void QQuickCanvasItem::initializeContext(QQuickCanvasContext *context, const QVariantMap &args)
968 Q_D(QQuickCanvasItem);
970 d->context = context;
971 d->context->init(this, args);
972 d->context->setV8Engine(QQmlEnginePrivate::getV8Engine(qmlEngine(this)));
973 d->contextInitialized = true;
974 connect(d->context, SIGNAL(textureChanged()), SLOT(update()));
975 connect(d->context, SIGNAL(textureChanged()), SIGNAL(painted()));
976 emit contextChanged();
979 QRect QQuickCanvasItem::tiledRect(const QRectF &window, const QSize &tileSize)
981 if (window.isEmpty())
984 const int tw = tileSize.width();
985 const int th = tileSize.height();
986 const int h1 = window.left() / tw;
987 const int v1 = window.top() / th;
989 const int htiles = ((window.right() - h1 * tw) + tw - 1)/tw;
990 const int vtiles = ((window.bottom() - v1 * th) + th - 1)/th;
992 return QRect(h1 * tw, v1 * th, htiles * tw, vtiles * th);
996 \qmlsignal QtQuick2::Canvas::onPaint(rect region)
998 This handler is called to render the \a region. If a context is active it
999 can be referenced from the context property.
1001 This signal can be triggered by QtQuick2::Canvas::markdirty,
1002 QtQuick2::Canvas::requestPaint or by changing the current canvas window.
1006 \qmlsignal QtQuick2::Canvas::onPainted()
1008 This handler is called after all context painting commands are executed and
1009 the Canvas has been rendered.