Rename Qt Quick-specific classes to QQuick*
[profile/ivi/qtdeclarative.git] / src / declarative / items / context2d / qquickcanvasitem.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 <private/qsgadaptationlayer_p.h>
43 #include "qquickcanvasitem_p.h"
44 #include <private/qquickitem_p.h>
45 #include "qquickcontext2d_p.h"
46 #include "qquickcontext2dnode_p.h"
47 #include "qquickcontext2dtexture_p.h"
48 #include <private/qdeclarativepixmapcache_p.h>
49
50 #include <qdeclarativeinfo.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <QtCore/QBuffer>
53
54 QT_BEGIN_NAMESPACE
55
56 class QQuickCanvasItemPrivate : public QQuickItemPrivate
57 {
58 public:
59     QQuickCanvasItemPrivate();
60     ~QQuickCanvasItemPrivate();
61     QQuickContext2D* context;
62     QQuickContext2DTexture* texture;
63     QSizeF canvasSize;
64     QSize tileSize;
65     QRectF canvasWindow;
66     QRectF dirtyRect;
67     uint renderInThread : 1;
68     uint hasCanvasSize :1;
69     uint hasTileSize :1;
70     uint hasCanvasWindow :1;
71     uint componentCompleted :1;
72     QQuickCanvasItem::RenderTarget renderTarget;
73     QHash<QUrl, QDeclarativePixmap*> images;
74     QUrl baseUrl;
75 };
76
77 QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
78     : QQuickItemPrivate()
79     , context(0)
80     , texture(0)
81     , canvasSize(1, 1)
82     , tileSize(1, 1)
83     , renderInThread(false)
84     , hasCanvasSize(false)
85     , hasTileSize(false)
86     , hasCanvasWindow(false)
87     , componentCompleted(false)
88     , renderTarget(QQuickCanvasItem::FramebufferObject)
89 {
90 }
91
92 QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
93 {
94     qDeleteAll(images);
95 }
96
97 /*!
98     \qmlclass Canvas QQuickCanvasItem
99     \inqmlmodule QtQuick 2
100     \since QtQuick 2.0
101     \brief The Canvas item provides HTML5 like canvas element which enables you to
102     draw within the item area by using Javascript.
103     \inherits Item
104     \ingroup qml-basic-visual-elements
105
106     With the Canvas item, users can draw straight and curved lines, simple and
107     complex shapes, graphs, and referenced graphic images. can also add texts, colors,
108     shadows, gradients, and patterns, and do low level pixel operations, etc. The Canvas item
109     also enables you to save or export the canvas as a image file or serialize the image data
110     to data url string.
111
112     To define a drawing area in the Canvas item, just set the \c width and \c height properties.
113     For example, the following code creates a Canvas item which has a drawing area with a height of 100
114     pixels and width of 200 pixels:
115     \qml
116     import QtQuick 2.0
117     Canvas {
118       id:mycanvas
119       width:100
120       height:200
121     }
122     \endqml
123
124     Currently the Canvas item only supports the two-dimensional rendering context.
125
126     \section1 Thread Rendering and Render Target
127     The Canvas item supports two render targets:Canvas.Image and Canvas.FramebufferObject.
128     The Canvas.Image render target is a \a QImage object which is actually a block of system
129     memory. This render target support background thread rendering. So if some complex or long
130     running painting need to be done, the Canvas.Image with thread rendering mode should be
131     chosen to avoid blocking the UI. Otherwise the Canvas.FramebufferObject render target should
132     be chosen as it could be much faster with good OpenGL hardware accelaration than rendering into
133     system memory, especially when the CPU is already very busy.
134
135     The default render target is Canvas.Image and the default renderInThread property is
136     false.
137
138     \section1 Tiled Canvas
139     The Canvas item also supports tiled rendering mode by setting the proper canvasSize, tileSize
140     and the canvasWindow properties.
141
142     With tiled canvas, a virtually very large canvas can be provided by a relatively small canvas
143     window. The actual memory consumption only relates to the canvas window size. So the canvas size
144     can be chosen freely as needed. The painting code then doesn't need to worry about the coordinate
145     system and complex matrix transformations at all.
146
147     As a side effect, by setting a good tile size, the tiles overlapped with the canvas window could be
148     cached and don't need to redraw, which can improve the performance significantly in some situations.
149
150     \section1 Pixel Operations
151     The Canvas item support all HTML5 2d context pixel operations. In order to get better
152     pixel reading/writing performance, the Canvas.Image render target should be chosen. As
153     for Canvas.FramebufferObject render target, the pixel data need to be exchanged between
154     the system memory and the graphic card, which can't be benefit from the hardware acceleration
155     at all. And the OpenGL rendering may synchronise with the V-Sync signal to avoid the
156     {en.wikipedia.org/wiki/Screen_tearing}{screen tearing} which makes the pixel operations
157     even slower with the Canvas.FrambufferObject render target.
158
159     \section1 Tips for Porting Existing HTML5 Canvas applications
160
161     Although the Canvas item is provided as a HTML5 like API, and
162     the canvas context API is as compatible with HTML5 2d context standard
163     as possible, the working HTML5 canvas applications are still need to
164     be modified to run in the Canvas item:
165     \list
166     \o Removes and replaces all DOM API calls with QML property bindings or Canvas item methods.
167     \o Removes and replaces all HTML envent handlers with the \a MouseArea item.
168     \o Changes the setInterval/setTimeout function calls with the \a Timer item.
169     \o Puts the actual painting code into the \a QtQuick2::Canvas::onPaint handler and triggers the
170        painting by calling the Canvas's \c markDirty or \c requestPaint methods.
171     \o For drawing images, loads them by calling the Canvas's loadImage method and then request to paint
172        them in the onImageLoaded handler.
173     \endlist
174
175     \sa QtQuick2::Context2D
176 */
177
178 QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
179     : QQuickItem(*(new QQuickCanvasItemPrivate), parent)
180 {
181     setFlag(ItemHasContents);
182 }
183
184 QQuickCanvasItem::~QQuickCanvasItem()
185 {
186     Q_D(QQuickCanvasItem);
187     delete d->context;
188 }
189
190 /*!
191     \qmlproperty size QtQuick2::Canvas::canvasSize
192      Holds the logical canvas size that the context paints on.
193
194      By default, the canvas size is the same size as the current canvas item size.
195      By setting the canvas size, tile size and canvas window, the Canvas
196      item can act as a virtual large canvas with many seperately rendered tile rectangle
197      areas. Only those tiles within the current canvas window would be painted by
198      the Canvas render engine.
199     \sa QtQuick2::Canvas::tileSize QtQuick2::Canvas::canvasWindow
200 */
201 QSizeF QQuickCanvasItem::canvasSize() const
202 {
203     Q_D(const QQuickCanvasItem);
204     return d->canvasSize;
205 }
206
207 void QQuickCanvasItem::setCanvasSize(const QSizeF & size)
208 {
209     Q_D(QQuickCanvasItem);
210     if (d->canvasSize != size) {
211         d->hasCanvasSize = true;
212         d->canvasSize = size;
213         emit canvasSizeChanged();
214         polish();
215         update();
216     }
217 }
218
219 /*!
220     \qmlproperty size QtQuick2::Canvas::tileSize
221      Holds the canvas rendering tile size.
222
223      When the Canvas item in tiled mode by setting the canvas size, tile size and
224      the canvas window. The canvas render can improve the rendering performance
225      by rendering and caching tiles instead of rendering the whole canvas everytime.
226
227      Additionally, the canvas size could be infinitely large without allocating more
228      memories because only those tiles within the current visible region
229      are actually rendered.
230
231      By default, the tile size is the same with the canvas size.
232      \sa QtQuick2::Canvas::canvaasSize QtQuick2::Canvas::canvasWindow
233 */
234 QSize QQuickCanvasItem::tileSize() const
235 {
236     Q_D(const QQuickCanvasItem);
237     return d->tileSize;
238 }
239
240 void QQuickCanvasItem::setTileSize(const QSize & size)
241 {
242     Q_D(QQuickCanvasItem);
243     if (d->tileSize != size) {
244         d->hasTileSize = true;
245         d->tileSize = size;
246
247         emit tileSizeChanged();
248         polish();
249         update();
250     }
251 }
252
253 /*!
254     \qmlproperty rect QtQuick2::Canvas::canvasWindow
255      Holds the current canvas visible window.
256
257      By default, the canvas window size is the same as the Canvas item
258      size with the topleft point as (0, 0).
259
260      If the canvas size is different with the Canvas item size, the Canvas
261      item can display different visible areas by changing the canvas window's size
262      and/or position.
263     \sa QtQuick2::Canvas::canvasSize QtQuick2::Canvas::tileSize
264 */
265 QRectF QQuickCanvasItem::canvasWindow() const
266 {
267     Q_D(const QQuickCanvasItem);
268     return d->canvasWindow;
269 }
270
271 void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
272 {
273     Q_D(QQuickCanvasItem);
274     if (d->canvasWindow != rect) {
275         d->canvasWindow = rect;
276
277         d->hasCanvasWindow = true;
278         emit canvasWindowChanged();
279         polish();
280         update();
281     }
282 }
283
284
285 QQuickContext2D* QQuickCanvasItem::context() const
286 {
287     Q_D(const QQuickCanvasItem);
288     return d->context;
289 }
290 /*!
291     \qmlproperty bool QtQuick2::Canvas::renderInThread
292      Holds the current canvas rendering mode.
293
294      By setting the renderInThread to true, complex and long
295      running painting can be rendered in a dedicated background
296      rendering thread to avoid blocking the main GUI.
297
298      Note: Different renderTarget may or may not support the
299      background rendering thread, if not, the renderInThread
300      property will be ignored.
301
302      The default value is false.
303     \sa QtQuick2::Canvas::renderTarget
304 */
305 bool QQuickCanvasItem::renderInThread() const
306 {
307     Q_D(const QQuickCanvasItem);
308     return d->renderInThread;
309 }
310 /*!
311     \qmlproperty bool QtQuick2::Canvas::renderTarget
312      Holds the current canvas render target.
313
314      \list
315      \o Canvas.Image  - render to an in memory image buffer, the render
316                         target supports background rendering.
317      \o Canvas.FramebufferObject - render to an OpenGL frame buffer,
318                                    this render target will ignore the
319                                    renderInThread property. The actual
320                                    rendering happens in the main QML rendering
321                                    process, which may be in a seperate render thread
322                                    or in the main GUI thread depends on the platforms.
323      \endlist
324
325      The default render target is \c Canvas.Image.
326     \sa QtQuick2::Canvas::renderInThread
327 */
328 QQuickCanvasItem::RenderTarget QQuickCanvasItem::renderTarget() const
329 {
330     Q_D(const QQuickCanvasItem);
331     return d->renderTarget;
332 }
333
334 void QQuickCanvasItem::setRenderTarget(RenderTarget target)
335 {
336     Q_D(QQuickCanvasItem);
337     if (d->renderTarget != target) {
338         d->renderTarget = target;
339
340         if (d->componentCompleted)
341             createTexture();
342         emit renderTargetChanged();
343     }
344 }
345
346 void QQuickCanvasItem::_doPainting(const QRectF& region)
347 {
348     Q_D(QQuickCanvasItem);
349     emit paint(QDeclarativeV8Handle::fromHandle(d->context->v8value())
350              , QQuickContext2DTexture::tiledRect(region, d->tileSize));
351     if (d->texture)
352         d->texture->wake();
353 }
354
355 /*!
356     \qmlproperty bool QtQuick2::Canvas::renderInThread
357      Holds the current canvas rendering mode.
358
359      When this property is true, all canvas painting commands
360      are rendered in a background rendering thread, otherwise
361      the rendering happens in the main GUI thread.
362
363      The default renderInThread value is false.
364 */
365 void QQuickCanvasItem::setRenderInThread(bool renderInThread)
366 {
367     Q_D(QQuickCanvasItem);
368     if (d->renderInThread != renderInThread) {
369         d->renderInThread = renderInThread;
370
371         if (d->componentCompleted)
372             createTexture();
373
374         if (d->renderInThread)
375             connect(this, SIGNAL(painted()), SLOT(update()));
376         else
377             disconnect(this, SIGNAL(painted()), this, SLOT(update()));
378         emit renderInThreadChanged();
379         polish();
380         update();
381     }
382 }
383
384 void QQuickCanvasItem::geometryChanged(const QRectF &newGeometry,
385                              const QRectF &oldGeometry)
386 {
387     Q_D(QQuickCanvasItem);
388     QQuickItem::geometryChanged(newGeometry, oldGeometry);
389
390     const qreal w = newGeometry.width();
391     const qreal h = newGeometry.height();
392
393     if (!d->hasCanvasSize) {
394         d->canvasSize = QSizeF(w, h);
395         emit canvasSizeChanged();
396     }
397
398     if (!d->hasTileSize) {
399         d->tileSize = d->canvasSize.toSize();
400         emit tileSizeChanged();
401     }
402
403     if (!d->hasCanvasWindow) {
404         d->canvasWindow = newGeometry;
405         emit canvasWindowChanged();
406     }
407
408     polish();
409     update();
410 }
411
412 void QQuickCanvasItem::componentComplete()
413 {
414     Q_D(QQuickCanvasItem);
415     QQuickItem::componentComplete();
416
417     if (!d->context)
418         createContext();
419     createTexture();
420
421     d->baseUrl = qmlEngine(this)->contextForObject(this)->baseUrl();
422     requestPaint();
423     updatePolish(); //force update the canvas sizes to texture for the first time
424     update();
425     d->componentCompleted = true;
426 }
427
428 void QQuickCanvasItem::updatePolish()
429 {
430     Q_D(QQuickCanvasItem);
431     QQuickItem::updatePolish();
432     if (d->texture) {
433         if (!d->renderInThread && d->dirtyRect.isValid())
434             _doPainting(d->dirtyRect);
435
436         d->texture->canvasChanged(d->canvasSize.toSize()
437                                 , d->tileSize
438                                 , d->canvasWindow.toAlignedRect()
439                                 , d->dirtyRect.toAlignedRect()
440                                 , d->smooth);
441         d->dirtyRect = QRectF();
442     }
443 }
444
445 QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
446 {
447     Q_D(QQuickCanvasItem);
448     QQuickContext2DNode *node = static_cast<QQuickContext2DNode *>(oldNode);
449     if (!node)
450         node = new QQuickContext2DNode(this);
451
452     node->setTexture(d->texture);
453     node->setSize(d->canvasWindow.size());
454     node->update();
455     return node;
456 }
457
458 void QQuickCanvasItem::createTexture()
459 {
460     Q_D(QQuickCanvasItem);
461
462     if (!d->texture
463       || d->texture->threadRendering() != d->renderInThread
464       || d->texture->renderTarget() != d->renderTarget) {
465         if (d->texture) {
466             d->texture->deleteLater();
467             d->texture = 0;
468         }
469
470         if (d->renderTarget == QQuickCanvasItem::Image) {
471             d->texture = new QQuickContext2DImageTexture(d->renderInThread);
472         } else if (d->renderTarget == QQuickCanvasItem::FramebufferObject) {
473             d->texture = new QQuickContext2DFBOTexture();
474         }
475
476         if (d->renderInThread && !d->texture->supportThreadRendering()) {
477             qWarning("Canvas: render target does not support thread rendering, force to non-thread rendering mode.");
478             d->renderInThread = false;
479             emit renderInThreadChanged();
480         }
481
482         if (d->renderInThread)
483             connect(d->texture, SIGNAL(textureChanged()), this, SLOT(update()));
484
485         d->texture->setItem(this);
486     }
487 }
488
489 void QQuickCanvasItem::createContext()
490 {
491     Q_D(QQuickCanvasItem);
492
493     delete d->context;
494
495     d->context = new QQuickContext2D(this);
496
497     QV8Engine *e = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this));
498     d->context->setV8Engine(e);
499 }
500
501 /*!
502   \qmlmethod object QtQuick2::Canvas::getContext(string contextId)
503
504   Currently, the canvas item only support the 2D context. If the \a contextId
505   parameter isn't provided or is "2d", then the QtQuick2::Context2D object is
506   returned, otherwise returns an invalid value.
507   */
508 QDeclarativeV8Handle QQuickCanvasItem::getContext(const QString &contextId)
509 {
510     Q_D(QQuickCanvasItem);
511
512     if (contextId.toLower() != QLatin1String("2d"))
513         return QDeclarativeV8Handle::fromHandle(v8::Undefined());
514
515     if (!d->context)
516         createContext();
517     return QDeclarativeV8Handle::fromHandle(d->context->v8value());
518 }
519
520 /*!
521   \qmlmethod void QtQuick2::Canvas::markDirty(rect region)
522
523   Mark the given \a region as dirty, so that when this region is visible
524   the canvas render will redraw it. During the rendering process, the
525   canvas renderer may emit the canvas' "paint" signal so the actual painting
526   scripts can be putted into the canvas's "onPaint" signal handler function.
527
528   \sa QtQuick2::Canvas::paint QtQuick2::Canvas::requestPaint
529   */
530 void QQuickCanvasItem::markDirty(const QRectF& region)
531 {
532     Q_D(QQuickCanvasItem);
533     d->dirtyRect |= region;
534     if (d->componentCompleted)
535         polish();
536     update();
537 }
538
539
540 /*!
541   \qmlmethod bool QtQuick2::Canvas::save(string filename)
542
543    Save the current canvas content into an image file \a filename.
544    The saved image format is automatically decided by the \a filename's
545    suffix.
546
547    Note: calling this method will force painting the whole canvas, not the
548    current canvas visible window.
549
550    \sa canvasWindow canvasSize toDataURL
551   */
552 bool QQuickCanvasItem::save(const QString &filename) const
553 {
554     Q_D(const QQuickCanvasItem);
555     QUrl url = d->baseUrl.resolved(QUrl::fromLocalFile(filename));
556     return toImage().save(url.toLocalFile());
557 }
558
559 QImage QQuickCanvasItem::loadedImage(const QUrl& url)
560 {
561     Q_D(QQuickCanvasItem);
562     QUrl fullPathUrl = d->baseUrl.resolved(url);
563     if (!d->images.contains(fullPathUrl)) {
564         loadImage(url);
565     }
566     QDeclarativePixmap* pix = d->images.value(fullPathUrl);
567     if (pix->isLoading() || pix->isError()) {
568         return QImage();
569     }
570     return pix->pixmap().toImage();
571 }
572
573 /*!
574   \qmlmethod void QtQuick2::Canvas::loadImage(url image)
575     Loads the given \c image asynchronously, when the image is
576     ready, an imageLoaded signal will be emitted.
577     The loaded image can be unloaded by the \a QtQuick2::Canvas::unloadImage method.
578
579     Note: Only loaded images can be painted on the Canvas item.
580   \sa QtQuick2::Canvas::unloadImage QtQuick2::Canvas::imageLoaded QtQuick2::Canvas::isImageLoaded
581   \sa QtQuick2::Context2D::createImageData QtQuick2::Context2D::drawImage
582   */
583 void QQuickCanvasItem::loadImage(const QUrl& url)
584 {
585     Q_D(QQuickCanvasItem);
586     QUrl fullPathUrl = d->baseUrl.resolved(url);
587     if (!d->images.contains(fullPathUrl)) {
588         QDeclarativePixmap* pix = new QDeclarativePixmap();
589         d->images.insert(fullPathUrl, pix);
590
591         pix->load(qmlEngine(this)
592                 , fullPathUrl
593                 , QDeclarativePixmap::Cache | QDeclarativePixmap::Asynchronous);
594         pix->connectFinished(this, SIGNAL(imageLoaded()));
595     }
596 }
597 /*!
598   \qmlmethod void QtQuick2::Canvas::loadImage(url image)
599   Unloads the \c image.
600
601   If the image is unloaded from the Canvas item, it can't be painted by the canvas context
602   until it's loaded again.
603
604   \sa QtQuick2::Canvas::loadImage QtQuick2::Canvas::imageLoaded QtQuick2::Canvas::isImageLoaded
605   \sa QtQuick2::Context2D::createImageData QtQuick2::Context2D::drawImage
606   */
607 void QQuickCanvasItem::unloadImage(const QUrl& url)
608 {
609     Q_D(QQuickCanvasItem);
610     QUrl removeThis = d->baseUrl.resolved(url);
611     if (d->images.contains(removeThis)) {
612         delete d->images.value(removeThis);
613         d->images.remove(removeThis);
614     }
615 }
616
617 /*!
618   \qmlmethod void QtQuick2::Canvas::isImageError(url image)
619   Returns true if the image can't be loaded because of error happens.
620
621   \sa QtQuick2::Canvas::loadImage
622   */
623 bool QQuickCanvasItem::isImageError(const QUrl& url) const
624 {
625     Q_D(const QQuickCanvasItem);
626     QUrl fullPathUrl = d->baseUrl.resolved(url);
627     return d->images.contains(fullPathUrl)
628         && d->images.value(fullPathUrl)->isError();
629 }
630
631 /*!
632   \qmlmethod void QtQuick2::Canvas::isImageLoading(url image)
633   Returns true if the Canvas item still is loading the \c image.
634
635   \sa QtQuick2::Canvas::loadImage
636   */
637 bool QQuickCanvasItem::isImageLoading(const QUrl& url) const
638 {
639     Q_D(const QQuickCanvasItem);
640     QUrl fullPathUrl = d->baseUrl.resolved(url);
641     return d->images.contains(fullPathUrl)
642         && d->images.value(fullPathUrl)->isLoading();
643 }
644 /*!
645   \qmlmethod void QtQuick2::Canvas::isImageLoaded(url image)
646   Returns true if the \c image is sucessfully loaded and ready to use.
647
648   \sa QtQuick2::Canvas::loadImage
649   */
650 bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const
651 {
652     Q_D(const QQuickCanvasItem);
653     QUrl fullPathUrl = d->baseUrl.resolved(url);
654     return d->images.contains(fullPathUrl)
655         && d->images.value(fullPathUrl)->isReady();
656 }
657
658 QImage QQuickCanvasItem::toImage(const QRectF& region) const
659 {
660     Q_D(const QQuickCanvasItem);
661     if (d->texture) {
662         if (region.isEmpty())
663             return d->texture->toImage(canvasWindow());
664         else
665             return d->texture->toImage(region);
666     }
667     return QImage();
668 }
669
670 /*!
671   \qmlmethod string QtQuick2::Canvas::toDataURL(string mimeType)
672
673    Returns a data: URL for the image in the canvas.
674
675    The default \a mimeType is "image/png".
676
677    \sa QtQuick2::Canvas::save
678   */
679 QString QQuickCanvasItem::toDataURL(const QString& mimeType) const
680 {
681     QImage image = toImage();
682
683     if (!image.isNull()) {
684         QByteArray ba;
685         QBuffer buffer(&ba);
686         buffer.open(QIODevice::WriteOnly);
687         QString mime = mimeType.toLower();
688         QString type;
689         if (mime == QLatin1Literal("image/png")) {
690             type = QLatin1Literal("PNG");
691         } else if (mime == QLatin1Literal("image/bmp"))
692             type = QLatin1Literal("BMP");
693         else if (mime == QLatin1Literal("image/jpeg"))
694             type = QLatin1Literal("JPEG");
695         else if (mime == QLatin1Literal("image/x-portable-pixmap"))
696             type = QLatin1Literal("PPM");
697         else if (mime == QLatin1Literal("image/tiff"))
698             type = QLatin1Literal("TIFF");
699         else if (mime == QLatin1Literal("image/xpm"))
700             type = QLatin1Literal("XPM");
701         else
702             return QLatin1Literal("data:,");
703
704         image.save(&buffer, type.toAscii());
705         buffer.close();
706         QString dataUrl = QLatin1Literal("data:%1;base64,%2");
707         return dataUrl.arg(mime).arg(QLatin1String(ba.toBase64().constData()));
708     }
709     return QLatin1Literal("data:,");
710 }
711
712 /*!
713     \qmlsignal QtQuick2::Canvas::onPaint(QtQuick2::Context2D context, rect region)
714
715     This handler is called before the given \c region needs to be rendered.
716
717     This signal can be triggered by QtQuick2::Canvas::markdirty, QtQuick2::Canvas::requestPaint
718     or by changing the current canvas window.
719 */
720
721 /*!
722     \qmlsignal QtQuick2::Canvas::onPainted()
723
724     This handler is called after all context painting commands are executed and
725     the Canvas is actually rendered.
726 */
727
728 QT_END_NAMESPACE