aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/items/qsgimage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/items/qsgimage.cpp')
-rw-r--r--src/declarative/items/qsgimage.cpp306
1 files changed, 306 insertions, 0 deletions
diff --git a/src/declarative/items/qsgimage.cpp b/src/declarative/items/qsgimage.cpp
new file mode 100644
index 0000000000..706aaa7d5d
--- /dev/null
+++ b/src/declarative/items/qsgimage.cpp
@@ -0,0 +1,306 @@
+// Commit: 051a76c1d65d698f71dc75c89f91ae9021357eae
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgimage_p.h"
+#include "qsgimage_p_p.h"
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+
+#include <QtGui/qpainter.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGImagePrivate::QSGImagePrivate()
+ : fillMode(QSGImage::Stretch)
+ , paintedWidth(0)
+ , paintedHeight(0)
+ , pixmapChanged(false)
+{
+}
+
+QSGImage::QSGImage(QSGItem *parent)
+ : QSGImageBase(*(new QSGImagePrivate), parent)
+{
+}
+
+QSGImage::QSGImage(QSGImagePrivate &dd, QSGItem *parent)
+ : QSGImageBase(dd, parent)
+{
+}
+
+QSGImage::~QSGImage()
+{
+}
+
+void QSGImagePrivate::setPixmap(const QPixmap &pixmap)
+{
+ Q_Q(QSGImage);
+ pix.setPixmap(pixmap);
+
+ q->pixmapChange();
+ status = pix.isNull() ? QSGImageBase::Null : QSGImageBase::Ready;
+
+ q->update();
+}
+
+QSGImage::FillMode QSGImage::fillMode() const
+{
+ Q_D(const QSGImage);
+ return d->fillMode;
+}
+
+void QSGImage::setFillMode(FillMode mode)
+{
+ Q_D(QSGImage);
+ if (d->fillMode == mode)
+ return;
+ d->fillMode = mode;
+ update();
+ updatePaintedGeometry();
+ emit fillModeChanged();
+}
+
+qreal QSGImage::paintedWidth() const
+{
+ Q_D(const QSGImage);
+ return d->paintedWidth;
+}
+
+qreal QSGImage::paintedHeight() const
+{
+ Q_D(const QSGImage);
+ return d->paintedHeight;
+}
+
+void QSGImage::updatePaintedGeometry()
+{
+ Q_D(QSGImage);
+
+ if (d->fillMode == PreserveAspectFit) {
+ if (!d->pix.width() || !d->pix.height()) {
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+ return;
+ }
+ qreal w = widthValid() ? width() : d->pix.width();
+ qreal widthScale = w / qreal(d->pix.width());
+ qreal h = heightValid() ? height() : d->pix.height();
+ qreal heightScale = h / qreal(d->pix.height());
+ if (widthScale <= heightScale) {
+ d->paintedWidth = w;
+ d->paintedHeight = widthScale * qreal(d->pix.height());
+ } else if(heightScale < widthScale) {
+ d->paintedWidth = heightScale * qreal(d->pix.width());
+ d->paintedHeight = h;
+ }
+ if (widthValid() && !heightValid()) {
+ setImplicitHeight(d->paintedHeight);
+ } else {
+ setImplicitHeight(d->pix.height());
+ }
+ if (heightValid() && !widthValid()) {
+ setImplicitWidth(d->paintedWidth);
+ } else {
+ setImplicitWidth(d->pix.width());
+ }
+ } else if (d->fillMode == PreserveAspectCrop) {
+ if (!d->pix.width() || !d->pix.height())
+ return;
+ qreal widthScale = width() / qreal(d->pix.width());
+ qreal heightScale = height() / qreal(d->pix.height());
+ if (widthScale < heightScale) {
+ widthScale = heightScale;
+ } else if(heightScale < widthScale) {
+ heightScale = widthScale;
+ }
+
+ d->paintedHeight = heightScale * qreal(d->pix.height());
+ d->paintedWidth = widthScale * qreal(d->pix.width());
+ } else {
+ d->paintedWidth = width();
+ d->paintedHeight = height();
+ }
+ emit paintedGeometryChanged();
+}
+
+void QSGImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QSGImageBase::geometryChanged(newGeometry, oldGeometry);
+ updatePaintedGeometry();
+}
+
+QRectF QSGImage::boundingRect() const
+{
+ Q_D(const QSGImage);
+ return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
+}
+
+QSGTexture *QSGImage::texture() const
+{
+ Q_D(const QSGImage);
+ QSGTexture *t = d->pix.texture(d->sceneGraphContext());
+ if (t) {
+ t->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ t->setMipmapFiltering(QSGTexture::None);
+ t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ }
+ return t;
+}
+
+QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ Q_D(QSGImage);
+
+ QSGTexture *texture = d->pix.texture(d->sceneGraphContext());
+
+ if (!texture || width() <= 0 || height() <= 0) {
+ delete oldNode;
+ return 0;
+ }
+
+ QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
+ if (!node) {
+ d->pixmapChanged = true;
+ node = d->sceneGraphContext()->createImageNode();
+ node->setTexture(texture);
+ }
+
+ if (d->pixmapChanged) {
+ // force update the texture in the node to trigger reconstruction of
+ // geometry and the likes when a atlas segment has changed.
+ node->setTexture(0);
+ node->setTexture(texture);
+ d->pixmapChanged = false;
+ }
+
+ QRectF targetRect;
+ QRectF sourceRect;
+ QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
+ QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
+
+ switch (d->fillMode) {
+ default:
+ case Stretch:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = d->pix.rect();
+ break;
+
+ case PreserveAspectFit:
+ targetRect = QRectF((width() - d->paintedWidth) / 2., (height() - d->paintedHeight) / 2.,
+ d->paintedWidth, d->paintedHeight);
+ sourceRect = d->pix.rect();
+ break;
+
+ case PreserveAspectCrop: {
+ targetRect = QRect(0, 0, width(), height());
+ qreal wscale = width() / qreal(d->pix.width());
+ qreal hscale = height() / qreal(d->pix.height());
+
+ if (wscale > hscale) {
+ int src = (hscale / wscale) * qreal(d->pix.height());
+ sourceRect = QRectF(0, (d->pix.height() - src) / 2, d->pix.width(), src);
+ } else {
+ int src = (wscale / hscale) * qreal(d->pix.width());
+ sourceRect = QRectF((d->pix.width() - src) / 2, 0, src, d->pix.height());
+ }
+ }
+ break;
+
+ case Tile:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, width(), height());
+ hWrap = QSGTexture::Repeat;
+ vWrap = QSGTexture::Repeat;
+ break;
+
+ case TileHorizontally:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, width(), d->pix.height());
+ hWrap = QSGTexture::Repeat;
+ break;
+
+ case TileVertically:
+ targetRect = QRectF(0, 0, width(), height());
+ sourceRect = QRectF(0, 0, d->pix.width(), height());
+ vWrap = QSGTexture::Repeat;
+ break;
+
+ };
+
+ QRectF nsrect(sourceRect.x() / d->pix.width(),
+ sourceRect.y() / d->pix.height(),
+ sourceRect.width() / d->pix.width(),
+ sourceRect.height() / d->pix.height());
+
+ if (d->mirror) {
+ qreal oldLeft = nsrect.left();
+ nsrect.setLeft(nsrect.right());
+ nsrect.setRight(oldLeft);
+ }
+
+ node->setHorizontalWrapMode(hWrap);
+ node->setVerticalWrapMode(vWrap);
+ node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+
+ node->setTargetRect(targetRect);
+ node->setSourceRect(nsrect);
+ node->update();
+
+ return node;
+}
+
+void QSGImage::pixmapChange()
+{
+ Q_D(QSGImage);
+ // PreserveAspectFit calculates the implicit size differently so we
+ // don't call our superclass pixmapChange(), since that would
+ // result in the implicit size being set incorrectly, then updated
+ // in updatePaintedGeometry()
+ if (d->fillMode != PreserveAspectFit)
+ QSGImageBase::pixmapChange();
+ updatePaintedGeometry();
+ d->pixmapChanged = true;
+}
+
+QT_END_NAMESPACE