Initial import from qtquick2.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgimage.cpp
1 // Commit: 695a39410c8ce186a2ce78cef51093c55fc32643
2 /****************************************************************************
3 **
4 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 **
8 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** No Commercial Usage
12 ** This file contains pre-release code and may not be distributed.
13 ** You may use this file in accordance with the terms and conditions
14 ** contained in the Technology Preview License Agreement accompanying
15 ** this package.
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 **
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42
43 #include "qsgimage_p.h"
44 #include "qsgimage_p_p.h"
45
46 #include <private/qsgcontext_p.h>
47 #include <private/qsgadaptationlayer_p.h>
48
49 #include <QtGui/qpainter.h>
50
51 QT_BEGIN_NAMESPACE
52
53 QSGImagePrivate::QSGImagePrivate()
54     : fillMode(QSGImage::Stretch)
55     , paintedWidth(0)
56     , paintedHeight(0)
57     , pixmapChanged(false)
58 {
59 }
60
61 QSGImage::QSGImage(QSGItem *parent)
62     : QSGImageBase(*(new QSGImagePrivate), parent)
63 {
64 }
65
66 QSGImage::QSGImage(QSGImagePrivate &dd, QSGItem *parent)
67     : QSGImageBase(dd, parent)
68 {
69 }
70
71 QSGImage::~QSGImage()
72 {
73 }
74
75 void QSGImagePrivate::setPixmap(const QPixmap &pixmap)
76 {
77     Q_Q(QSGImage);
78     pix.setPixmap(pixmap);
79
80     q->setImplicitWidth(pix.width());
81     q->setImplicitHeight(pix.height());
82     status = pix.isNull() ? QSGImageBase::Null : QSGImageBase::Ready;
83
84     q->update();
85     q->pixmapChange();
86 }
87
88 QSGImage::FillMode QSGImage::fillMode() const
89 {
90     Q_D(const QSGImage);
91     return d->fillMode;
92 }
93
94 void QSGImage::setFillMode(FillMode mode)
95 {
96     Q_D(QSGImage);
97     if (d->fillMode == mode)
98         return;
99     d->fillMode = mode;
100     update();
101     updatePaintedGeometry();
102     emit fillModeChanged();
103 }
104
105 qreal QSGImage::paintedWidth() const
106 {
107     Q_D(const QSGImage);
108     return d->paintedWidth;
109 }
110
111 qreal QSGImage::paintedHeight() const
112 {
113     Q_D(const QSGImage);
114     return d->paintedHeight;
115 }
116
117 void QSGImage::updatePaintedGeometry()
118 {
119     Q_D(QSGImage);
120
121     if (d->fillMode == PreserveAspectFit) {
122         if (!d->pix.width() || !d->pix.height())
123             return;
124         qreal w = widthValid() ? width() : d->pix.width();
125         qreal widthScale = w / qreal(d->pix.width());
126         qreal h = heightValid() ? height() : d->pix.height();
127         qreal heightScale = h / qreal(d->pix.height());
128         if (widthScale <= heightScale) {
129             d->paintedWidth = w;
130             d->paintedHeight = widthScale * qreal(d->pix.height());
131         } else if(heightScale < widthScale) {
132             d->paintedWidth = heightScale * qreal(d->pix.width());
133             d->paintedHeight = h;
134         }
135         if (widthValid() && !heightValid()) {
136             setImplicitHeight(d->paintedHeight);
137         }
138         if (heightValid() && !widthValid()) {
139             setImplicitWidth(d->paintedWidth);
140         }
141     } else if (d->fillMode == PreserveAspectCrop) {
142         if (!d->pix.width() || !d->pix.height())
143             return;
144         qreal widthScale = width() / qreal(d->pix.width());
145         qreal heightScale = height() / qreal(d->pix.height());
146         if (widthScale < heightScale) {
147             widthScale = heightScale;
148         } else if(heightScale < widthScale) {
149             heightScale = widthScale;
150         }
151
152         d->paintedHeight = heightScale * qreal(d->pix.height());
153         d->paintedWidth = widthScale * qreal(d->pix.width());
154     } else {
155         d->paintedWidth = width();
156         d->paintedHeight = height();
157     }
158     emit paintedGeometryChanged();
159 }
160
161 void QSGImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
162 {
163     QSGImageBase::geometryChanged(newGeometry, oldGeometry);
164     updatePaintedGeometry();
165 }
166
167 QRectF QSGImage::boundingRect() const
168 {
169     Q_D(const QSGImage);
170     return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
171 }
172
173 QSGTexture *QSGImage::texture() const
174 {
175     Q_D(const QSGImage);
176     QSGTexture *t = d->pix.texture();
177     t->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
178     t->setMipmapFiltering(QSGTexture::None);
179     t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
180     t->setVerticalWrapMode(QSGTexture::ClampToEdge);
181     return t;
182 }
183
184 QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
185 {
186     Q_D(QSGImage);
187     //XXX Support mirror property
188
189     if (!d->pix.texture() || width() <= 0 || height() <= 0) {
190         delete oldNode;
191         return 0;
192     }
193
194     QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
195     if (!node) { 
196         d->pixmapChanged = true;
197         node = d->sceneGraphContext()->createImageNode();
198         node->setTexture(d->pix.texture());
199     }
200
201     if (d->pixmapChanged) {
202         // force update the texture in the node to trigger reconstruction of
203         // geometry and the likes when a atlas segment has changed.
204         QSGTexture *t = d->pix.texture();
205         node->setTexture(0);
206         node->setTexture(t);
207         d->pixmapChanged = false;
208     }
209
210     QRectF targetRect;
211     QRectF sourceRect;
212     QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
213     QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
214
215     switch (d->fillMode) {
216     default:
217     case Stretch:
218         targetRect = QRectF(0, 0, width(), height());
219         sourceRect = d->pix.rect();
220         break;
221
222     case PreserveAspectFit:
223         targetRect = QRectF((width() - d->paintedWidth) / 2., (height() - d->paintedHeight) / 2.,
224                             d->paintedWidth, d->paintedHeight);
225         sourceRect = d->pix.rect();
226         break;
227
228     case PreserveAspectCrop: {
229         targetRect = QRect(0, 0, width(), height());
230         qreal wscale = width() / qreal(d->pix.width());
231         qreal hscale = height() / qreal(d->pix.height());
232
233         if (wscale > hscale) {
234             int src = (hscale / wscale) * qreal(d->pix.height());
235             sourceRect = QRectF(0, (d->pix.height() - src) / 2, d->pix.width(), src);
236         } else {
237             int src = (wscale / hscale) * qreal(d->pix.width());
238             sourceRect = QRectF((d->pix.width() - src) / 2, 0, src, d->pix.height());
239         }
240     }
241         break;
242
243     case Tile:
244         targetRect = QRectF(0, 0, width(), height());
245         sourceRect = QRectF(0, 0, width(), height());
246         hWrap = QSGTexture::Repeat;
247         vWrap = QSGTexture::Repeat;
248         break;
249
250     case TileHorizontally:
251         targetRect = QRectF(0, 0, width(), height());
252         sourceRect = QRectF(0, 0, width(), d->pix.height());
253         hWrap = QSGTexture::Repeat;
254         break;
255
256     case TileVertically:
257         targetRect = QRectF(0, 0, width(), height());
258         sourceRect = QRectF(0, 0, d->pix.width(), height());
259         vWrap = QSGTexture::Repeat;
260         break;
261
262     };
263
264     QRectF nsrect(sourceRect.x() / d->pix.width(),
265                   1 - sourceRect.y() / d->pix.height(),
266                   sourceRect.width() / d->pix.width(),
267                   -sourceRect.height() / d->pix.height());
268
269     node->setHorizontalWrapMode(hWrap);
270     node->setVerticalWrapMode(vWrap);
271     node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
272
273     node->setTargetRect(targetRect);
274     node->setSourceRect(nsrect);
275     node->update();
276
277     return node;
278 }
279
280 void QSGImage::pixmapChange()
281 {
282     Q_D(QSGImage);
283
284     updatePaintedGeometry();
285     d->pixmapChanged = true;
286 }
287
288 QT_END_NAMESPACE