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 enumeration 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) {
432 qmlInfo(this) << "Canvas:renderTarget not changeble once context is active.";
436 d->renderTarget = target;
437 emit renderTargetChanged();
442 \qmlproperty enumeration QtQuick2::Canvas::renderStrategy
443 Holds the current canvas rendering strategy.
446 \li Canvas.Immediate - context will perform graphics commands immediately in the main UI thread.
447 \li Canvas.Threaded - context will defer graphics commands to a private rendering thread.
448 \li Canvas.Cooperative - context will defer graphics commands to the applications global render thread.
451 This hint is supplied along with renderTarget to the graphics context to
452 determine the method of rendering. A renderStrategy, renderTarget or a
453 combination may not be supported by a graphics context, in which case the
454 context will choose appropriate options and Canvas will signal the change
457 Configuration or runtime tests may cause the QML Scene Graph to render in
458 the GUI thread. Selecting \c Canvas.Cooperative, does not guarantee
459 rendering will occur on a thread separate from the GUI thread.
461 The default value is \c Canvas.Cooperative.
463 \sa QtQuick2::Canvas::renderTarget
466 QQuickCanvasItem::RenderStrategy QQuickCanvasItem::renderStrategy() const
468 return d_func()->renderStrategy;
471 void QQuickCanvasItem::setRenderStrategy(QQuickCanvasItem::RenderStrategy strategy)
473 Q_D(QQuickCanvasItem);
474 if (d->renderStrategy != strategy) {
475 if (d->contextInitialized) {
476 qmlInfo(this) << "Canvas:renderStrategy not changeable once context is active.";
480 d->renderStrategy = strategy;
481 emit renderStrategyChanged();
485 QQuickCanvasContext* QQuickCanvasItem::rawContext() const
487 return d_func()->context;
490 bool QQuickCanvasItem::isPaintConnected()
492 IS_SIGNAL_CONNECTED(this, "paint(QRect)");
495 void QQuickCanvasItem::sceneGraphInitialized()
497 Q_D(QQuickCanvasItem);
500 connect(this, SIGNAL(visibleChanged()), SLOT(checkAnimationCallbacks()));
501 QMetaObject::invokeMethod(this, "availableChanged", Qt::QueuedConnection);
503 if (!d->contextType.isNull())
504 QMetaObject::invokeMethod(this, "delayedCreate", Qt::QueuedConnection);
505 else if (isPaintConnected())
506 QMetaObject::invokeMethod(this, "requestPaint", Qt::QueuedConnection);
509 void QQuickCanvasItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
511 Q_D(QQuickCanvasItem);
513 QQuickItem::geometryChanged(newGeometry, oldGeometry);
515 QSizeF newSize = newGeometry.size();
516 if (!d->hasCanvasSize && d->canvasSize != newSize) {
517 d->canvasSize = newSize;
518 emit canvasSizeChanged();
521 if (!d->hasTileSize && d->tileSize != newSize) {
522 d->tileSize = newSize.toSize();
523 emit tileSizeChanged();
526 const QRectF rect = QRectF(QPointF(0, 0), newSize);
528 if (!d->hasCanvasWindow && d->canvasWindow != rect) {
529 d->canvasWindow = rect;
530 emit canvasWindowChanged();
537 void QQuickCanvasItem::componentComplete()
539 QQuickItem::componentComplete();
541 Q_D(QQuickCanvasItem);
542 d->baseUrl = qmlEngine(this)->contextForObject(this)->baseUrl();
545 void QQuickCanvasItem::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
547 QQuickItem::itemChange(change, value);
548 if (change != QQuickItem::ItemSceneChange)
551 Q_D(QQuickCanvasItem);
555 if (value.canvas == 0)
558 d->canvas = value.canvas;
559 if (d->canvas->openglContext() != 0) // available context == initialized
560 sceneGraphInitialized();
562 connect(d->canvas, SIGNAL(sceneGraphInitialized()), SLOT(sceneGraphInitialized()));
565 void QQuickCanvasItem::updatePolish()
567 QQuickItem::updatePolish();
569 Q_D(QQuickCanvasItem);
571 if (d->contextInitialized)
572 d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth);
574 if (d->animationCallbacks.size() > 0 && isVisible()) {
575 QMap<int, v8::Persistent<v8::Function> > animationCallbacks = d->animationCallbacks;
576 d->animationCallbacks.clear();
578 foreach (int key, animationCallbacks.keys()) {
579 v8::HandleScope handle_scope;
580 v8::Handle<v8::Object> self = QQmlEnginePrivate::getV8Engine(qmlEngine(this))->newQObject(this).As<v8::Object>();
581 v8::Handle<v8::Value> args[] = { v8::Uint32::New(QDateTime::currentDateTimeUtc().toTime_t()) };
582 v8::Persistent<v8::Function> f = animationCallbacks.value(key);
583 f->Call(self, 1, args);
588 if (d->dirtyRect.isValid()) {
589 if (d->hasTileSize && d->hasCanvasWindow)
590 emit paint(tiledRect(d->canvasWindow.intersected(d->dirtyRect.toAlignedRect()), d->tileSize));
592 emit paint(d->dirtyRect.toRect());
593 d->dirtyRect = QRectF();
597 if (d->contextInitialized) {
598 if (d->renderStrategy == QQuickCanvasItem::Cooperative)
605 QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
607 Q_D(QQuickCanvasItem);
609 if (!d->contextInitialized)
612 class CanvasTextureNode : public QSGSimpleTextureNode
615 CanvasTextureNode() : QSGSimpleTextureNode() {}
616 ~CanvasTextureNode() {delete texture();}
619 CanvasTextureNode *node = static_cast<CanvasTextureNode*>(oldNode);
621 node = new CanvasTextureNode;
624 if (d->renderStrategy == QQuickCanvasItem::Cooperative)
627 node->setTexture(d->context->texture());
628 node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
633 \qmlmethod object QtQuick2::Canvas::getContext(string contextId, any... args)
635 Returns a drawing context or null if no context available.
637 The \a contextId parameter names the required context. The Canvas element
638 will return a context that implements the required drawing mode. After the
639 first call to getContext any subsequent call to getContext with the same
640 contextId will return the same context object.
642 If the context type is not supported or the canvas has previously been
643 requested to provide a different and incompatible context type, null will
646 Canvas only supports a 2d context.
649 void QQuickCanvasItem::getContext(QQmlV8Function *args)
651 Q_D(QQuickCanvasItem);
653 if (args->Length() < 1 || !(*args)[0]->IsString()) {
654 qmlInfo(this) << "getContext should be called with a string naming the required context type";
655 args->returnValue(v8::Null());
660 qmlInfo(this) << "Unable to use getContext() at this time, please wait for available: true";
661 args->returnValue(v8::Null());
665 QString contextId = QString::fromUtf16(*v8::String::Value((*args)[0]));
667 if (d->context != 0) {
668 if (d->context->contextNames().contains(contextId, Qt::CaseInsensitive)) {
669 args->returnValue(d->context->v8value());
673 qmlInfo(this) << "Canvas already initialized with a different context type";
674 args->returnValue(v8::Null());
678 if (createContext(contextId))
679 args->returnValue(d->context->v8value());
681 args->returnValue(v8::Null());
685 \qmlmethod long QtQuick2::Canvas::requestAnimationFrame(callback)
687 This function schedules callback to be invoked before composing the QtQuick
691 void QQuickCanvasItem::requestAnimationFrame(QQmlV8Function *args)
693 if (args->Length() < 1 || !(*args)[0]->IsFunction()) {
694 qmlInfo(this) << "requestAnimationFrame should be called with an animation callback function";
695 args->returnValue(v8::Null());
699 Q_D(QQuickCanvasItem);
703 d->animationCallbacks.insert(++id, v8::Persistent<v8::Function>::New(((*args)[0]).As<v8::Function>()));
708 args->returnValue(v8::Int32::New(id));
712 \qmlmethod void QtQuick2::Canvas::cancelRequestAnimationFrmae(long handle)
714 This function will cancel the animation callback referenced by \a handle.
717 void QQuickCanvasItem::cancelRequestAnimationFrame(QQmlV8Function *args)
719 if (args->Length() < 1 || !(*args)[0]->IsInt32()) {
720 qmlInfo(this) << "cancelRequestAnimationFrame should be called with an animation callback id";
721 args->returnValue(v8::Null());
725 d_func()->animationCallbacks.remove((*args)[0]->Int32Value());
730 \qmlmethod void QtQuick2::Canvas::requestPaint()
732 Request the entire visible region be re-drawn.
734 \sa QtQuick::Canvas::markDirty
737 void QQuickCanvasItem::requestPaint()
739 markDirty(d_func()->canvasWindow);
743 \qmlmethod void QtQuick2::Canvas::markDirty(rect area)
745 Mark the given \a area as dirty, so that when this area is visible the
746 canvas renderer will redraw it. This will trigger the "onPaint" signal
749 \sa QtQuick2::Canvas::paint, QtQuick2::Canvas::requestPaint
752 void QQuickCanvasItem::markDirty(const QRectF& rect)
754 Q_D(QQuickCanvasItem);
758 d->dirtyRect |= rect;
763 void QQuickCanvasItem::checkAnimationCallbacks()
765 if (d_func()->animationCallbacks.size() > 0 && isVisible())
770 \qmlmethod bool QtQuick2::Canvas::save(string filename)
772 Save the current canvas content into an image file \a filename.
773 The saved image format is automatically decided by the \a filename's
776 Note: calling this method will force painting the whole canvas, not just the
777 current canvas visible window.
779 \sa canvasWindow, canvasSize, toDataURL
781 bool QQuickCanvasItem::save(const QString &filename) const
783 Q_D(const QQuickCanvasItem);
784 QUrl url = d->baseUrl.resolved(QUrl::fromLocalFile(filename));
785 return toImage().save(url.toLocalFile());
788 QImage QQuickCanvasItem::loadedImage(const QUrl& url)
790 Q_D(QQuickCanvasItem);
791 QUrl fullPathUrl = d->baseUrl.resolved(url);
792 if (!d->images.contains(fullPathUrl)) {
795 QQuickPixmap* pix = d->images.value(fullPathUrl);
796 if (pix->isLoading() || pix->isError()) {
803 \qmlmethod void QtQuick2::Canvas::loadImage(url image)
804 Loads the given \c image asynchronously.
806 When the image is ready, onImageLoaded will be emitted.
807 The loaded image can be unloaded by the \a QtQuick2::Canvas::unloadImage method.
809 Note: Only loaded images can be painted on the Canvas item.
810 \sa QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::imageLoaded, QtQuick2::Canvas::isImageLoaded,
811 QtQuick2::Context2D::createImageData, QtQuick2::Context2D::drawImage
813 void QQuickCanvasItem::loadImage(const QUrl& url)
815 Q_D(QQuickCanvasItem);
816 QUrl fullPathUrl = d->baseUrl.resolved(url);
817 if (!d->images.contains(fullPathUrl)) {
818 QQuickPixmap* pix = new QQuickPixmap();
819 d->images.insert(fullPathUrl, pix);
821 pix->load(qmlEngine(this)
823 , QQuickPixmap::Cache | QQuickPixmap::Asynchronous);
824 if (pix->isLoading())
825 pix->connectFinished(this, SIGNAL(imageLoaded()));
829 \qmlmethod void QtQuick2::Canvas::unloadImage(url image)
830 Unloads the \c image.
832 Once an image is unloaded it cannot be painted by the canvas context
833 unless it is loaded again.
835 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::imageLoaded, QtQuick2::Canvas::isImageLoaded,
836 QtQuick2::Context2D::createImageData, QtQuick2::Context2D::drawImage
838 void QQuickCanvasItem::unloadImage(const QUrl& url)
840 Q_D(QQuickCanvasItem);
841 QUrl removeThis = d->baseUrl.resolved(url);
842 if (d->images.contains(removeThis)) {
843 delete d->images.value(removeThis);
844 d->images.remove(removeThis);
849 \qmlmethod void QtQuick2::Canvas::isImageError(url image)
850 Returns true if the \a image failed to load.
852 \sa QtQuick2::Canvas::loadImage
854 bool QQuickCanvasItem::isImageError(const QUrl& url) const
856 Q_D(const QQuickCanvasItem);
857 QUrl fullPathUrl = d->baseUrl.resolved(url);
858 return d->images.contains(fullPathUrl)
859 && d->images.value(fullPathUrl)->isError();
863 \qmlmethod void QtQuick2::Canvas::isImageLoading(url image)
864 Returns true if the \a image is currently loading.
866 \sa QtQuick2::Canvas::loadImage
868 bool QQuickCanvasItem::isImageLoading(const QUrl& url) const
870 Q_D(const QQuickCanvasItem);
871 QUrl fullPathUrl = d->baseUrl.resolved(url);
872 return d->images.contains(fullPathUrl)
873 && d->images.value(fullPathUrl)->isLoading();
876 \qmlmethod void QtQuick2::Canvas::isImageLoaded(url image)
877 Returns true if the \a image is sucessfully loaded and ready to use.
879 \sa QtQuick2::Canvas::loadImage
881 bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const
883 Q_D(const QQuickCanvasItem);
884 QUrl fullPathUrl = d->baseUrl.resolved(url);
885 return d->images.contains(fullPathUrl)
886 && d->images.value(fullPathUrl)->isReady();
889 QImage QQuickCanvasItem::toImage(const QRectF& rect) const
891 Q_D(const QQuickCanvasItem);
892 if (d->contextInitialized) {
894 return d->context->toImage(canvasWindow());
896 return d->context->toImage(rect);
903 \qmlmethod string QtQuick2::Canvas::toDataURL(string mimeType)
905 Returns a data URL for the image in the canvas.
907 The default \a mimeType is "image/png".
909 \sa QtQuick2::Canvas::save
911 QString QQuickCanvasItem::toDataURL(const QString& mimeType) const
913 QImage image = toImage();
915 if (!image.isNull()) {
918 buffer.open(QIODevice::WriteOnly);
919 QString mime = mimeType.toLower();
921 if (mime == QLatin1String("image/png")) {
922 type = QStringLiteral("PNG");
923 } else if (mime == QLatin1String("image/bmp"))
924 type = QStringLiteral("BMP");
925 else if (mime == QLatin1String("image/jpeg"))
926 type = QStringLiteral("JPEG");
927 else if (mime == QLatin1String("image/x-portable-pixmap"))
928 type = QStringLiteral("PPM");
929 else if (mime == QLatin1String("image/tiff"))
930 type = QStringLiteral("TIFF");
931 else if (mime == QLatin1String("image/xpm"))
932 type = QStringLiteral("XPM");
934 return QStringLiteral("data:,");
936 image.save(&buffer, type.toLatin1());
938 QString dataUrl = QStringLiteral("data:%1;base64,%2");
939 return dataUrl.arg(mime).arg(QLatin1String(ba.toBase64().constData()));
941 return QStringLiteral("data:,");
944 void QQuickCanvasItem::delayedCreate()
946 Q_D(QQuickCanvasItem);
948 if (!d->contextInitialized && !d->contextType.isNull())
949 createContext(d->contextType);
954 bool QQuickCanvasItem::createContext(const QString &contextType)
956 Q_D(QQuickCanvasItem);
958 if (contextType == QLatin1String("2d")) {
959 if (d->contextType.compare(QLatin1String("2d"), Qt::CaseInsensitive) != 0) {
960 d->contextType = QLatin1String("2d");
961 emit contextTypeChanged(); // XXX: can't be in setContextType()
963 initializeContext(new QQuickContext2D(this));
970 void QQuickCanvasItem::initializeContext(QQuickCanvasContext *context, const QVariantMap &args)
972 Q_D(QQuickCanvasItem);
974 d->context = context;
975 d->context->init(this, args);
976 d->context->setV8Engine(QQmlEnginePrivate::getV8Engine(qmlEngine(this)));
977 d->contextInitialized = true;
978 connect(d->context, SIGNAL(textureChanged()), SLOT(update()));
979 connect(d->context, SIGNAL(textureChanged()), SIGNAL(painted()));
980 emit contextChanged();
983 QRect QQuickCanvasItem::tiledRect(const QRectF &window, const QSize &tileSize)
985 if (window.isEmpty())
988 const int tw = tileSize.width();
989 const int th = tileSize.height();
990 const int h1 = window.left() / tw;
991 const int v1 = window.top() / th;
993 const int htiles = ((window.right() - h1 * tw) + tw - 1)/tw;
994 const int vtiles = ((window.bottom() - v1 * th) + th - 1)/th;
996 return QRect(h1 * tw, v1 * th, htiles * tw, vtiles * th);
1000 \qmlsignal QtQuick2::Canvas::onPaint(rect region)
1002 This handler is called to render the \a region. If a context is active it
1003 can be referenced from the context property.
1005 This signal can be triggered by QtQuick2::Canvas::markdirty,
1006 QtQuick2::Canvas::requestPaint or by changing the current canvas window.
1010 \qmlsignal QtQuick2::Canvas::onPainted()
1012 This handler is called after all context painting commands are executed and
1013 the Canvas has been rendered.