fix several canvasitem bugs
[profile/ivi/qtdeclarative.git] / src / declarative / items / context2d / qsgcanvasitem.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 "qsgcanvasitem_p.h"
44 #include "qsgitem_p.h"
45 #include "qsgcontext2d_p.h"
46 #include "qsgcontext2dnode_p.h"
47 #include "qsgcontext2dtexture_p.h"
48 #include "qdeclarativepixmapcache_p.h"
49
50 #include <qdeclarativeinfo.h>
51 #include "qdeclarativeengine_p.h"
52 #include <QtCore/QBuffer>
53
54 QT_BEGIN_NAMESPACE
55
56 class QSGCanvasItemPrivate : public QSGItemPrivate
57 {
58 public:
59     QSGCanvasItemPrivate();
60     ~QSGCanvasItemPrivate();
61     QSGContext2D* context;
62     QSGContext2DTexture* 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     QSGCanvasItem::RenderTarget renderTarget;
73     QHash<QUrl, QDeclarativePixmap*> images;
74     QUrl baseUrl;
75 };
76
77 QSGCanvasItemPrivate::QSGCanvasItemPrivate()
78     : QSGItemPrivate()
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(QSGCanvasItem::FramebufferObject)
89 {
90 }
91
92 QSGCanvasItemPrivate::~QSGCanvasItemPrivate()
93 {
94     qDeleteAll(images);
95 }
96
97 /*!
98     \qmlclass Canvas QSGCanvasItem
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 QSGCanvasItem::QSGCanvasItem(QSGItem *parent)
179     : QSGItem(*(new QSGCanvasItemPrivate), parent)
180 {
181     setFlag(ItemHasContents);
182 }
183
184 QSGCanvasItem::~QSGCanvasItem()
185 {
186     Q_D(QSGCanvasItem);
187     if (d->texture) {
188         d->texture->setItem(0);
189         d->texture->deleteLater();
190     }
191     delete d->context;
192 }
193
194 /*!
195     \qmlproperty size QtQuick2::Canvas::canvasSize
196      Holds the logical canvas size that the context paints on.
197
198      By default, the canvas size is the same size as the current canvas item size.
199      By setting the canvas size, tile size and canvas window, the Canvas
200      item can act as a virtual large canvas with many seperately rendered tile rectangle
201      areas. Only those tiles within the current canvas window would be painted by
202      the Canvas render engine.
203     \sa QtQuick2::Canvas::tileSize QtQuick2::Canvas::canvasWindow
204 */
205 QSizeF QSGCanvasItem::canvasSize() const
206 {
207     Q_D(const QSGCanvasItem);
208     return d->canvasSize;
209 }
210
211 void QSGCanvasItem::setCanvasSize(const QSizeF & size)
212 {
213     Q_D(QSGCanvasItem);
214     if (d->canvasSize != size) {
215         d->hasCanvasSize = true;
216         d->canvasSize = size;
217         emit canvasSizeChanged();
218         polish();
219         update();
220     }
221 }
222
223 /*!
224     \qmlproperty size QtQuick2::Canvas::tileSize
225      Holds the canvas rendering tile size.
226
227      When the Canvas item in tiled mode by setting the canvas size, tile size and
228      the canvas window. The canvas render can improve the rendering performance
229      by rendering and caching tiles instead of rendering the whole canvas everytime.
230
231      Additionally, the canvas size could be infinitely large without allocating more
232      memories because only those tiles within the current visible region
233      are actually rendered.
234
235      By default, the tile size is the same with the canvas size.
236      \sa QtQuick2::Canvas::canvaasSize QtQuick2::Canvas::canvasWindow
237 */
238 QSize QSGCanvasItem::tileSize() const
239 {
240     Q_D(const QSGCanvasItem);
241     return d->tileSize;
242 }
243
244 void QSGCanvasItem::setTileSize(const QSize & size)
245 {
246     Q_D(QSGCanvasItem);
247     if (d->tileSize != size) {
248         d->hasTileSize = true;
249         d->tileSize = size;
250
251         emit tileSizeChanged();
252         polish();
253         update();
254     }
255 }
256
257 /*!
258     \qmlproperty rect QtQuick2::Canvas::canvasWindow
259      Holds the current canvas visible window.
260
261      By default, the canvas window size is the same as the Canvas item
262      size with the topleft point as (0, 0).
263
264      If the canvas size is different with the Canvas item size, the Canvas
265      item can display different visible areas by changing the canvas window's size
266      and/or position.
267     \sa QtQuick2::Canvas::canvasSize QtQuick2::Canvas::tileSize
268 */
269 QRectF QSGCanvasItem::canvasWindow() const
270 {
271     Q_D(const QSGCanvasItem);
272     return d->canvasWindow;
273 }
274
275 void QSGCanvasItem::setCanvasWindow(const QRectF& rect)
276 {
277     Q_D(QSGCanvasItem);
278     if (d->canvasWindow != rect) {
279         d->canvasWindow = rect;
280
281         d->hasCanvasWindow = true;
282         emit canvasWindowChanged();
283         polish();
284         update();
285     }
286 }
287
288
289 QSGContext2D* QSGCanvasItem::context() const
290 {
291     Q_D(const QSGCanvasItem);
292     return d->context;
293 }
294 /*!
295     \qmlproperty bool QtQuick2::Canvas::renderInThread
296      Holds the current canvas rendering mode.
297
298      By setting the renderInThread to true, complex and long
299      running painting can be rendered in a dedicated background
300      rendering thread to avoid blocking the main GUI.
301
302      Note: Different renderTarget may or may not support the
303      background rendering thread, if not, the renderInThread
304      property will be ignored.
305
306      The default value is false.
307     \sa QtQuick2::Canvas::renderTarget
308 */
309 bool QSGCanvasItem::renderInThread() const
310 {
311     Q_D(const QSGCanvasItem);
312     return d->renderInThread;
313 }
314 /*!
315     \qmlproperty bool QtQuick2::Canvas::renderTarget
316      Holds the current canvas render target.
317
318      \list
319      \o Canvas.Image  - render to an in memory image buffer, the render
320                         target supports background rendering.
321      \o Canvas.FramebufferObject - render to an OpenGL frame buffer,
322                                    this render target will ignore the
323                                    renderInThread property. The actual
324                                    rendering happens in the main QML rendering
325                                    process, which may be in a seperate render thread
326                                    or in the main GUI thread depends on the platforms.
327      \endlist
328
329      The default render target is \c Canvas.Image.
330     \sa QtQuick2::Canvas::renderInThread
331 */
332 QSGCanvasItem::RenderTarget QSGCanvasItem::renderTarget() const
333 {
334     Q_D(const QSGCanvasItem);
335     return d->renderTarget;
336 }
337
338 void QSGCanvasItem::setRenderTarget(RenderTarget target)
339 {
340     Q_D(QSGCanvasItem);
341     if (d->renderTarget != target) {
342         d->renderTarget = target;
343
344         if (d->componentCompleted)
345             createTexture();
346         emit renderTargetChanged();
347     }
348 }
349
350 void QSGCanvasItem::_doPainting(const QRectF& region)
351 {
352     Q_D(QSGCanvasItem);
353     emit paint(QDeclarativeV8Handle::fromHandle(d->context->v8value())
354              , QSGContext2DTexture::tiledRect(region, d->tileSize));
355     if (d->texture)
356         d->texture->wake();
357 }
358
359 /*!
360     \qmlproperty bool QtQuick2::Canvas::renderInThread
361      Holds the current canvas rendering mode.
362
363      When this property is true, all canvas painting commands
364      are rendered in a background rendering thread, otherwise
365      the rendering happens in the main GUI thread.
366
367      The default renderInThread value is false.
368 */
369 void QSGCanvasItem::setRenderInThread(bool renderInThread)
370 {
371     Q_D(QSGCanvasItem);
372     if (d->renderInThread != renderInThread) {
373         d->renderInThread = renderInThread;
374
375         if (d->componentCompleted)
376             createTexture();
377
378         if (d->renderInThread)
379             connect(this, SIGNAL(painted()), SLOT(update()));
380         else
381             disconnect(this, SIGNAL(painted()), this, SLOT(update()));
382         emit renderInThreadChanged();
383         polish();
384         update();
385     }
386 }
387
388 void QSGCanvasItem::geometryChanged(const QRectF &newGeometry,
389                              const QRectF &oldGeometry)
390 {
391     Q_D(QSGCanvasItem);
392     QSGItem::geometryChanged(newGeometry, oldGeometry);
393
394     const qreal w = newGeometry.width();
395     const qreal h = newGeometry.height();
396
397     if (!d->hasCanvasSize) {
398         d->canvasSize = QSizeF(w, h);
399         emit canvasSizeChanged();
400     }
401
402     if (!d->hasTileSize) {
403         d->tileSize = d->canvasSize.toSize();
404         emit tileSizeChanged();
405     }
406
407     if (!d->hasCanvasWindow) {
408         d->canvasWindow = newGeometry;
409         emit canvasWindowChanged();
410     }
411
412     polish();
413     update();
414 }
415
416 void QSGCanvasItem::componentComplete()
417 {
418     Q_D(QSGCanvasItem);
419     QSGItem::componentComplete();
420
421     if (!d->context)
422         createContext();
423     createTexture();
424
425     d->baseUrl = qmlEngine(this)->contextForObject(this)->baseUrl();
426     requestPaint();
427     updatePolish(); //force update the canvas sizes to texture for the first time
428     update();
429     d->componentCompleted = true;
430 }
431
432 void QSGCanvasItem::updatePolish()
433 {
434     Q_D(QSGCanvasItem);
435     QSGItem::updatePolish();
436     if (d->texture) {
437         if (!d->renderInThread && d->dirtyRect.isValid())
438             _doPainting(d->dirtyRect);
439
440         d->texture->canvasChanged(d->canvasSize.toSize()
441                                 , d->tileSize
442                                 , d->canvasWindow.toAlignedRect()
443                                 , d->dirtyRect.toAlignedRect()
444                                 , d->smooth);
445         d->dirtyRect = QRectF();
446     }
447 }
448
449 QSGNode *QSGCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
450 {
451     Q_D(QSGCanvasItem);
452     QSGContext2DNode *node = static_cast<QSGContext2DNode *>(oldNode);
453     if (!node)
454         node = new QSGContext2DNode(this);
455
456     node->setTexture(d->texture);
457     node->setSize(d->canvasWindow.size());
458     node->update();
459     return node;
460 }
461
462 void QSGCanvasItem::createTexture()
463 {
464     Q_D(QSGCanvasItem);
465
466     if (!d->texture
467       || d->texture->threadRendering() != d->renderInThread
468       || d->texture->renderTarget() != d->renderTarget) {
469         if (d->texture) {
470             d->texture->deleteLater();
471             d->texture = 0;
472         }
473
474         if (d->renderTarget == QSGCanvasItem::Image) {
475             d->texture = new QSGContext2DImageTexture(d->renderInThread);
476         } else if (d->renderTarget == QSGCanvasItem::FramebufferObject) {
477             d->texture = new QSGContext2DFBOTexture();
478         }
479
480         if (d->renderInThread && !d->texture->supportThreadRendering()) {
481             qWarning("Canvas: render target does not support thread rendering, force to non-thread rendering mode.");
482             d->renderInThread = false;
483             emit renderInThreadChanged();
484         }
485
486         if (d->renderInThread)
487             connect(d->texture, SIGNAL(textureChanged()), this, SLOT(update()));
488
489         d->texture->setItem(this);
490     }
491 }
492
493 void QSGCanvasItem::createContext()
494 {
495     Q_D(QSGCanvasItem);
496
497     delete d->context;
498
499     d->context = new QSGContext2D(this);
500
501     QV8Engine *e = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this));
502     d->context->setV8Engine(e);
503 }
504
505 /*!
506   \qmlmethod object QtQuick2::Canvas::getContext(string contextId)
507
508   Currently, the canvas item only support the 2D context. If the \a contextId
509   parameter isn't provided or is "2d", then the QtQuick2::Context2D object is
510   returned, otherwise returns an invalid value.
511   */
512 QDeclarativeV8Handle QSGCanvasItem::getContext(const QString &contextId)
513 {
514     Q_D(QSGCanvasItem);
515
516     if (contextId.toLower() != QLatin1String("2d"))
517         return QDeclarativeV8Handle::fromHandle(v8::Undefined());
518
519     if (!d->context)
520         createContext();
521     return QDeclarativeV8Handle::fromHandle(d->context->v8value());
522 }
523
524 /*!
525   \qmlmethod void QtQuick2::Canvas::markDirty(rect region)
526
527   Mark the given \a region as dirty, so that when this region is visible
528   the canvas render will redraw it. During the rendering process, the
529   canvas renderer may emit the canvas' "paint" signal so the actual painting
530   scripts can be putted into the canvas's "onPaint" signal handler function.
531
532   \sa QtQuick2::Canvas::paint QtQuick2::Canvas::requestPaint
533   */
534 void QSGCanvasItem::markDirty(const QRectF& region)
535 {
536     Q_D(QSGCanvasItem);
537     d->dirtyRect |= region;
538     if (d->componentCompleted)
539         polish();
540     update();
541 }
542
543
544 /*!
545   \qmlmethod bool QtQuick2::Canvas::save(string filename)
546
547    Save the current canvas content into an image file \a filename.
548    The saved image format is automatically decided by the \a filename's
549    suffix.
550
551    Note: calling this method will force painting the whole canvas, not the
552    current canvas visible window.
553
554    \sa canvasWindow canvasSize toDataURL
555   */
556 bool QSGCanvasItem::save(const QString &filename) const
557 {
558     Q_D(const QSGCanvasItem);
559     QUrl url = d->baseUrl.resolved(QUrl::fromLocalFile(filename));
560     return toImage().save(url.toLocalFile());
561 }
562
563 QImage QSGCanvasItem::loadedImage(const QUrl& url)
564 {
565     Q_D(QSGCanvasItem);
566     QUrl fullPathUrl = d->baseUrl.resolved(url);
567     if (!d->images.contains(fullPathUrl)) {
568         loadImage(url);
569     }
570     QDeclarativePixmap* pix = d->images.value(fullPathUrl);
571     if (pix->isLoading() || pix->isError()) {
572         return QImage();
573     }
574     return pix->pixmap().toImage();
575 }
576
577 /*!
578   \qmlmethod void QtQuick2::Canvas::loadImage(url image)
579     Loads the given \c image asynchronously, when the image is
580     ready, an imageLoaded signal will be emitted.
581     The loaded image can be unloaded by the \a QtQuick2::Canvas::unloadImage method.
582
583     Note: Only loaded images can be painted on the Canvas item.
584   \sa QtQuick2::Canvas::unloadImage QtQuick2::Canvas::imageLoaded QtQuick2::Canvas::isImageLoaded
585   \sa QtQuick2::Context2D::createImageData QtQuick2::Context2D::drawImage
586   */
587 void QSGCanvasItem::loadImage(const QUrl& url)
588 {
589     Q_D(QSGCanvasItem);
590     QUrl fullPathUrl = d->baseUrl.resolved(url);
591     if (!d->images.contains(fullPathUrl)) {
592         QDeclarativePixmap* pix = new QDeclarativePixmap();
593         d->images.insert(fullPathUrl, pix);
594
595         pix->load(qmlEngine(this)
596                 , fullPathUrl
597                 , QDeclarativePixmap::Cache | QDeclarativePixmap::Asynchronous);
598         pix->connectFinished(this, SIGNAL(imageLoaded()));
599     }
600 }
601 /*!
602   \qmlmethod void QtQuick2::Canvas::loadImage(url image)
603   Unloads the \c image.
604
605   If the image is unloaded from the Canvas item, it can't be painted by the canvas context
606   until it's loaded again.
607
608   \sa QtQuick2::Canvas::loadImage QtQuick2::Canvas::imageLoaded QtQuick2::Canvas::isImageLoaded
609   \sa QtQuick2::Context2D::createImageData QtQuick2::Context2D::drawImage
610   */
611 void QSGCanvasItem::unloadImage(const QUrl& url)
612 {
613     Q_D(QSGCanvasItem);
614     QUrl removeThis = d->baseUrl.resolved(url);
615     if (d->images.contains(removeThis)) {
616         delete d->images.value(removeThis);
617         d->images.remove(removeThis);
618     }
619 }
620
621 /*!
622   \qmlmethod void QtQuick2::Canvas::isImageError(url image)
623   Returns true if the image can't be loaded because of error happens.
624
625   \sa QtQuick2::Canvas::loadImage
626   */
627 bool QSGCanvasItem::isImageError(const QUrl& url) const
628 {
629     Q_D(const QSGCanvasItem);
630     QUrl fullPathUrl = d->baseUrl.resolved(url);
631     return d->images.contains(fullPathUrl)
632         && d->images.value(fullPathUrl)->isError();
633 }
634
635 /*!
636   \qmlmethod void QtQuick2::Canvas::isImageLoading(url image)
637   Returns true if the Canvas item still is loading the \c image.
638
639   \sa QtQuick2::Canvas::loadImage
640   */
641 bool QSGCanvasItem::isImageLoading(const QUrl& url) const
642 {
643     Q_D(const QSGCanvasItem);
644     QUrl fullPathUrl = d->baseUrl.resolved(url);
645     return d->images.contains(fullPathUrl)
646         && d->images.value(fullPathUrl)->isLoading();
647 }
648 /*!
649   \qmlmethod void QtQuick2::Canvas::isImageLoaded(url image)
650   Returns true if the \c image is sucessfully loaded and ready to use.
651
652   \sa QtQuick2::Canvas::loadImage
653   */
654 bool QSGCanvasItem::isImageLoaded(const QUrl& url) const
655 {
656     Q_D(const QSGCanvasItem);
657     QUrl fullPathUrl = d->baseUrl.resolved(url);
658     return d->images.contains(fullPathUrl)
659         && d->images.value(fullPathUrl)->isReady();
660 }
661
662 QImage QSGCanvasItem::toImage(const QRectF& region) const
663 {
664     Q_D(const QSGCanvasItem);
665     if (d->texture) {
666         if (region.isEmpty())
667             return d->texture->toImage(canvasWindow());
668         else
669             return d->texture->toImage(region);
670     }
671     return QImage();
672 }
673
674 /*!
675   \qmlmethod string QtQuick2::Canvas::toDataURL(string mimeType)
676
677    Returns a data: URL for the image in the canvas.
678
679    The default \a mimeType is "image/png".
680
681    \sa QtQuick2::Canvas::save
682   */
683 QString QSGCanvasItem::toDataURL(const QString& mimeType) const
684 {
685     QImage image = toImage();
686
687     if (!image.isNull()) {
688         QByteArray ba;
689         QBuffer buffer(&ba);
690         buffer.open(QIODevice::WriteOnly);
691         QString mime = mimeType.toLower();
692         QString type;
693         if (mime == QLatin1Literal("image/png")) {
694             type = QLatin1Literal("PNG");
695         } else if (mime == QLatin1Literal("image/bmp"))
696             type = QLatin1Literal("BMP");
697         else if (mime == QLatin1Literal("image/jpeg"))
698             type = QLatin1Literal("JPEG");
699         else if (mime == QLatin1Literal("image/x-portable-pixmap"))
700             type = QLatin1Literal("PPM");
701         else if (mime == QLatin1Literal("image/tiff"))
702             type = QLatin1Literal("TIFF");
703         else if (mime == QLatin1Literal("image/xpm"))
704             type = QLatin1Literal("XPM");
705         else
706             return QLatin1Literal("data:,");
707
708         image.save(&buffer, type.toAscii());
709         buffer.close();
710         QString dataUrl = QLatin1Literal("data:%1;base64,%2");
711         return dataUrl.arg(mime).arg(QLatin1String(ba.toBase64().constData()));
712     }
713     return QLatin1Literal("data:,");
714 }
715
716 /*!
717     \qmlsignal QtQuick2::Canvas::onPaint(QtQuick2::Context2D context, rect region)
718
719     This handler is called before the given \c region needs to be rendered.
720
721     This signal can be triggered by QtQuick2::Canvas::markdirty, QtQuick2::Canvas::requestPaint
722     or by changing the current canvas window.
723 */
724
725 /*!
726     \qmlsignal QtQuick2::Canvas::onPainted()
727
728     This handler is called after all context painting commands are executed and
729     the Canvas is actually rendered.
730 */
731
732 QT_END_NAMESPACE