Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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
20 : m_texture(nullptr)
21 , m_smooth(false)
22{
23}
24
26 if (m_texture == texture)
27 return;
30}
31
33 if (m_texture) {
38 }
39 return m_texture;
40}
41
43 : pixmapChanged(false)
44 , mipmap(false)
45{
46}
47
200{
201}
202
205{
206}
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
328{
329 Q_D(const QQuickImage);
330 return d->fillMode;
331}
332
334{
335 Q_D(QQuickImage);
336 if (d->fillMode == mode)
337 return;
338 d->fillMode = mode;
339 if ((mode == PreserveAspectCrop) != d->providerOptions.preserveAspectRatioCrop()) {
340 d->providerOptions.setPreserveAspectRatioCrop(mode == PreserveAspectCrop);
342 load();
343 } else if ((mode == PreserveAspectFit) != d->providerOptions.preserveAspectRatioFit()) {
344 d->providerOptions.setPreserveAspectRatioFit(mode == PreserveAspectFit);
346 load();
347 }
348 update();
351}
352
365{
366 Q_D(const QQuickImage);
367 return d->paintedWidth;
368}
369
371{
372 Q_D(const QQuickImage);
373 return d->paintedHeight;
374}
375
603{
604 Q_D(QQuickImage);
605
606 if (d->fillMode == PreserveAspectFit) {
607 if (!d->pix.width() || !d->pix.height()) {
608 setImplicitSize(0, 0);
609 return;
610 }
611 const qreal pixWidth = d->pix.width() / d->devicePixelRatio;
612 const qreal pixHeight = d->pix.height() / d->devicePixelRatio;
613 const qreal w = widthValid() ? width() : pixWidth;
614 const qreal widthScale = w / pixWidth;
615 const qreal h = heightValid() ? height() : pixHeight;
616 const qreal heightScale = h / pixHeight;
617 if (widthScale <= heightScale) {
618 d->paintedWidth = w;
619 d->paintedHeight = widthScale * pixHeight;
620 } else if (heightScale < widthScale) {
621 d->paintedWidth = heightScale * pixWidth;
622 d->paintedHeight = h;
623 }
624 const qreal iHeight = (widthValid() && !heightValid()) ? d->paintedHeight : pixHeight;
625 const qreal iWidth = (heightValid() && !widthValid()) ? d->paintedWidth : pixWidth;
626 setImplicitSize(iWidth, iHeight);
627
628 } else if (d->fillMode == PreserveAspectCrop) {
629 if (!d->pix.width() || !d->pix.height())
630 return;
631 const qreal pixWidth = d->pix.width() / d->devicePixelRatio;
632 const qreal pixHeight = d->pix.height() / d->devicePixelRatio;
633 qreal widthScale = width() / pixWidth;
634 qreal heightScale = height() / pixHeight;
635 if (widthScale < heightScale) {
636 widthScale = heightScale;
637 } else if (heightScale < widthScale) {
638 heightScale = widthScale;
639 }
640
641 d->paintedHeight = heightScale * pixHeight;
642 d->paintedWidth = widthScale * pixWidth;
643 } else if (d->fillMode == Pad) {
644 d->paintedWidth = d->pix.width() / d->devicePixelRatio;
645 d->paintedHeight = d->pix.height() / d->devicePixelRatio;
646 } else {
647 d->paintedWidth = width();
648 d->paintedHeight = height();
649 }
651}
652
653void QQuickImage::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
654{
655 QQuickImageBase::geometryChange(newGeometry, oldGeometry);
656 if (newGeometry.size() != oldGeometry.size())
658}
659
661{
662 Q_D(const QQuickImage);
663 return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
664}
665
667{
668 Q_D(const QQuickImage);
669
670 // When Item::layer::enabled == true, QQuickItem will be a texture
671 // provider. In this case we should prefer to return the layer rather
672 // than the image itself. The layer will include any children and any
673 // the image's wrap and fill mode.
676
677 if (!d->window || !d->sceneGraphRenderContext() || QThread::currentThread() != d->sceneGraphRenderContext()->thread()) {
678 qWarning("QQuickImage::textureProvider: can only be queried on the rendering thread of an exposed window");
679 return nullptr;
680 }
681
682 if (!d->provider) {
683 QQuickImagePrivate *dd = const_cast<QQuickImagePrivate *>(d);
685 dd->provider->m_smooth = d->smooth;
686 dd->provider->m_mipmap = d->mipmap;
687 dd->provider->updateTexture(d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window()));
688 }
689
690 return d->provider;
691}
692
693void QQuickImage::invalidateSceneGraph()
694{
695 Q_D(QQuickImage);
696 delete d->provider;
697 d->provider = nullptr;
698}
699
701{
702 Q_D(QQuickImage);
703 if (d->provider) {
705 d->provider = nullptr;
706 }
707}
708
710{
711 Q_D(QQuickImage);
712
713 QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
714
715 // Copy over the current texture state into the texture provider...
716 if (d->provider) {
717 d->provider->m_smooth = d->smooth;
718 d->provider->m_mipmap = d->mipmap;
719 d->provider->updateTexture(texture);
720 }
721
722 if (!texture || width() <= 0 || height() <= 0) {
723 delete oldNode;
724 return nullptr;
725 }
726
727 QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
728 if (!node) {
729 d->pixmapChanged = true;
730 node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
731 }
732
733 QRectF targetRect;
734 QRectF sourceRect;
737
738 qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width() / d->devicePixelRatio;
739 qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->pix.height() / d->devicePixelRatio;
740
741 int xOffset = 0;
742 if (d->hAlign == QQuickImage::AlignHCenter)
743 xOffset = (width() - pixWidth) / 2;
744 else if (d->hAlign == QQuickImage::AlignRight)
745 xOffset = qCeil(width() - pixWidth);
746
747 int yOffset = 0;
748 if (d->vAlign == QQuickImage::AlignVCenter)
749 yOffset = (height() - pixHeight) / 2;
750 else if (d->vAlign == QQuickImage::AlignBottom)
751 yOffset = qCeil(height() - pixHeight);
752
753 switch (d->fillMode) {
754 case Stretch:
755 targetRect = QRectF(0, 0, width(), height());
756 sourceRect = d->pix.rect();
757 break;
758
760 targetRect = QRectF(xOffset, yOffset, d->paintedWidth, d->paintedHeight);
761 sourceRect = d->pix.rect();
762 break;
763
764 case PreserveAspectCrop: {
765 targetRect = QRectF(0, 0, width(), height());
766 qreal wscale = width() / qreal(d->pix.width());
767 qreal hscale = height() / qreal(d->pix.height());
768
769 if (wscale > hscale) {
770 int src = (hscale / wscale) * qreal(d->pix.height());
771 int y = 0;
772 if (d->vAlign == QQuickImage::AlignVCenter)
773 y = qCeil((d->pix.height() - src) / 2.);
774 else if (d->vAlign == QQuickImage::AlignBottom)
775 y = qCeil(d->pix.height() - src);
776 sourceRect = QRectF(0, y, d->pix.width(), src);
777
778 } else {
779 int src = (wscale / hscale) * qreal(d->pix.width());
780 int x = 0;
781 if (d->hAlign == QQuickImage::AlignHCenter)
782 x = qCeil((d->pix.width() - src) / 2.);
783 else if (d->hAlign == QQuickImage::AlignRight)
784 x = qCeil(d->pix.width() - src);
785 sourceRect = QRectF(x, 0, src, d->pix.height());
786 }
787 }
788 break;
789
790 case Tile:
791 targetRect = QRectF(0, 0, width(), height());
792 sourceRect = QRectF(-xOffset, -yOffset, width(), height());
793 hWrap = QSGTexture::Repeat;
794 vWrap = QSGTexture::Repeat;
795 break;
796
797 case TileHorizontally:
798 targetRect = QRectF(0, 0, width(), height());
799 sourceRect = QRectF(-xOffset, 0, width(), d->pix.height());
800 hWrap = QSGTexture::Repeat;
801 break;
802
803 case TileVertically:
804 targetRect = QRectF(0, 0, width(), height());
805 sourceRect = QRectF(0, -yOffset, d->pix.width(), height());
806 vWrap = QSGTexture::Repeat;
807 break;
808
809 case Pad:
810 qreal w = qMin(qreal(pixWidth), width());
811 qreal h = qMin(qreal(pixHeight), height());
812 qreal x = (pixWidth > width()) ? -xOffset : 0;
813 qreal y = (pixHeight > height()) ? -yOffset : 0;
814 targetRect = QRectF(x + xOffset, y + yOffset, w, h);
815 sourceRect = QRectF(x, y, w, h);
816 break;
817 }
818
819 qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
820 qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
821 QRectF nsrect(sourceRect.x() / nsWidth,
822 sourceRect.y() / nsHeight,
823 sourceRect.width() / nsWidth,
824 sourceRect.height() / nsHeight);
825
826 if (targetRect.isEmpty()
827 || !qt_is_finite(targetRect.width()) || !qt_is_finite(targetRect.height())
828 || nsrect.isEmpty()
829 || !qt_is_finite(nsrect.width()) || !qt_is_finite(nsrect.height())) {
830 delete node;
831 return nullptr;
832 }
833
834 if (d->pixmapChanged) {
835 // force update the texture in the node to trigger reconstruction of
836 // geometry and the likes when a atlas segment has changed.
837 if (texture->isAtlasTexture() && (hWrap == QSGTexture::Repeat || vWrap == QSGTexture::Repeat || d->mipmap))
838 node->setTexture(texture->removedFromAtlas());
839 else
840 node->setTexture(texture);
841 d->pixmapChanged = false;
842 }
843
845 node->setHorizontalWrapMode(hWrap);
846 node->setVerticalWrapMode(vWrap);
848
849 node->setTargetRect(targetRect);
850 node->setInnerTargetRect(targetRect);
851 node->setSubSourceRect(nsrect);
852 node->setMirror(d->mirrorHorizontally, d->mirrorVertically);
853 node->setAntialiasing(d->antialiasing);
854 node->update();
855
856 return node;
857}
858
860{
861 Q_D(QQuickImage);
862 // PreserveAspectFit calculates the implicit size differently so we
863 // don't call our superclass pixmapChange(), since that would
864 // result in the implicit size being set incorrectly, then updated
865 // in updatePaintedGeometry()
866 if (d->fillMode != PreserveAspectFit)
869 d->pixmapChanged = true;
870
871 // When the pixmap changes, such as being deleted, we need to update the textures
872 update();
873}
874
876{
877 Q_D(const QQuickImage);
878 return d->vAlign;
879}
880
882{
883 Q_D(QQuickImage);
884 if (d->vAlign == align)
885 return;
886
887 d->vAlign = align;
888 update();
891}
892
894{
895 Q_D(const QQuickImage);
896 return d->hAlign;
897}
898
900{
901 Q_D(QQuickImage);
902 if (d->hAlign == align)
903 return;
904
905 d->hAlign = align;
906 update();
909}
910
928{
929 Q_D(const QQuickImage);
930 return d->mipmap;
931}
932
934{
935 Q_D(QQuickImage);
936 if (d->mipmap == use)
937 return;
938 d->mipmap = use;
939 emit mipmapChanged(d->mipmap);
940
941 d->pixmapChanged = true;
943 load();
944 update();
945}
946
970
971#include "moc_qquickimage_p_p.cpp"
972
973#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:64
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:76
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:77
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:483
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:647
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:658
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:655
constexpr QSizeF size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:721
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:966
Combined button and popup list for selecting options.
Definition image.cpp:4
#define qWarning
Definition qlogging.h:162
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:111
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:92
QObject::connect nullptr
widget render & pixmap
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent