Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickimagebase.cpp
Go to the documentation of this file.
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 "qquickimagebase_p.h"
6
7#include <QtGui/qguiapplication.h>
8#include <QtGui/qscreen.h>
9#include <QtGui/qicon.h>
10
11#include <QtQml/qqmlinfo.h>
12#include <QtQml/qqmlfile.h>
13#include <QtQml/qqmlabstracturlinterceptor.h>
14
15
17
18using namespace Qt::Literals::StringLiterals;
19
20// This function gives derived classes the chance set the devicePixelRatio
21// if they're not happy with our implementation of it.
23{
24 // QQuickImageProvider and SVG and PDF can generate a high resolution image when
25 // sourceSize is set. If sourceSize is not set then the provider default size will
26 // be used, as usual.
27 const bool setDevicePixelRatio = QQuickPixmap::isScalableImageFormat(url);
28
29 if (setDevicePixelRatio)
30 devicePixelRatio = targetDevicePixelRatio;
31
32 return setDevicePixelRatio;
33}
34
36{
37 Q_Q(QQuickImageBase);
38
39 if (status == value)
40 return;
41
42 status = value;
43 emit q->statusChanged(status);
44}
45
47{
48 Q_Q(QQuickImageBase);
49
51 return;
52
54 emit q->progressChanged(progress);
55}
56
62
68
72
74{
75 Q_D(const QQuickImageBase);
76 return d->status;
77}
78
80{
81 Q_D(const QQuickImageBase);
82 return d->progress;
83}
84
86{
87 Q_D(const QQuickImageBase);
88 return d->async;
89}
90
92{
93 Q_D(QQuickImageBase);
94 if (d->async != async) {
95 d->async = async;
97 }
98}
99
101{
102 Q_D(const QQuickImageBase);
103 return d->url;
104}
105
107{
108 Q_D(QQuickImageBase);
109
110 if (url == d->url)
111 return;
112
113 d->url = url;
114 emit sourceChanged(d->url);
115
117 load();
118}
119
121{
122 Q_D(QQuickImageBase);
123 if (d->sourcesize == size)
124 return;
125
126 d->sourcesize = size;
129 load();
130}
131
133{
134 Q_D(const QQuickImageBase);
135
136 int width = d->sourcesize.width();
137 int height = d->sourcesize.height();
138 return QSize(width != -1 ? width : d->currentPix->width(), height != -1 ? height : d->currentPix->height());
139}
140
145
147{
148 Q_D(const QQuickImageBase);
149 return d->sourceClipRect;
150}
151
153{
154 Q_D(QQuickImageBase);
155 if (d->sourceClipRect == r)
156 return;
157
158 d->sourceClipRect = r;
159 d->providerOptions.setSourceClipRect(r);
160 emit sourceClipRectChanged();
162 load();
163}
164
169
171{
172 Q_D(const QQuickImageBase);
173 return d->cache;
174}
175
177{
178 Q_D(QQuickImageBase);
179 if (d->cache == cache)
180 return;
181
182 d->cache = cache;
185 load();
186}
187
189{
190 Q_D(const QQuickImageBase);
191 return d->currentPix->image();
192}
193
195{
196 Q_D(QQuickImageBase);
197 if (mirror == d->mirrorHorizontally)
198 return;
199
200 d->mirrorHorizontally = mirror;
201
203 update();
204
206}
207
209{
210 Q_D(const QQuickImageBase);
211 return d->mirrorHorizontally;
212}
213
215{
216 Q_D(QQuickImageBase);
217 if (mirror == d->mirrorVertically)
218 return;
219
220 d->mirrorVertically = mirror;
221
223 update();
224
225 emit mirrorVerticallyChanged();
226}
227
229{
230 Q_D(const QQuickImageBase);
231 return d->mirrorVertically;
232}
233
235{
236 Q_D(QQuickImageBase);
237 if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->currentPix->frameCount()))
238 return;
239
240 d->currentFrame = frame;
241
242 if (isComponentComplete()) {
243 if (frame > 0)
244 d->cache = false;
245 load();
246 update();
247 }
248
249 emit currentFrameChanged();
250}
251
253{
254 Q_D(const QQuickImageBase);
255 return d->currentFrame;
256}
257
259{
260 Q_D(const QQuickImageBase);
261 return d->frameCount;
262}
263
265{
266 Q_D(QQuickImageBase);
267 d->currentPix->clear(this);
268 d->pendingPix->clear(this);
269 d->setProgress(0);
270 d->status = Null; // do not emit statusChanged until after setImplicitSize
271 setImplicitSize(0, 0); // also called in QQuickImageBase::pixmapChange, but not QQuickImage/QQuickBorderImage overrides
272 pixmapChange(); // This calls update() in QQuickBorderImage and QQuickImage, not in QQuickImageBase...
273
274 emit statusChanged(d->status);
275 if (sourceSize() != d->oldSourceSize) {
276 d->oldSourceSize = sourceSize();
278 }
279 if (autoTransform() != d->oldAutoTransform) {
280 d->oldAutoTransform = autoTransform();
282 }
283 update(); // .. but double updating should be harmless
284}
285
286void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
287{
288 Q_D(QQuickImageBase);
289 QQuickPixmap::Options options;
290 if (d->async)
292 if (d->cache)
293 options |= QQuickPixmap::Cache;
294 d->pendingPix->clear(this);
295 QUrl loadUrl = url;
296 const QQmlContext *context = qmlContext(this);
297 if (context)
298 loadUrl = context->resolvedUrl(url);
299
300 if (loadOptions & HandleDPR) {
301 const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
302 d->devicePixelRatio = 1.0;
303 bool updatedDevicePixelRatio = false;
304 if (d->sourcesize.isValid()
305 || (QQuickPixmap::isScalableImageFormat(d->url) && d->url.scheme() != "image"_L1)) {
306 updatedDevicePixelRatio = d->updateDevicePixelRatio(targetDevicePixelRatio);
307 }
308
309 if (!updatedDevicePixelRatio) {
310 // (possible) local file: loadUrl and d->devicePixelRatio will be modified if
311 // an "@2x" file is found.
312 resolve2xLocalFile(context ? context->resolvedUrl(d->url) : d->url,
313 targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
314 }
315 }
316
317 d->status = Null; // reset status, no emit
318
319 d->pendingPix->load(qmlEngine(this),
320 loadUrl,
321 d->sourceClipRect.toRect(),
322 (loadOptions & HandleDPR) ? d->sourcesize * d->devicePixelRatio : QSize(),
323 options,
324 (loadOptions & UseProviderOptions) ? d->providerOptions : QQuickImageProviderOptions(),
325 d->currentFrame, d->frameCount,
326 d->devicePixelRatio);
327
328 if (d->pendingPix->isLoading()) {
329 d->setProgress(0);
330 d->setStatus(Loading);
331
332 static int thisRequestProgress = -1;
333 static int thisRequestFinished = -1;
334 if (thisRequestProgress == -1) {
335 thisRequestProgress =
336 QQuickImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
337 thisRequestFinished =
338 QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
339 }
340
341 d->pendingPix->connectFinished(this, thisRequestFinished);
342 d->pendingPix->connectDownloadProgress(this, thisRequestProgress);
343 if (!d->retainWhileLoading)
344 update(); //pixmap may have invalidated texture, updatePaintNode needs to be called before the next repaint
345 } else {
347 }
348}
349
351{
352 Q_D(QQuickImageBase);
353
354 if (d->url.isEmpty()) {
355 loadEmptyUrl();
356 update();
357 } else {
358 loadPixmap(d->url, LoadPixmapOptions(HandleDPR | UseProviderOptions));
359 }
360}
361
363{
364 Q_D(QQuickImageBase);
365
366 if (d->pendingPix != d->currentPix) {
367 std::swap(d->pendingPix, d->currentPix);
368 d->pendingPix->clear(this); // Clear the old image
369 }
370
371 if (d->currentPix->isError()) {
372 qmlWarning(this) << d->currentPix->error();
373 d->status = Error;
374 d->setProgress(0);
375 } else {
376 d->status = Ready; // do not emit statusChanged until after setImplicitSize
377 d->setProgress(1);
378 }
379
380 pixmapChange();
381 emit statusChanged(d->status);
382
383 if (sourceSize() != d->oldSourceSize) {
384 d->oldSourceSize = sourceSize();
386 }
387 if (autoTransform() != d->oldAutoTransform) {
388 d->oldAutoTransform = autoTransform();
390 }
391 if (d->frameCount != d->currentPix->frameCount()) {
392 d->frameCount = d->currentPix->frameCount();
393 emit frameCountChanged();
394 }
395 if (d->colorSpace != d->currentPix->colorSpace()) {
396 d->colorSpace = d->currentPix->colorSpace();
397 emit colorSpaceChanged();
398 }
399
400 update();
401}
402
403void QQuickImageBase::requestProgress(qint64 received, qint64 total)
404{
405 Q_D(QQuickImageBase);
406 if (d->status == Loading && total > 0)
407 d->setProgress(qreal(received) / total);
408}
409
411{
412 Q_D(QQuickImageBase);
413 // If the screen DPI changed, reload image.
414 if (change == ItemDevicePixelRatioHasChanged && value.realValue != d->devicePixelRatio) {
415 const auto oldDpr = d->devicePixelRatio;
416 // ### how can we get here with !qmlEngine(this)? that implies
417 // itemChange() on an item pending deletion, which seems strange.
418 if (qmlEngine(this) && isComponentComplete() && d->url.isValid()) {
419 load();
420 // not changed when loading (sourceSize might not be set)
421 if (d->devicePixelRatio == oldDpr)
422 d->updateDevicePixelRatio(value.realValue);
423 }
424 }
426}
427
429{
430 Q_D(QQuickImageBase);
432 if (d->url.isValid())
433 load();
434}
435
437{
438 Q_D(QQuickImageBase);
439 setImplicitSize(d->currentPix->width() / d->devicePixelRatio, d->currentPix->height() / d->devicePixelRatio);
440}
441
442void QQuickImageBase::resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio)
443{
444 Q_ASSERT(sourceUrl);
445 Q_ASSERT(sourceDevicePixelRatio);
446
447 // Bail out if "@2x" image loading is disabled, don't change the source url or devicePixelRatio.
448 static const bool disable2xImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING");
449 if (disable2xImageLoading)
450 return;
451
452 const QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
453
454 // Non-local file path: @2x loading is not supported.
455 if (localFile.isEmpty())
456 return;
457
458 // Special case: the url in the QML source refers directly to an "@2x" file.
459 int atLocation = localFile.lastIndexOf(QLatin1Char('@'));
460 if (atLocation > 0 && atLocation + 3 < localFile.size()) {
461 if (localFile[atLocation + 1].isDigit()
462 && localFile[atLocation + 2] == QLatin1Char('x')
463 && localFile[atLocation + 3] == QLatin1Char('.')) {
464 *sourceDevicePixelRatio = localFile[atLocation + 1].digitValue();
465 return;
466 }
467 }
468
469 // Look for an @2x version
470 QString localFileX = qt_findAtNxFile(localFile, targetDevicePixelRatio, sourceDevicePixelRatio);
471 if (localFileX != localFile)
472 *sourceUrl = QUrl::fromLocalFile(localFileX);
473}
474
476{
477 Q_D(const QQuickImageBase);
478 if (d->providerOptions.autoTransform() == QQuickImageProviderOptions::UsePluginDefaultTransform)
479 return d->currentPix->autoTransform() == QQuickImageProviderOptions::ApplyTransform;
480 return d->providerOptions.autoTransform() == QQuickImageProviderOptions::ApplyTransform;
481}
482
484{
485 Q_D(QQuickImageBase);
486 if (d->providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform &&
487 transform == (d->providerOptions.autoTransform() == QQuickImageProviderOptions::ApplyTransform))
488 return;
491}
492
494{
495 Q_D(const QQuickImageBase);
496 return d->colorSpace;
497}
498
500{
501 Q_D(QQuickImageBase);
502 if (d->colorSpace == colorSpace)
503 return;
504 d->colorSpace = colorSpace;
505 d->providerOptions.setTargetColorSpace(colorSpace);
506 emit colorSpaceChanged();
507}
508
510{
511 Q_D(const QQuickImageBase);
512 return d->retainWhileLoading;
513}
514
515void QQuickImageBase::setRetainWhileLoading(bool retainWhileLoading)
516{
517 Q_D(QQuickImageBase);
518 if (d->retainWhileLoading == retainWhileLoading)
519 return;
520
521 d->retainWhileLoading = retainWhileLoading;
522 if (d->retainWhileLoading) {
523 if (d->currentPix == &d->pix1)
524 d->pendingPix = &d->pix2;
525 else
526 d->pendingPix = &d->pix1;
527 } else {
528 d->pendingPix->clear();
529 d->pendingPix = d->currentPix;
530 }
531}
532
534
535#include "moc_qquickimagebase_p.cpp"
The QColorSpace class provides a color space abstraction.
Definition qcolorspace.h:21
\inmodule QtGui
Definition qimage.h:37
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to \l{QFile}.
Definition qqmlfile.cpp:742
QQuickImageBase::Status status
virtual bool updateDevicePixelRatio(qreal targetDevicePixelRatio)
void setProgress(qreal value)
void setStatus(QQuickImageBase::Status value)
bool autoTransform() const
void itemChange(ItemChange change, const ItemChangeData &value) override
Called when change occurs for this item.
void setRetainWhileLoading(bool retain)
virtual void pixmapChange()
virtual void setMirror(bool mirror)
virtual void setAutoTransform(bool transform)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
virtual void load()
void sourceSizeChanged()
virtual void setSourceSize(const QSize &)
void asynchronousChanged()
void statusChanged(QQuickImageBase::Status)
virtual void setColorSpace(const QColorSpace &colorSpace)
void loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions=NoOption)
void setSourceClipRect(const QRectF &r)
QImage image() const
static void resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio)
QColorSpace colorSpace
QRectF sourceClipRect() const
virtual void setCurrentFrame(int frame)
QSize sourceSize() const
virtual void requestFinished()
virtual void emitAutoTransformBaseChanged()
virtual void setSource(const QUrl &url)
void sourceChanged(const QUrl &)
void setAsynchronous(bool)
void mirrorChanged()
QQuickImageBase(QQuickItem *parent=nullptr)
virtual void setMirrorVertically(bool mirror)
The QQuickImageProviderOptions class provides options for QQuickImageProviderWithOptions image reques...
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void setFlag(Flag flag, bool enabled=true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disable...
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
QSizeF size() const
QQuickWindow * window() const
Returns the window in which this item is rendered.
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
@ ItemDevicePixelRatioHasChanged
Definition qquickitem.h:154
void update()
Schedules a call to updatePaintNode() for this item.
void setImplicitSize(qreal, qreal)
static bool isScalableImageFormat(const QUrl &url)
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
Definition qsize.h:25
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qurl.h:94
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3368
QCache< int, Employee > cache
[0]
Combined button and popup list for selecting options.
static void * context
#define qApp
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio, qreal *sourceDevicePixelRatio)
Definition qicon.cpp:1984
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLint GLsizei width
GLuint GLenum GLenum transform
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
QQmlEngine * qmlEngine(const QObject *obj)
Definition qqml.cpp:80
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
static QT_BEGIN_NAMESPACE bool isDigit(ushort ch)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
#define emit
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QUrl url("example.com")
[constructor-url-reference]
QFrame frame
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
\inmodule QtQuick
Definition qquickitem.h:159