5#include <private/qsgadaptationlayer_p.h>
7#include <private/qquickitem_p.h>
8#include <private/qquickcanvascontext_p.h>
9#include <private/qquickcontext2d_p.h>
10#include <private/qquickcontext2dtexture_p.h>
11#include <private/qsgadaptationlayer_p.h>
12#include <qsgtextureprovider.h>
13#include <QtQuick/private/qquickpixmap_p.h>
14#include <QtGui/QGuiApplication>
15#include <qsgtextureprovider.h>
18#include <private/qqmlengine_p.h>
19#include <QtCore/QBuffer>
21#include <QtCore/qdatetime.h>
23#include <private/qv4value_p.h>
24#include <private/qv4functionobject_p.h>
25#include <private/qv4scopedvalue_p.h>
26#include <private/qv4jscall_p.h>
27#include <private/qv4qobjectwrapper_p.h>
28#include <private/qjsvalue_p.h>
61 return m_pixmap->width();
63 return m_image.width();
69 return m_pixmap->height();
71 return m_image.height();
77 return m_pixmap->isReady();
78 return !m_image.isNull();
83 if (m_image.isNull() && m_pixmap)
84 m_image = m_pixmap->image();
93 : QThread(eng), m_engine(eng), m_eventLoopQuitHack(
nullptr)
96 m_eventLoopQuitHack =
new QObject;
97 m_eventLoopQuitHack->moveToThread(
this);
98 connect(m_eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection);
99 start(QThread::IdlePriority);
104 renderThreadsMutex.lock();
105 renderThreads.remove(m_engine);
106 renderThreadsMutex.unlock();
108 m_eventLoopQuitHack->deleteLater();
115 renderThreadsMutex.lock();
116 if (renderThreads.contains(engine))
117 thread = renderThreads.value(engine);
119 thread =
new QQuickContext2DRenderThread(engine);
120 renderThreads.insert(engine, thread);
122 renderThreadsMutex.unlock();
166 implicitAntialiasing =
true;
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
261 : QQuickItem(*(
new QQuickCanvasItemPrivate), parent)
263 setFlag(ItemHasContents);
268 Q_D(QQuickCanvasItem);
270 if (d->textureProvider)
271 QQuickWindowQObjectCleanupJob::schedule(window(), d->textureProvider);
275
276
277
278
282 return d_func()->available;
286
287
288
289
290
291
292
293
294
295
296
297
298
302 return d_func()->contextType;
307 Q_D(QQuickCanvasItem);
309 if (contextType.compare(d->contextType, Qt::CaseInsensitive) == 0)
313 qmlWarning(
this) <<
"Canvas already initialized with a different context type";
317 d->contextType = contextType;
320 createContext(contextType);
322 emit contextTypeChanged();
326
327
328
329
330
331
332
336 Q_D(
const QQuickCanvasItem);
337 return d->context ? QJSValuePrivate::fromReturnedValue(d->context->v4value()) : QJSValue();
341
342
343
344
345
346
347
348
349
350
351
352
353
356 Q_D(
const QQuickCanvasItem);
357 return d->canvasSize;
362 Q_D(QQuickCanvasItem);
363 if (d->canvasSize != size) {
364 d->hasCanvasSize =
true;
365 d->canvasSize = size;
366 emit canvasSizeChanged();
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
392 Q_D(
const QQuickCanvasItem);
398 Q_D(QQuickCanvasItem);
399 if (d->tileSize != size) {
400 d->hasTileSize =
true;
403 emit tileSizeChanged();
411
412
413
414
415
416
417
418
419
420
421
422
423
424
427 Q_D(
const QQuickCanvasItem);
428 return d->canvasWindow;
433 Q_D(QQuickCanvasItem);
434 if (d->canvasWindow != rect) {
435 d->canvasWindow = rect;
437 d->hasCanvasWindow =
true;
438 emit canvasWindowChanged();
446
447
448
449
450
451
452
453
454
455
456
457
458
459
462 Q_D(
const QQuickCanvasItem);
463 return d->renderTarget;
468 Q_D(QQuickCanvasItem);
469 if (d->renderTarget != target) {
471 qmlWarning(
this) <<
"Canvas:renderTarget not changeble once context is active.";
475 d->renderTarget = target;
476 emit renderTargetChanged();
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
505 return d_func()->renderStrategy;
510 Q_D(QQuickCanvasItem);
511 if (d->renderStrategy != strategy) {
513 qmlWarning(
this) <<
"Canvas:renderStrategy not changeable once context is active.";
516 d->renderStrategy = strategy;
517 emit renderStrategyChanged();
523 return d_func()->context;
528 IS_SIGNAL_CONNECTED(
this, QQuickCanvasItem, paint, (
const QRect &));
533 Q_D(QQuickCanvasItem);
536 connect(
this, SIGNAL(visibleChanged()), SLOT(checkAnimationCallbacks()));
537 QMetaObject::invokeMethod(
this,
"availableChanged", Qt::QueuedConnection);
539 if (!d->contextType.isNull())
540 QMetaObject::invokeMethod(
this,
"delayedCreate", Qt::QueuedConnection);
541 else if (isPaintConnected())
542 QMetaObject::invokeMethod(
this,
"requestPaint", Qt::QueuedConnection);
547 Q_D(QQuickCanvasItem);
549 QQuickItem::geometryChange(newGeometry, oldGeometry);
553 QSizeF newSize = QSizeF(width(), height());
554 if (!d->hasCanvasSize && d->canvasSize != newSize) {
555 d->canvasSize = newSize;
556 emit canvasSizeChanged();
559 if (!d->hasTileSize && d->tileSize != newSize) {
560 d->tileSize = newSize.toSize();
561 emit tileSizeChanged();
564 const QRectF rect = QRectF(QPointF(0, 0), newSize);
566 if (!d->hasCanvasWindow && d->canvasWindow != rect) {
567 d->canvasWindow = rect;
568 emit canvasWindowChanged();
571 if (d->available && newSize != oldGeometry.size()) {
572 if (isVisible() || (d->extra.isAllocated() && d->extra->effectRefCount > 0))
579 Q_D(QQuickCanvasItem);
583 d->context =
nullptr;
586 if (d->textureProvider) {
587 QQuickWindowQObjectCleanupJob::schedule(window(), d->textureProvider);
588 d->textureProvider =
nullptr;
590 if (d->nodeTexture) {
591 QQuickWindowQObjectCleanupJob::schedule(window(), d->nodeTexture);
592 d->nodeTexture =
nullptr;
598 switch (event->type()) {
599 case QEvent::PolishRequest:
603 return QQuickItem::event(event);
609 Q_D(QQuickCanvasItem);
611 d->context->deleteLater();
612 d->context =
nullptr;
614 delete d->textureProvider;
615 d->textureProvider =
nullptr;
616 delete d->nodeTexture;
617 d->nodeTexture =
nullptr;
626 auto polishRequestEvent =
new QEvent(QEvent::PolishRequest);
627 QCoreApplication::postEvent(
this, polishRequestEvent);
632 QQuickItem::componentComplete();
634 Q_D(QQuickCanvasItem);
635 d->baseUrl = qmlEngine(
this)->contextForObject(
this)->baseUrl();
640 QQuickItem::itemChange(change, value);
641 if (change != QQuickItem::ItemSceneChange)
644 Q_D(QQuickCanvasItem);
646 if (d->dirtyAttributes & QQuickItemPrivate::ContentUpdateMask)
651 if (value.window==
nullptr)
654 d->window = value.window;
655 QSGRenderContext *context = QQuickWindowPrivate::get(d->window)->context;
658 if (context !=
nullptr && (d->renderTarget != FramebufferObject || context->isValid())) {
662 QMetaObject::invokeMethod(
this,
"sceneGraphInitialized", Qt::QueuedConnection);
664 connect(d->window, SIGNAL(sceneGraphInitialized()), SLOT(sceneGraphInitialized()));
670 QQuickItem::updatePolish();
672 Q_D(QQuickCanvasItem);
673 if (d->context && d->renderStrategy != QQuickCanvasItem::Cooperative)
674 d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth, antialiasing());
676 if (d->animationCallbacks.size() > 0 && isVisible()) {
677 QMap<
int, QV4::PersistentValue> animationCallbacks = d->animationCallbacks;
678 d->animationCallbacks.clear();
680 QV4::ExecutionEngine *v4 = qmlEngine(
this)->handle();
681 QV4::Scope scope(v4);
682 QV4::ScopedFunctionObject function(scope);
683 QV4::JSCallArguments jsCall(scope, 1);
684 *jsCall.thisObject = QV4::QObjectWrapper::wrap(v4,
this);
686 for (
auto it = animationCallbacks.cbegin(), end = animationCallbacks.cend(); it != end; ++it) {
687 function = it.value().value();
688 jsCall.args[0] = QV4::Value::fromUInt32(QDateTime::currentMSecsSinceEpoch());
689 function->call(jsCall);
693 if (d->dirtyRect.isValid()) {
694 if (d->hasTileSize && d->hasCanvasWindow)
695 emit paint(tiledRect(d->canvasWindow.intersected(d->dirtyRect.toAlignedRect()), d->tileSize));
697 emit paint(d->dirtyRect.toRect());
698 d->dirtyRect = QRectF();
703 if (d->renderStrategy == QQuickCanvasItem::Cooperative)
712 Q_D(QQuickCanvasItem);
714 if (!d->context || d->canvasWindow.size().isEmpty()) {
715 if (d->textureProvider) {
716 d->textureProvider->tex =
nullptr;
717 d->textureProvider->fireTextureChanged();
723 QSGInternalImageNode *node =
static_cast<QSGInternalImageNode *>(oldNode);
725 QSGRenderContext *rc = QQuickWindowPrivate::get(window())->context;
726 node = rc->sceneGraphContext()->createInternalImageNode(rc);
732 node->setFiltering(QSGTexture::Linear);
734 node->setFiltering(QSGTexture::Nearest);
736 if (d->renderStrategy == QQuickCanvasItem::Cooperative) {
737 d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth, antialiasing());
741 QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
742 QQuickContext2DTexture *factory = ctx->texture();
743 QSGTexture *texture = factory->textureForNextFrame(d->nodeTexture, window());
747 d->nodeTexture =
nullptr;
748 if (d->textureProvider) {
749 d->textureProvider->tex =
nullptr;
750 d->textureProvider->fireTextureChanged();
755 d->nodeTexture = texture;
756 node->setTexture(texture);
757 node->setTargetRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
758 node->setInnerTargetRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
761 if (d->textureProvider) {
762 d->textureProvider->tex = d->nodeTexture;
763 d->textureProvider->fireTextureChanged();
778 if (QQuickItem::isTextureProvider())
779 return QQuickItem::textureProvider();
781 Q_D(
const QQuickCanvasItem);
783 QQuickWindow *w = window();
784 if (!w || !w->isSceneGraphInitialized()
785 || QThread::currentThread() != QQuickWindowPrivate::get(w)->context->thread()) {
786 qWarning(
"QQuickCanvasItem::textureProvider: can only be queried on the rendering thread of an exposed window");
790 if (!d->textureProvider)
791 d->textureProvider =
new QQuickCanvasTextureProvider;
792 d->textureProvider->tex = d->nodeTexture;
793 return d->textureProvider;
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
817 Q_D(QQuickCanvasItem);
819 QV4::Scope scope(args->v4engine());
820 QV4::ScopedString str(scope, (*args)[0]);
822 qmlWarning(
this) <<
"getContext should be called with a string naming the required context type";
823 args->setReturnValue(QV4::Encode::null());
828 qmlWarning(
this) <<
"Unable to use getContext() at this time, please wait for available: true";
829 args->setReturnValue(QV4::Encode::null());
833 QString contextId = str->toQString();
835 if (d->context !=
nullptr) {
836 if (d->context->contextNames().contains(contextId, Qt::CaseInsensitive)) {
837 args->setReturnValue(d->context->v4value());
841 qmlWarning(
this) <<
"Canvas already initialized with a different context type";
842 args->setReturnValue(QV4::Encode::null());
846 if (createContext(contextId))
847 args->setReturnValue(d->context->v4value());
849 args->setReturnValue(QV4::Encode::null());
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
903 QV4::Scope scope(args->v4engine());
904 QV4::ScopedFunctionObject f(scope, (*args)[0]);
906 qmlWarning(
this) <<
"requestAnimationFrame should be called with an animation callback function";
907 args->setReturnValue(QV4::Encode::null());
911 Q_D(QQuickCanvasItem);
915 d->animationCallbacks.insert(++id, QV4::PersistentValue(scope.engine, f->asReturnedValue()));
921 args->setReturnValue(QV4::Encode(id));
925
926
927
928
932 QV4::Scope scope(args->v4engine());
933 QV4::ScopedValue v(scope, (*args)[0]);
934 if (!v->isInteger()) {
935 qmlWarning(
this) <<
"cancelRequestAnimationFrame should be called with an animation callback id";
936 args->setReturnValue(QV4::Encode::null());
940 d_func()->animationCallbacks.remove(v->integerValue());
945
946
947
948
949
950
954 markDirty(d_func()->canvasWindow);
958
959
960
961
962
963
964
968 Q_D(QQuickCanvasItem);
972 d->dirtyRect |= rect;
979 if (d_func()->animationCallbacks.size() > 0 && isVisible())
984
985
986
987
988
989
990
991
992
993
994
995
996
997
1000 Q_D(
const QQuickCanvasItem);
1001 QString localFile = filename;
1002 if (QDir::isRelativePath(filename)) {
1004 url.setPath(filename);
1005 localFile = d->baseUrl.resolved(url).toLocalFile();
1007 return toImage(QRectF(QPointF(0, 0), imageSize)).save(localFile);
1012 Q_D(QQuickCanvasItem);
1013 QUrl fullPathUrl = d->baseUrl.resolved(url);
1014 if (!d->pixmaps.contains(fullPathUrl)) {
1015 loadImage(url, sourceSize);
1017 return d->pixmaps.value(fullPathUrl);
1021
1022
1023
1024
1025
1026
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1047 Q_D(QQuickCanvasItem);
1048 QUrl fullPathUrl = d->baseUrl.resolved(url);
1049 if (!d->pixmaps.contains(fullPathUrl)) {
1050 QQuickPixmap* pix =
new QQuickPixmap();
1051 QQmlRefPointer<QQuickCanvasPixmap> canvasPix;
1052 canvasPix.adopt(
new QQuickCanvasPixmap
(pix
));
1053 d->pixmaps.insert(fullPathUrl, canvasPix);
1055 pix->load(qmlEngine(
this)
1058 , sourceSize.toSize()
1059 , QQuickPixmap::Cache | QQuickPixmap::Asynchronous);
1060 if (pix->isLoading())
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1077 Q_D(QQuickCanvasItem);
1078 d->pixmaps.remove(d->baseUrl.resolved(url));
1082
1083
1084
1085
1086
1087
1090 Q_D(
const QQuickCanvasItem);
1091 QUrl fullPathUrl = d->baseUrl.resolved(url);
1092 return d->pixmaps.contains(fullPathUrl)
1093 && d->pixmaps.value(fullPathUrl)->pixmap()->isError();
1097
1098
1099
1100
1101
1104 Q_D(
const QQuickCanvasItem);
1105 QUrl fullPathUrl = d->baseUrl.resolved(url);
1106 return d->pixmaps.contains(fullPathUrl)
1107 && d->pixmaps.value(fullPathUrl)->pixmap()->isLoading();
1110
1111
1112
1113
1114
1117 Q_D(
const QQuickCanvasItem);
1118 QUrl fullPathUrl = d->baseUrl.resolved(url);
1119 return d->pixmaps.contains(fullPathUrl)
1120 && d->pixmaps.value(fullPathUrl)->pixmap()->isReady();
1124
1125
1126
1127
1131 Q_D(
const QQuickCanvasItem);
1136 const QRectF &rectSource = rect.isEmpty() ? canvasWindow() : rect;
1137 const qreal dpr = window() && rect.isEmpty() ? window()->effectiveDevicePixelRatio() : qreal(1);
1138 const QRectF rectScaled(rectSource.topLeft() * dpr, rectSource.size() * dpr);
1140 QImage image = d->context->toImage(rectScaled);
1141 image.setDevicePixelRatio(dpr);
1147 const QLatin1String imagePrefix(
"image/");
1148 if (!mime.startsWith(imagePrefix))
1150 const QStringView mimeExt = QStringView{mime}.mid(imagePrefix.size());
1151 if (mimeExt == QLatin1String(
"png"))
1153 else if (mimeExt == QLatin1String(
"bmp"))
1155 else if (mimeExt == QLatin1String(
"jpeg"))
1157 else if (mimeExt == QLatin1String(
"x-portable-pixmap"))
1159 else if (mimeExt == QLatin1String(
"tiff"))
1161 else if (mimeExt == QLatin1String(
"xpm"))
1167
1168
1169
1170
1171
1172
1173
1174
1177 QImage image = toImage();
1179 if (!image.isNull()) {
1181 QBuffer buffer(&ba);
1182 buffer.open(QIODevice::WriteOnly);
1183 const QString mime = mimeType.toLower();
1184 const char* type = mimeToType(mime);
1186 return QStringLiteral(
"data:,");
1188 image.save(&buffer, type);
1190 return QLatin1String(
"data:") + mime + QLatin1String(
";base64,") + QLatin1String(ba.toBase64().constData());
1192 return QStringLiteral(
"data:,");
1197 Q_D(QQuickCanvasItem);
1199 if (!d->context && !d->contextType.isNull())
1200 createContext(d->contextType);
1207 Q_D(QQuickCanvasItem);
1212 if (contextType == QLatin1String(
"2d")) {
1213 if (d->contextType.compare(QLatin1String(
"2d"), Qt::CaseInsensitive) != 0) {
1214 d->contextType = QLatin1String(
"2d");
1215 emit contextTypeChanged();
1217 initializeContext(
new QQuickContext2D(
this));
1226 Q_D(QQuickCanvasItem);
1228 d->context = context;
1229 d->context->init(
this, args);
1230 d->context->setV4Engine(qmlEngine(
this)->handle());
1231 connect(d->context, SIGNAL(textureChanged()), SLOT(update()));
1232 connect(d->context, SIGNAL(textureChanged()), SIGNAL(
painted()));
1233 emit contextChanged();
1236QRect
QQuickCanvasItem::tiledRect(
const QRectF &window,
const QSize &tileSize)
1238 if (window.isEmpty())
1241 const int tw = tileSize.width();
1242 const int th = tileSize.height();
1243 const int h1 = window.left() / tw;
1244 const int v1 = window.top() / th;
1246 const int htiles = ((window.right() - h1 * tw) + tw - 1)/tw;
1247 const int vtiles = ((window.bottom() - v1 * th) + th - 1)/th;
1249 return QRect(h1 * tw, v1 * th, htiles * tw, vtiles * th);
1253
1254
1255
1256
1257
1258
1259
1260
1263
1264
1265
1266
1267
1271#include "moc_qquickcanvasitem_p.cpp"
QQuickCanvasItemPrivate()
QSGInternalImageNode * node
~QQuickCanvasItemPrivate()
QQuickCanvasItem::RenderTarget renderTarget
QMap< int, QV4::PersistentValue > animationCallbacks
QQuickCanvasItem::RenderStrategy renderStrategy
QQuickCanvasContext * context
QQuickCanvasTextureProvider * textureProvider
void setTileSize(const QSize &)
void setCanvasWindow(const QRectF &rect)
bool event(QEvent *event) override
This virtual function receives events to an object and should return true if the event e was recogniz...
bool isTextureProvider() const override
Returns true if this item is a texture provider.
bool isImageLoaded(const QUrl &url) const
\qmlmethod bool QtQuick::Canvas::isImageLoaded(url image) Returns true if the image is successfully l...
void setCanvasSize(const QSizeF &)
void setRenderStrategy(RenderStrategy strategy)
QQmlRefPointer< QQuickCanvasPixmap > loadedPixmap(const QUrl &url, QSizeF sourceSize=QSizeF())
Q_INVOKABLE void requestAnimationFrame(QQmlV4FunctionPtr args)
\qmlmethod int QtQuick::Canvas::requestAnimationFrame(callback)
void updatePolish() override
This function should perform any layout as required for this item.
QQuickCanvasContext * rawContext() const
RenderStrategy renderStrategy() const
\qmlproperty enumeration QtQuick::Canvas::renderStrategy Holds the current canvas rendering strategy.
QSGTextureProvider * textureProvider() const override
Returns the texture provider for an item.
RenderTarget renderTarget() const
\qmlproperty enumeration QtQuick::Canvas::renderTarget Holds the current canvas render target.
void setContextType(const QString &contextType)
bool isAvailable() const
\qmlproperty bool QtQuick::Canvas::available
Q_INVOKABLE bool save(const QString &filename, const QSizeF &imageSize=QSizeF()) const
\qmlmethod bool QtQuick::Canvas::save(string filename, size imageSize = undefined)
QRectF canvasWindow() const
\qmlproperty rect QtQuick::Canvas::canvasWindow Holds the current canvas visible window.
void unloadImage(const QUrl &url)
\qmlmethod void QtQuick::Canvas::unloadImage(url image)
bool isImageError(const QUrl &url) const
\qmlmethod bool QtQuick::Canvas::isImageError(url image)
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
QJSValue context() const
\qmlproperty object QtQuick::Canvas::context Holds the active drawing context.
QImage toImage(const QRectF &rect=QRectF()) const
QSize tileSize() const
\qmlproperty size QtQuick::Canvas::tileSize Holds the canvas rendering tile size.
QSGNode * updatePaintNode(QSGNode *, UpdatePaintNodeData *) override
Called on the render thread when it is time to sync the state of the item with the scene graph.
QSizeF canvasSize() const
\qmlproperty size QtQuick::Canvas::canvasSize Holds the logical canvas size that the context paints o...
void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &) override
Called when change occurs for this item.
void releaseResources() override
This function is called when an item should release graphics resources which are not already managed ...
Q_INVOKABLE void cancelRequestAnimationFrame(QQmlV4FunctionPtr args)
\qmlmethod void QtQuick::Canvas::cancelRequestAnimationFrame(int handle)
Q_INVOKABLE void getContext(QQmlV4FunctionPtr args)
\qmlmethod Context2D QtQuick::Canvas::getContext(string contextId, ... args)
bool isImageLoading(const QUrl &url) const
\qmlmethod bool QtQuick::Canvas::isImageLoading(url image) Returns true if the image is currently loa...
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
Q_INVOKABLE void markDirty(const QRectF &dirtyRect=QRectF())
\qmlmethod void QtQuick::Canvas::markDirty(rect area)
QString contextType() const
\qmlproperty string QtQuick::Canvas::contextType The type of drawing context to use.
Q_INVOKABLE void requestPaint()
\qmlmethod void QtQuick::Canvas::requestPaint()
QQuickCanvasPixmap(const QImage &image)
QQuickCanvasPixmap(QQuickPixmap *pixmap)
QSGTexture * texture() const override
Returns a pointer to the texture object.
void fireTextureChanged()
static QQuickContext2DRenderThread * instance(QQmlEngine *engine)
~QQuickContext2DRenderThread()
Combined button and popup list for selecting options.
static const char * mimeToType(const QString &mime)