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