1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickimageprovider.h"
5
6#include "qquickimageprovider_p.h"
7#include "qquickpixmapcache_p.h"
8#include <QtQuick/private/qsgcontext_p.h>
9#include <private/qqmlglobal_p.h>
10#include <QtGui/qcolorspace.h>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \class QQuickTextureFactory
16 \since 5.0
17 \brief The QQuickTextureFactory class provides an interface for loading custom textures from QML.
18 \inmodule QtQuick
19
20 The purpose of the texture factory is to provide a placeholder for a image
21 data that can be converted into an OpenGL texture.
22
23 Creating a texture directly is not possible as there is rarely an OpenGL context
24 available in the thread that is responsible for loading the image data.
25*/
26
27/*!
28 Constructs a texture factory. Since QQuickTextureFactory is abstract, it
29 cannot be instantiated directly.
30*/
31
32QQuickTextureFactory::QQuickTextureFactory()
33{
34}
35
36/*!
37 Destroys the texture factory.
38*/
39
40QQuickTextureFactory::~QQuickTextureFactory()
41{
42}
43
44/*!
45 \fn int QQuickTextureFactory::textureByteCount() const
46
47 Returns the number of bytes of memory the texture consumes.
48*/
49
50/*!
51 \fn QImage QQuickTextureFactory::image() const
52
53 Returns an image version of this texture.
54
55 The lifespan of the returned image is unknown, so the implementation should
56 return a self contained QImage, not make use of the QImage(uchar *, ...)
57 constructor.
58
59 This function is not commonly used and is expected to be slow.
60 */
61
62QImage QQuickTextureFactory::image() const
63{
64 return QImage();
65}
66
67/*!
68 Returns a QQuickTextureFactory holding the given \a image.
69
70 This is typically used as a helper in QQuickImageResponse::textureFactory.
71
72 \since 5.6
73 */
74
75QQuickTextureFactory *QQuickTextureFactory::textureFactoryForImage(const QImage &image)
76{
77 if (image.isNull())
78 return nullptr;
79 QQuickTextureFactory *texture = QSGContext::createTextureFactoryFromImage(image);
80 if (texture)
81 return texture;
82 return new QQuickDefaultTextureFactory(image);
83}
84
85
86
87/*!
88 \fn QSGTexture *QQuickTextureFactory::createTexture(QQuickWindow *window) const
89
90 This function is called on the scene graph rendering thread to create a QSGTexture
91 instance from the factory. \a window provides the context which this texture is
92 created in.
93
94 QML will internally cache the returned texture as needed. Each call to this
95 function should return a unique instance.
96
97 The OpenGL context used for rendering is bound when this function is called.
98 */
99
100/*!
101 \fn QSize QQuickTextureFactory::textureSize() const
102
103 Returns the size of the texture. This function will be called from arbitrary threads
104 and should not rely on an OpenGL context bound.
105 */
106
107
108/*!
109 \class QQuickImageResponse
110 \since 5.6
111 \brief The QQuickImageResponse class provides an interface for asynchronous image loading in QQuickAsyncImageProvider.
112 \inmodule QtQuick
113
114 The purpose of an image response is to provide a way for image provider jobs to be executed
115 in an asynchronous way.
116
117 Responses are deleted via \l deleteLater once the finished() signal has been emitted.
118 If you are using QRunnable as base for your QQuickImageResponse
119 ensure automatic deletion is disabled.
120
121 See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation.
122
123 \sa QQuickImageProvider
124*/
125
126/*!
127 Constructs the image response
128*/
129QQuickImageResponse::QQuickImageResponse()
130 : QObject(*(new QQuickImageResponsePrivate))
131{
132 qmlobject_connect(this, QQuickImageResponse, SIGNAL(finished()),
133 this, QQuickImageResponse, SLOT(_q_finished()));
134}
135
136/*!
137 Destructs the image response
138*/
139QQuickImageResponse::~QQuickImageResponse()
140{
141}
142
143/*!
144 Returns the error string for the job execution. An empty string means no error.
145*/
146QString QQuickImageResponse::errorString() const
147{
148 return QString();
149}
150
151/*!
152 This method is used to communicate that the response is no longer required by the engine.
153
154 It may be reimplemented to cancel a request in the provider side, however, it is not mandatory.
155
156 A cancelled QQuickImageResponse still needs to emit finished() so that the
157 engine may clean up the QQuickImageResponse.
158
159 \note finished() should not be emitted until the response is complete,
160 regardless of whether or not cancel() was called. If it is called prematurely,
161 the engine may destroy the response while it is still active, leading to a crash.
162*/
163void QQuickImageResponse::cancel()
164{
165}
166
167/*!
168 \fn void QQuickImageResponse::finished()
169
170 Signals that the job execution has finished (be it successfully, because an
171 error happened or because it was cancelled).
172
173 \note Emission of this signal must be the final action the response performs:
174 once the signal is received, the response will subsequently be destroyed by
175 the engine.
176 */
177
178/*!
179 \fn QQuickTextureFactory *QQuickImageResponse::textureFactory() const
180
181 Returns the texture factory for the job. You can use QQuickTextureFactory::textureFactoryForImage
182 if your provider works with QImage. The engine takes ownership of the returned QQuickTextureFactory.
183
184 \note This method will be called only when needed. For example, it may not be called if there is an
185 error or the job is cancelled. Therefore, allocate the QQuickTextureFactory instance only in this
186 method or otherwise ensure its deletion.
187 */
188
189
190/*!
191 \class QQuickImageProvider
192 \since 5.0
193 \inmodule QtQuick
194 \brief The QQuickImageProvider class provides an interface for supporting pixmaps and threaded image requests in QML.
195
196 QQuickImageProvider is used to provide advanced image loading features
197 in QML applications. It allows images in QML to be:
198
199 \list
200 \li Loaded using QPixmaps rather than actual image files
201 \li Loaded asynchronously in a separate thread
202 \endlist
203
204 To specify that an image should be loaded by an image provider, use the
205 \b {"image:"} scheme for the URL source of the image, followed by the
206 identifiers of the image provider and the requested image. For example:
207
208 \qml
209 Image { source: "image://myimageprovider/image.png" }
210 \endqml
211
212 This specifies that the image should be loaded by the image provider named
213 "myimageprovider", and the image to be loaded is named "image.png". The QML engine
214 invokes the appropriate image provider according to the providers that have
215 been registered through QQmlEngine::addImageProvider().
216
217 Note that the identifiers are case-insensitive, but the rest of the URL will be passed on with
218 preserved case. For example, the below snippet would still specify that the image is loaded by the
219 image provider named "myimageprovider", but it would request a different image than the above snippet
220 ("Image.png" instead of "image.png").
221 \qml
222 Image { source: "image://MyImageProvider/Image.png" }
223 \endqml
224
225 If you want the rest of the URL to be case insensitive, you will have to take care
226 of that yourself inside your image provider.
227
228 \section2 An Example
229
230 Here are two images. Their \c source values indicate they should be loaded by
231 an image provider named "colors", and the images to be loaded are "yellow"
232 and "red", respectively:
233
234 \snippet imgprovider/imageprovider-example.qml 0
235
236 When these images are loaded by QML, it looks for a matching image provider
237 and calls its requestImage() or requestPixmap() method (depending on its
238 imageType()) to load the image. The method is called with the \c id
239 parameter set to "yellow" for the first image, and "red" for the second.
240
241 Here is an image provider implementation that can load the images
242 requested by the above QML. This implementation dynamically
243 generates QPixmap images that are filled with the requested color:
244
245 \snippet imgprovider/imageprovider.cpp 0
246
247 To make this provider accessible to QML, it is registered with the QML engine
248 with a "colors" identifier:
249
250 \snippet imgprovider/imageprovider.cpp 1
251 \codeline
252 \snippet imgprovider/imageprovider.cpp 2
253
254 Now the images can be successfully loaded in QML:
255
256 \image imageprovider.png
257
258 See the \l {imageprovider}{Image Provider Example} for the complete implementation.
259 Note that the example registers the provider via a \l{QQmlEngineExtensionPlugin}{plugin}
260 instead of registering it in the application \c main() function as shown above.
261
262
263 \section2 Asynchronous Image Loading
264
265 Image providers that support QImage or Texture loading automatically include support
266 for asychronous loading of images. To enable asynchronous loading for an
267 image source, set the \c asynchronous property to \c true for the relevant
268 \l Image or \l BorderImage object. When this is enabled,
269 the image request to the provider is run in a low priority thread,
270 allowing image loading to be executed in the background, and reducing the
271 performance impact on the user interface.
272
273 To force asynchronous image loading, even for image sources that do not
274 have the \c asynchronous property set to \c true, you may pass the
275 \c QQmlImageProviderBase::ForceAsynchronousImageLoading flag to the image
276 provider constructor. This ensures that all image requests for the
277 provider are handled in a separate thread.
278
279 Asynchronous loading for image providers that provide QPixmap is only supported
280 in platforms that have the ThreadedPixmaps feature, in platforms where
281 pixmaps can only be created in the main thread (i.e. ThreadedPixmaps is not supported)
282 if \l {Image::}{asynchronous} is set to \c true, the value is ignored
283 and the image is loaded synchronously.
284
285 Asynchronous image loading for providers of type other than ImageResponse are
286 executed on a single thread per engine basis. That means that a slow image provider
287 will block the loading of any other request. To avoid that we suggest using QQuickAsyncImageProvider
288 and implement threading on the provider side via a \c QThreadPool or similar.
289 See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation.
290
291
292 \section2 Image Caching
293
294 Images returned by a QQuickImageProvider are automatically cached,
295 similar to any image loaded by the QML engine. When an image with a
296 "image://" prefix is loaded from cache, requestImage() and requestPixmap()
297 will not be called for the relevant image provider. If an image should
298 always be fetched from the image provider, and should not be cached at
299 all, set the \c cache property to \c false for the relevant \l Image
300 or \l BorderImage object.
301
302 \sa QQmlEngine::addImageProvider()
303*/
304
305/*!
306 Creates an image provider that will provide images of the given \a type and
307 behave according to the given \a flags.
308*/
309QQuickImageProvider::QQuickImageProvider(ImageType type, Flags flags)
310 : d(new QQuickImageProviderPrivate)
311{
312 d->type = type;
313 d->flags = flags;
314 d->isProviderWithOptions = false;
315}
316
317/*!
318 Destroys the QQuickImageProvider
319
320 \note The destructor of your derived class need to be thread safe.
321*/
322QQuickImageProvider::~QQuickImageProvider()
323{
324 delete d;
325}
326
327/*!
328 Returns the image type supported by this provider.
329*/
330QQuickImageProvider::ImageType QQuickImageProvider::imageType() const
331{
332 return d->type;
333}
334
335/*!
336 Returns the flags set for this provider.
337*/
338QQuickImageProvider::Flags QQuickImageProvider::flags() const
339{
340 return d->flags;
341}
342
343/*!
344 Implement this method to return the image with \a id. The default
345 implementation returns an empty image.
346
347 The \a id is the requested image source, with the "image:" scheme and
348 provider identifier removed. For example, if the image \l{Image::}{source}
349 was "image://myprovider/icons/home", the given \a id would be "icons/home".
350
351 The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
352 an Image item. If \a requestedSize is a valid size, the image
353 returned should be of that size.
354
355 In all cases, \a size must be set to the original size of the image. This
356 is used to set the \l {Item::}{width} and \l {Item::}{height} of the
357 relevant \l Image if these values have not been set explicitly.
358
359 \note this method may be called by multiple threads, so ensure the
360 implementation of this method is reentrant.
361*/
362QImage QQuickImageProvider::requestImage(const QString &id, QSize *size, const QSize& requestedSize)
363{
364 Q_UNUSED(id);
365 Q_UNUSED(size);
366 Q_UNUSED(requestedSize);
367 if (d->type == Image)
368 qWarning(msg: "ImageProvider supports Image type but has not implemented requestImage()");
369 return QImage();
370}
371
372/*!
373 Implement this method to return the pixmap with \a id. The default
374 implementation returns an empty pixmap.
375
376 The \a id is the requested image source, with the "image:" scheme and
377 provider identifier removed. For example, if the image \l{Image::}{source}
378 was "image://myprovider/icons/home", the given \a id would be "icons/home".
379
380 The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
381 an Image item. If \a requestedSize is a valid size, the image
382 returned should be of that size.
383
384 In all cases, \a size must be set to the original size of the image. This
385 is used to set the \l {Item::}{width} and \l {Item::}{height} of the
386 relevant \l Image if these values have not been set explicitly.
387
388 \note this method may be called by multiple threads, so ensure the
389 implementation of this method is reentrant.
390*/
391QPixmap QQuickImageProvider::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
392{
393 Q_UNUSED(id);
394 Q_UNUSED(size);
395 Q_UNUSED(requestedSize);
396 if (d->type == Pixmap)
397 qWarning(msg: "ImageProvider supports Pixmap type but has not implemented requestPixmap()");
398 return QPixmap();
399}
400
401
402/*!
403 Implement this method to return the texture with \a id. The default
404 implementation returns \nullptr.
405
406 The \a id is the requested image source, with the "image:" scheme and
407 provider identifier removed. For example, if the image \l{Image::}{source}
408 was "image://myprovider/icons/home", the given \a id would be "icons/home".
409
410 The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
411 an Image item. If \a requestedSize is a valid size, the image
412 returned should be of that size.
413
414 In all cases, \a size must be set to the original size of the image. This
415 is used to set the \l {Item::}{width} and \l {Item::}{height} of the
416 relevant \l Image if these values have not been set explicitly.
417
418 \note this method may be called by multiple threads, so ensure the
419 implementation of this method is reentrant.
420*/
421
422QQuickTextureFactory *QQuickImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
423{
424 Q_UNUSED(id);
425 Q_UNUSED(size);
426 Q_UNUSED(requestedSize);
427 if (d->type == Texture)
428 qWarning(msg: "ImageProvider supports Texture type but has not implemented requestTexture()");
429 return nullptr;
430}
431
432/*!
433 \class QQuickAsyncImageProvider
434 \since 5.6
435 \inmodule QtQuick
436 \brief The QQuickAsyncImageProvider class provides an interface for asynchronous control of QML image requests.
437
438 See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation.
439
440 \sa QQuickImageProvider
441*/
442QQuickAsyncImageProvider::QQuickAsyncImageProvider()
443 : QQuickImageProvider(ImageResponse, ForceAsynchronousImageLoading)
444 , d(nullptr) // just as a placeholder in case we need it for the future
445{
446 Q_UNUSED(d);
447}
448
449QQuickAsyncImageProvider::~QQuickAsyncImageProvider()
450{
451}
452
453/*!
454 \fn QQuickImageResponse *QQuickAsyncImageProvider::requestImageResponse(const QString &id, const QSize &requestedSize)
455
456 Implement this method to return the job that will provide the texture with \a id.
457
458 The \a id is the requested image source, with the "image:" scheme and
459 provider identifier removed. For example, if the image \l{Image::}{source}
460 was "image://myprovider/icons/home", the given \a id would be "icons/home".
461
462 The \a requestedSize corresponds to the \l {Image::sourceSize} requested by
463 an Image item. If \a requestedSize is a valid size, the image
464 returned should be of that size.
465
466 \note this method may be called by multiple threads, so ensure the
467 implementation of this method is reentrant.
468*/
469
470
471class QQuickImageProviderOptionsPrivate : public QSharedData
472{
473public:
474 QQuickImageProviderOptionsPrivate()
475 {
476 }
477
478 QColorSpace targetColorSpace;
479 QQuickImageProviderOptions::AutoTransform autoTransform = QQuickImageProviderOptions::UsePluginDefaultTransform;
480 bool preserveAspectRatioCrop = false;
481 bool preserveAspectRatioFit = false;
482};
483
484/*!
485 \class QQuickImageProviderOptions
486 \brief The QQuickImageProviderOptions class provides options for QQuickImageProviderWithOptions image requests.
487 \inmodule QtQuick
488 \internal
489
490 \sa QQuickImageProviderWithOptions
491*/
492
493/*!
494 \enum QQuickImageProviderOptions::AutoTransform
495
496 Whether the image provider should apply transformation metadata on read().
497
498 \value UsePluginDefaultTransform Image provider should do its default behavior on whether applying transformation metadata on read or not
499 \value ApplyTransform Image provider should apply transformation metadata on read
500 \value DoNotApplyTransform Image provider should not apply transformation metadata on read
501*/
502
503QQuickImageProviderOptions::QQuickImageProviderOptions()
504 : d(new QQuickImageProviderOptionsPrivate())
505{
506}
507
508QQuickImageProviderOptions::~QQuickImageProviderOptions()
509{
510}
511
512QQuickImageProviderOptions::QQuickImageProviderOptions(const QQuickImageProviderOptions &other)
513 : d(other.d)
514{
515}
516
517QQuickImageProviderOptions& QQuickImageProviderOptions::operator=(const QQuickImageProviderOptions &other)
518{
519 d = other.d;
520 return *this;
521}
522
523bool QQuickImageProviderOptions::operator==(const QQuickImageProviderOptions &other) const
524{
525 return d->autoTransform == other.d->autoTransform &&
526 d->preserveAspectRatioCrop == other.d->preserveAspectRatioCrop &&
527 d->preserveAspectRatioFit == other.d->preserveAspectRatioFit &&
528 d->targetColorSpace == other.d->targetColorSpace;
529}
530
531/*!
532 Returns whether the image provider should apply transformation metadata on read().
533*/
534QQuickImageProviderOptions::AutoTransform QQuickImageProviderOptions::autoTransform() const
535{
536 return d->autoTransform;
537}
538
539void QQuickImageProviderOptions::setAutoTransform(QQuickImageProviderOptions::AutoTransform autoTransform)
540{
541 d->autoTransform = autoTransform;
542}
543
544/*!
545 Returns whether the image request is for a PreserveAspectCrop Image.
546 This allows the provider to better optimize the size of the returned image.
547*/
548bool QQuickImageProviderOptions::preserveAspectRatioCrop() const
549{
550 return d->preserveAspectRatioCrop;
551}
552
553void QQuickImageProviderOptions::setPreserveAspectRatioCrop(bool preserveAspectRatioCrop)
554{
555 d->preserveAspectRatioCrop = preserveAspectRatioCrop;
556}
557
558/*!
559 Returns whether the image request is for a PreserveAspectFit Image.
560 This allows the provider to better optimize the size of the returned image.
561*/
562bool QQuickImageProviderOptions::preserveAspectRatioFit() const
563{
564 return d->preserveAspectRatioFit;
565}
566
567void QQuickImageProviderOptions::setPreserveAspectRatioFit(bool preserveAspectRatioFit)
568{
569 d->preserveAspectRatioFit = preserveAspectRatioFit;
570}
571
572/*!
573 Returns the color space the image provider should return the image in.
574*/
575QColorSpace QQuickImageProviderOptions::targetColorSpace() const
576{
577 return d->targetColorSpace;
578}
579
580void QQuickImageProviderOptions::setTargetColorSpace(const QColorSpace &colorSpace)
581{
582 d->targetColorSpace = colorSpace;
583}
584
585QQuickImageProviderWithOptions::QQuickImageProviderWithOptions(ImageType type, Flags flags)
586 : QQuickAsyncImageProvider()
587{
588 QQuickImageProvider::d->type = type;
589 QQuickImageProvider::d->flags = flags;
590 QQuickImageProvider::d->isProviderWithOptions = true;
591}
592
593QImage QQuickImageProviderWithOptions::requestImage(const QString &id, QSize *size, const QSize& requestedSize)
594{
595 return requestImage(id, size, requestedSize, options: QQuickImageProviderOptions());
596}
597
598QPixmap QQuickImageProviderWithOptions::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
599{
600 return requestPixmap(id, size, requestedSize, options: QQuickImageProviderOptions());
601}
602
603QQuickTextureFactory *QQuickImageProviderWithOptions::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
604{
605 return requestTexture(id, size, requestedSize, options: QQuickImageProviderOptions());
606}
607
608QImage QQuickImageProviderWithOptions::requestImage(const QString &id, QSize *size, const QSize& requestedSize, const QQuickImageProviderOptions &options)
609{
610 Q_UNUSED(options);
611 return QQuickAsyncImageProvider::requestImage(id, size, requestedSize);
612}
613
614QPixmap QQuickImageProviderWithOptions::requestPixmap(const QString &id, QSize *size, const QSize& requestedSize, const QQuickImageProviderOptions &options)
615{
616 Q_UNUSED(options);
617 return QQuickAsyncImageProvider::requestPixmap(id, size, requestedSize);
618}
619
620QQuickTextureFactory *QQuickImageProviderWithOptions::requestTexture(const QString &id, QSize *size, const QSize &requestedSize, const QQuickImageProviderOptions &options)
621{
622 Q_UNUSED(options);
623 return QQuickAsyncImageProvider::requestTexture(id, size, requestedSize);
624}
625
626QQuickImageResponse *QQuickImageProviderWithOptions::requestImageResponse(const QString &id, const QSize &requestedSize)
627{
628 Q_UNUSED(id);
629 Q_UNUSED(requestedSize);
630 if (imageType() == ImageResponse)
631 qWarning(msg: "ImageProvider is of ImageResponse type but has not implemented requestImageResponse()");
632 return nullptr;
633}
634
635QQuickImageResponse *QQuickImageProviderWithOptions::requestImageResponse(const QString &id, const QSize &requestedSize, const QQuickImageProviderOptions &options)
636{
637 Q_UNUSED(options);
638 return requestImageResponse(id, requestedSize);
639}
640
641/*!
642 Returns the recommended scaled image size for loading and storage. This is
643 calculated according to the native pixel size of the image \a originalSize,
644 the requested sourceSize \a requestedSize, the image file format \a format,
645 and \a options. If the calculation otherwise concludes that scaled loading
646 is not recommended, an invalid size is returned.
647*/
648QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options,
649 qreal devicePixelRatio)
650{
651 QSize res;
652 const bool formatIsScalable = (format == "svg" || format == "svgz" || format == "pdf");
653 const bool noRequestedSize = requestedSize.width() <= 0 && requestedSize.height() <= 0;
654 if ((noRequestedSize && !formatIsScalable) || originalSize.isEmpty())
655 return res;
656
657 // If no sourceSize was set and we're loading an SVG, ensure that we provide
658 // a default size that accounts for DPR so that the image isn't blurry.
659 if (noRequestedSize && formatIsScalable)
660 return originalSize * devicePixelRatio;
661
662 const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit();
663
664 if (!preserveAspectCropOrFit && formatIsScalable && !requestedSize.isEmpty())
665 return requestedSize;
666
667 qreal ratio = 0.0;
668 if (requestedSize.width() && (preserveAspectCropOrFit || formatIsScalable ||
669 requestedSize.width() < originalSize.width())) {
670 ratio = qreal(requestedSize.width()) / originalSize.width();
671 }
672 if (requestedSize.height() && (preserveAspectCropOrFit || formatIsScalable ||
673 requestedSize.height() < originalSize.height())) {
674 qreal hr = qreal(requestedSize.height()) / originalSize.height();
675 if (ratio == 0.0)
676 ratio = hr;
677 else if (!preserveAspectCropOrFit && (hr < ratio))
678 ratio = hr;
679 else if (preserveAspectCropOrFit && (hr > ratio))
680 ratio = hr;
681 }
682 if (ratio > 0.0) {
683 res.setHeight(qRound(d: originalSize.height() * ratio));
684 res.setWidth(qRound(d: originalSize.width() * ratio));
685 }
686 return res;
687}
688
689QQuickImageProviderWithOptions *QQuickImageProviderWithOptions::checkedCast(QQuickImageProvider *provider)
690{
691 if (provider && provider->d && provider->d->isProviderWithOptions)
692 return static_cast<QQuickImageProviderWithOptions *>(provider);
693
694 return nullptr;
695}
696
697QT_END_NAMESPACE
698
699#include "moc_qquickimageprovider.cpp"
700

source code of qtdeclarative/src/quick/util/qquickimageprovider.cpp