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
qquickimage.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 "qquickimage_p.h"
5#include "qquickimage_p_p.h"
6
7#include <QtQuick/qsgtextureprovider.h>
8
9#include <QtQuick/private/qsgcontext_p.h>
10#include <private/qsgadaptationlayer_p.h>
11#include <private/qnumeric_p.h>
12
13#include <QtCore/qmath.h>
14#include <QtGui/qpainter.h>
15#include <QtCore/QRunnable>
16
18
24
31
41
43 : pixmapChanged(false)
44 , mipmap(false)
45{
46}
47
202
207
209{
210 Q_D(QQuickImage);
211 if (d->provider) {
212 // We're guaranteed to have a window() here because the provider would have
213 // been released in releaseResources() if we were gone from a window.
215 }
216}
217
219{
220 Q_Q(QQuickImage);
222 q->pixmapChange();
223 q->update();
224}
225
227{
228 Q_Q(QQuickImage);
230 q->pixmapChange();
231 q->update();
232}
233
329{
330 Q_D(const QQuickImage);
331 return d->fillMode;
332}
333
335{
336 Q_D(QQuickImage);
337 if (d->fillMode == mode)
338 return;
339 d->fillMode = mode;
340 if ((mode == PreserveAspectCrop) != d->providerOptions.preserveAspectRatioCrop()) {
341 d->providerOptions.setPreserveAspectRatioCrop(mode == PreserveAspectCrop);
343 load();
344 } else if ((mode == PreserveAspectFit) != d->providerOptions.preserveAspectRatioFit()) {
345 d->providerOptions.setPreserveAspectRatioFit(mode == PreserveAspectFit);
347 load();
348 }
349 update();
352}
353
366{
367 Q_D(const QQuickImage);
368 return d->paintedWidth;
369}
370
372{
373 Q_D(const QQuickImage);
374 return d->paintedHeight;
375}
376
604{
605 Q_D(QQuickImage);
606
607 if (d->fillMode == PreserveAspectFit) {
608 if (!d->currentPix->width() || !d->currentPix->height()) {
609 setImplicitSize(0, 0);
610 return;
611 }
612 const qreal pixWidth = d->currentPix->width() / d->devicePixelRatio;
613 const qreal pixHeight = d->currentPix->height() / d->devicePixelRatio;
614 const qreal w = widthValid() ? width() : pixWidth;
615 const qreal widthScale = w / pixWidth;
616 const qreal h = heightValid() ? height() : pixHeight;
617 const qreal heightScale = h / pixHeight;
618 if (widthScale <= heightScale) {
619 d->paintedWidth = w;
620 d->paintedHeight = widthScale * pixHeight;
621 } else if (heightScale < widthScale) {
622 d->paintedWidth = heightScale * pixWidth;
623 d->paintedHeight = h;
624 }
625 const qreal iHeight = (widthValid() && !heightValid()) ? d->paintedHeight : pixHeight;
626 const qreal iWidth = (heightValid() && !widthValid()) ? d->paintedWidth : pixWidth;
627 setImplicitSize(iWidth, iHeight);
628
629 } else if (d->fillMode == PreserveAspectCrop) {
630 if (!d->currentPix->width() || !d->currentPix->height())
631 return;
632 const qreal pixWidth = d->currentPix->width() / d->devicePixelRatio;
633 const qreal pixHeight = d->currentPix->height() / d->devicePixelRatio;
634 qreal widthScale = width() / pixWidth;
635 qreal heightScale = height() / pixHeight;
636 if (widthScale < heightScale) {
637 widthScale = heightScale;
638 } else if (heightScale < widthScale) {
639 heightScale = widthScale;
640 }
641
642 d->paintedHeight = heightScale * pixHeight;
643 d->paintedWidth = widthScale * pixWidth;
644 } else if (d->fillMode == Pad) {
645 d->paintedWidth = d->currentPix->width() / d->devicePixelRatio;
646 d->paintedHeight = d->currentPix->height() / d->devicePixelRatio;
647 } else {
648 d->paintedWidth = width();
649 d->paintedHeight = height();
650 }
652}
653
654void QQuickImage::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
655{
656 QQuickImageBase::geometryChange(newGeometry, oldGeometry);
657 if (newGeometry.size() != oldGeometry.size())
659}
660
662{
663 Q_D(const QQuickImage);
664 return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
665}
666
668{
669 Q_D(const QQuickImage);
670
671 // When Item::layer::enabled == true, QQuickItem will be a texture
672 // provider. In this case we should prefer to return the layer rather
673 // than the image itself. The layer will include any children and any
674 // the image's wrap and fill mode.
677
678 if (!d->window || !d->sceneGraphRenderContext() || QThread::currentThread() != d->sceneGraphRenderContext()->thread()) {
679 qWarning("QQuickImage::textureProvider: can only be queried on the rendering thread of an exposed window");
680 return nullptr;
681 }
682
683 if (!d->provider) {
684 QQuickImagePrivate *dd = const_cast<QQuickImagePrivate *>(d);
686 dd->provider->m_smooth = d->smooth;
687 dd->provider->m_mipmap = d->mipmap;
688 dd->provider->updateTexture(d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window()));
689 }
690
691 return d->provider;
692}
693
694void QQuickImage::invalidateSceneGraph()
695{
696 Q_D(QQuickImage);
697 delete d->provider;
698 d->provider = nullptr;
699}
700
702{
703 Q_D(QQuickImage);
704 if (d->provider) {
706 d->provider = nullptr;
707 }
708}
709
711{
712 Q_D(QQuickImage);
713
714 QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window());
715
716 // Copy over the current texture state into the texture provider...
717 if (d->provider) {
718 d->provider->m_smooth = d->smooth;
719 d->provider->m_mipmap = d->mipmap;
720 d->provider->updateTexture(texture);
721 }
722
723 if (!texture || width() <= 0 || height() <= 0) {
724 delete oldNode;
725 return nullptr;
726 }
727
728 QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
729 if (!node) {
730 d->pixmapChanged = true;
731 node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
732 }
733
734 QRectF targetRect;
735 QRectF sourceRect;
738
739 qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->currentPix->width() / d->devicePixelRatio;
740 qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->currentPix->height() / d->devicePixelRatio;
741
742 int xOffset = 0;
743 if (d->hAlign == QQuickImage::AlignHCenter)
744 xOffset = (width() - pixWidth) / 2;
745 else if (d->hAlign == QQuickImage::AlignRight)
746 xOffset = qCeil(width() - pixWidth);
747
748 int yOffset = 0;
749 if (d->vAlign == QQuickImage::AlignVCenter)
750 yOffset = (height() - pixHeight) / 2;
751 else if (d->vAlign == QQuickImage::AlignBottom)
752 yOffset = qCeil(height() - pixHeight);
753
754 switch (d->fillMode) {
755 case Stretch:
756 targetRect = QRectF(0, 0, width(), height());
757 sourceRect = d->currentPix->rect();
758 break;
759
761 targetRect = QRectF(xOffset, yOffset, d->paintedWidth, d->paintedHeight);
762 sourceRect = d->currentPix->rect();
763 break;
764
765 case PreserveAspectCrop: {
766 targetRect = QRectF(0, 0, width(), height());
767 qreal wscale = width() / qreal(d->currentPix->width());
768 qreal hscale = height() / qreal(d->currentPix->height());
769
770 if (wscale > hscale) {
771 int src = (hscale / wscale) * qreal(d->currentPix->height());
772 int y = 0;
773 if (d->vAlign == QQuickImage::AlignVCenter)
774 y = qCeil((d->currentPix->height() - src) / 2.);
775 else if (d->vAlign == QQuickImage::AlignBottom)
776 y = qCeil(d->currentPix->height() - src);
777 sourceRect = QRectF(0, y, d->currentPix->width(), src);
778
779 } else {
780 int src = (wscale / hscale) * qreal(d->currentPix->width());
781 int x = 0;
782 if (d->hAlign == QQuickImage::AlignHCenter)
783 x = qCeil((d->currentPix->width() - src) / 2.);
784 else if (d->hAlign == QQuickImage::AlignRight)
785 x = qCeil(d->currentPix->width() - src);
786 sourceRect = QRectF(x, 0, src, d->currentPix->height());
787 }
788 }
789 break;
790
791 case Tile:
792 targetRect = QRectF(0, 0, width(), height());
793 sourceRect = QRectF(-xOffset, -yOffset, width(), height());
794 hWrap = QSGTexture::Repeat;
795 vWrap = QSGTexture::Repeat;
796 break;
797
798 case TileHorizontally:
799 targetRect = QRectF(0, 0, width(), height());
800 sourceRect = QRectF(-xOffset, 0, width(), d->currentPix->height());
801 hWrap = QSGTexture::Repeat;
802 break;
803
804 case TileVertically:
805 targetRect = QRectF(0, 0, width(), height());
806 sourceRect = QRectF(0, -yOffset, d->currentPix->width(), height());
807 vWrap = QSGTexture::Repeat;
808 break;
809
810 case Pad:
811 qreal w = qMin(qreal(pixWidth), width());
812 qreal h = qMin(qreal(pixHeight), height());
813 qreal x = (pixWidth > width()) ? -xOffset : 0;
814 qreal y = (pixHeight > height()) ? -yOffset : 0;
815 targetRect = QRectF(x + xOffset, y + yOffset, w, h);
816 sourceRect = QRectF(x, y, w, h);
817 break;
818 }
819
820 qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->currentPix->width() / d->devicePixelRatio : d->currentPix->width();
821 qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->currentPix->height() / d->devicePixelRatio : d->currentPix->height();
822 QRectF nsrect(sourceRect.x() / nsWidth,
823 sourceRect.y() / nsHeight,
824 sourceRect.width() / nsWidth,
825 sourceRect.height() / nsHeight);
826
827 if (targetRect.isEmpty()
828 || !qt_is_finite(targetRect.width()) || !qt_is_finite(targetRect.height())
829 || nsrect.isEmpty()
830 || !qt_is_finite(nsrect.width()) || !qt_is_finite(nsrect.height())) {
831 delete node;
832 return nullptr;
833 }
834
835 if (d->pixmapChanged) {
836 // force update the texture in the node to trigger reconstruction of
837 // geometry and the likes when a atlas segment has changed.
838 if (texture->isAtlasTexture() && (hWrap == QSGTexture::Repeat || vWrap == QSGTexture::Repeat || d->mipmap))
839 node->setTexture(texture->removedFromAtlas());
840 else
841 node->setTexture(texture);
842 d->pixmapChanged = false;
843 }
844
846 node->setHorizontalWrapMode(hWrap);
847 node->setVerticalWrapMode(vWrap);
849
850 node->setTargetRect(targetRect);
851 node->setInnerTargetRect(targetRect);
852 node->setSubSourceRect(nsrect);
853 node->setMirror(d->mirrorHorizontally, d->mirrorVertically);
854 node->setAntialiasing(d->antialiasing);
855 node->update();
856
857 return node;
858}
859
861{
862 Q_D(QQuickImage);
863 // PreserveAspectFit calculates the implicit size differently so we
864 // don't call our superclass pixmapChange(), since that would
865 // result in the implicit size being set incorrectly, then updated
866 // in updatePaintedGeometry()
867 if (d->fillMode != PreserveAspectFit)
870 d->pixmapChanged = true;
871
872 // When the pixmap changes, such as being deleted, we need to update the textures
873 update();
874}
875
877{
878 Q_D(const QQuickImage);
879 return d->vAlign;
880}
881
883{
884 Q_D(QQuickImage);
885 if (d->vAlign == align)
886 return;
887
888 d->vAlign = align;
889 update();
892}
893
895{
896 Q_D(const QQuickImage);
897 return d->hAlign;
898}
899
901{
902 Q_D(QQuickImage);
903 if (d->hAlign == align)
904 return;
905
906 d->hAlign = align;
907 update();
910}
911
929{
930 Q_D(const QQuickImage);
931 return d->mipmap;
932}
933
935{
936 Q_D(QQuickImage);
937 if (d->mipmap == use)
938 return;
939 d->mipmap = use;
940 emit mipmapChanged(d->mipmap);
941
942 d->pixmapChanged = true;
944 load();
945 update();
946}
947
975
987
990
991#include "moc_qquickimage_p_p.cpp"
992
993#include "moc_qquickimage_p.cpp"
\inmodule QtGui
Definition qimage.h:37
virtual void pixmapChange()
virtual void load()
void setPixmap(const QQuickPixmap &pixmap)
QQuickImageTextureProvider * provider
void setImage(const QImage &img)
QSGTexture * texture() const override
Returns a pointer to the texture object.
void updateTexture(QSGTexture *texture)
void setFillMode(FillMode)
VAlignment verticalAlignment
void horizontalAlignmentChanged(HAlignment alignment)
qreal paintedWidth
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.
QQuickImage(QQuickItem *parent=nullptr)
\qmltype Image \instantiates QQuickImage \inqmlmodule QtQuick\inherits Item
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
void updatePaintedGeometry()
\qmlproperty enumeration QtQuick::Image::status \readonly
FillMode fillMode
QSGTextureProvider * textureProvider() const override
Returns the texture provider for an item.
void fillModeChanged()
QRectF boundingRect() const override
Returns the extents of the item in its own coordinate system: a rectangle from {0,...
qreal paintedHeight
void pixmapChange() override
HAlignment horizontalAlignment
void releaseResources() override
This function is called when an item should release graphics resources which are not already managed ...
void verticalAlignmentChanged(VAlignment alignment)
void setVerticalAlignment(VAlignment align)
void setHorizontalAlignment(HAlignment align)
void setMipmap(bool use)
void paintedGeometryChanged()
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
virtual QSGTextureProvider * textureProvider() const
Returns the texture provider for an item.
QQuickWindow * window() const
Returns the window in which this item is rendered.
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
bool heightValid() const
Returns whether the height property has been set explicitly.
bool widthValid() const
Returns whether the width property has been set explicitly.
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
void update()
Schedules a call to updatePaintNode() for this item.
virtual bool isTextureProvider() const
Returns true if this item is a texture provider.
void setImplicitSize(qreal, qreal)
void setImage(const QImage &)
void setPixmap(const QQuickPixmap &other)
static void schedule(QQuickWindow *window, QObject *object)
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
constexpr QSizeF size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:735
virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)=0
virtual void setTexture(QSGTexture *texture)=0
virtual void setTargetRect(const QRectF &rect)=0
virtual void setFiltering(QSGTexture::Filtering filtering)=0
virtual void update()=0
virtual void setSubSourceRect(const QRectF &rect)=0
virtual void setInnerTargetRect(const QRectF &rect)=0
virtual void setAntialiasing(bool antialiasing)
virtual void setMipmapFiltering(QSGTexture::Filtering filtering)=0
virtual void setMirror(bool horizontally, bool vertically)=0
virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode)=0
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
The QSGTextureProvider class encapsulates texture based entities in QML.
void textureChanged()
This signal is emitted when the texture changes.
\inmodule QtQuick
Definition qsgtexture.h:20
void setHorizontalWrapMode(WrapMode hwrap)
Sets the horizontal wrap mode to hwrap.
void setFiltering(Filtering filter)
Sets the sampling mode to filter.
void setMipmapFiltering(Filtering filter)
Sets the mipmap sampling mode to filter.
WrapMode
Specifies how the sampler should treat texture coordinates.
Definition qsgtexture.h:28
void setVerticalWrapMode(WrapMode vwrap)
Sets the vertical wrap mode to vwrap.
static QThread * currentThread()
Definition qthread.cpp:1039
Combined button and popup list for selecting options.
Definition image.cpp:4
#define qWarning
Definition qlogging.h:166
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
static Q_DECL_CONST_FUNCTION bool qt_is_finite(double d)
Definition qnumeric_p.h:117
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLenum src
GLenum GLuint texture
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
#define emit
double qreal
Definition qtypes.h:187
QObject::connect nullptr
widget render & pixmap