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