Merge master <-> api_changes
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickimage.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickimage_p.h"
43 #include "qquickimage_p_p.h"
44
45 #include <QtQuick/qsgtextureprovider.h>
46
47 #include <QtQuick/private/qsgcontext_p.h>
48 #include <private/qsgadaptationlayer_p.h>
49
50 #include <QtGui/qpainter.h>
51 #include <qmath.h>
52
53 QT_BEGIN_NAMESPACE
54
55 class QQuickImageTextureProvider : public QSGTextureProvider
56 {
57     Q_OBJECT
58 public:
59     QQuickImageTextureProvider()
60         : m_texture(0)
61         , m_smooth(false)
62     {
63     }
64
65     QSGTexture *texture() const {
66
67         if (m_texture && m_texture->isAtlasTexture())
68             const_cast<QQuickImageTextureProvider *>(this)->m_texture = m_texture->removedFromAtlas();
69
70         if (m_texture) {
71             m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest);
72             m_texture->setMipmapFiltering(QSGTexture::Nearest);
73             m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
74             m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);
75         }
76         return m_texture;
77     }
78
79     friend class QQuickImage;
80
81     QSGTexture *m_texture;
82     bool m_smooth;
83 };
84
85 #include "qquickimage.moc"
86
87 QQuickImagePrivate::QQuickImagePrivate()
88     : fillMode(QQuickImage::Stretch)
89     , paintedWidth(0)
90     , paintedHeight(0)
91     , pixmapChanged(false)
92     , hAlign(QQuickImage::AlignHCenter)
93     , vAlign(QQuickImage::AlignVCenter)
94     , provider(0)
95 {
96 }
97
98 /*!
99     \qmlclass Image QQuickImage
100     \inqmlmodule QtQuick 2
101     \ingroup qml-basic-visual-elements
102     \brief The Image element displays an image in a declarative user interface
103     \inherits Item
104
105     The Image element is used to display images in a declarative user interface.
106
107     The source of the image is specified as a URL using the \l source property.
108     Images can be supplied in any of the standard image formats supported by Qt,
109     including bitmap formats such as PNG and JPEG, and vector graphics formats
110     such as SVG. If you need to display animated images, use the \l AnimatedImage
111     element.
112
113     If the \l{Item::width}{width} and \l{Item::height}{height} properties are not
114     specified, the Image element automatically uses the size of the loaded image.
115     By default, specifying the width and height of the element causes the image
116     to be scaled to that size. This behavior can be changed by setting the
117     \l fillMode property, allowing the image to be stretched and tiled instead.
118
119     \section1 Example Usage
120
121     The following example shows the simplest usage of the Image element.
122
123     \snippet doc/src/snippets/qml/image.qml document
124
125     \beginfloatleft
126     \image declarative-qtlogo.png
127     \endfloat
128
129     \clearfloat
130
131     \section1 Performance
132
133     By default, locally available images are loaded immediately, and the user interface
134     is blocked until loading is complete. If a large image is to be loaded, it may be
135     preferable to load the image in a low priority thread, by enabling the \l asynchronous
136     property.
137
138     If the image is obtained from a network rather than a local resource, it is
139     automatically loaded asynchronously, and the \l progress and \l status properties
140     are updated as appropriate.
141
142     Images are cached and shared internally, so if several Image elements have the same \l source,
143     only one copy of the image will be loaded.
144
145     \bold Note: Images are often the greatest user of memory in QML user interfaces.  It is recommended
146     that images which do not form part of the user interface have their
147     size bounded via the \l sourceSize property. This is especially important for content
148     that is loaded from external sources or provided by the user.
149
150     \sa {declarative/imageelements/image}{Image example}, QQmlImageProvider
151 */
152
153 QQuickImage::QQuickImage(QQuickItem *parent)
154     : QQuickImageBase(*(new QQuickImagePrivate), parent)
155 {
156 }
157
158 QQuickImage::QQuickImage(QQuickImagePrivate &dd, QQuickItem *parent)
159     : QQuickImageBase(dd, parent)
160 {
161 }
162
163 QQuickImage::~QQuickImage()
164 {
165     Q_D(QQuickImage);
166     if (d->provider)
167         d->provider->deleteLater();
168 }
169
170 void QQuickImagePrivate::setImage(const QImage &image)
171 {
172     Q_Q(QQuickImage);
173     pix.setImage(image);
174
175     q->pixmapChange();
176     status = pix.isNull() ? QQuickImageBase::Null : QQuickImageBase::Ready;
177
178     q->update();
179 }
180
181 /*!
182     \qmlproperty enumeration QtQuick2::Image::fillMode
183
184     Set this property to define what happens when the source image has a different size
185     than the item.
186
187     \list
188     \o Image.Stretch - the image is scaled to fit
189     \o Image.PreserveAspectFit - the image is scaled uniformly to fit without cropping
190     \o Image.PreserveAspectCrop - the image is scaled uniformly to fill, cropping if necessary
191     \o Image.Tile - the image is duplicated horizontally and vertically
192     \o Image.TileVertically - the image is stretched horizontally and tiled vertically
193     \o Image.TileHorizontally - the image is stretched vertically and tiled horizontally
194     \o Image.Pad - the image is not transformed
195     \endlist
196
197     \table
198
199     \row
200     \o \image declarative-qtlogo-stretch.png
201     \o Stretch (default)
202     \qml
203     Image {
204         width: 130; height: 100
205         smooth: true
206         source: "qtlogo.png"
207     }
208     \endqml
209
210     \row
211     \o \image declarative-qtlogo-preserveaspectfit.png
212     \o PreserveAspectFit
213     \qml
214     Image {
215         width: 130; height: 100
216         fillMode: Image.PreserveAspectFit
217         smooth: true
218         source: "qtlogo.png"
219     }
220     \endqml
221
222     \row
223     \o \image declarative-qtlogo-preserveaspectcrop.png
224     \o PreserveAspectCrop
225     \qml
226     Image {
227         width: 130; height: 100
228         fillMode: Image.PreserveAspectCrop
229         smooth: true
230         source: "qtlogo.png"
231         clip: true
232     }
233     \endqml
234
235     \row
236     \o \image declarative-qtlogo-tile.png
237     \o Tile
238     \qml
239     Image {
240         width: 120; height: 120
241         fillMode: Image.Tile
242         source: "qtlogo.png"
243     }
244     \endqml
245
246     \row
247     \o \image declarative-qtlogo-tilevertically.png
248     \o TileVertically
249     \qml
250     Image {
251         width: 120; height: 120
252         fillMode: Image.TileVertically
253         smooth: true
254         source: "qtlogo.png"
255     }
256     \endqml
257
258     \row
259     \o \image declarative-qtlogo-tilehorizontally.png
260     \o TileHorizontally
261     \qml
262     Image {
263         width: 120; height: 120
264         fillMode: Image.TileHorizontally
265         smooth: true
266         source: "qtlogo.png"
267     }
268     \endqml
269
270     \endtable
271
272     Note that \c clip is \c false by default which means that the element might
273     paint outside its bounding rectangle even if the fillMode is set to \c PreserveAspectCrop.
274
275     \sa {declarative/imageelements/image}{Image example}
276 */
277 QQuickImage::FillMode QQuickImage::fillMode() const
278 {
279     Q_D(const QQuickImage);
280     return d->fillMode;
281 }
282
283 void QQuickImage::setFillMode(FillMode mode)
284 {
285     Q_D(QQuickImage);
286     if (d->fillMode == mode)
287         return;
288     d->fillMode = mode;
289     update();
290     updatePaintedGeometry();
291     emit fillModeChanged();
292 }
293
294 /*!
295
296     \qmlproperty real QtQuick2::Image::paintedWidth
297     \qmlproperty real QtQuick2::Image::paintedHeight
298
299     These properties hold the size of the image that is actually painted.
300     In most cases it is the same as \c width and \c height, but when using a
301     \c fillMode \c PreserveAspectFit or \c fillMode \c PreserveAspectCrop
302     \c paintedWidth or \c paintedHeight can be smaller or larger than
303     \c width and \c height of the Image element.
304 */
305 qreal QQuickImage::paintedWidth() const
306 {
307     Q_D(const QQuickImage);
308     return d->paintedWidth;
309 }
310
311 qreal QQuickImage::paintedHeight() const
312 {
313     Q_D(const QQuickImage);
314     return d->paintedHeight;
315 }
316
317 /*!
318     \qmlproperty enumeration QtQuick2::Image::status
319
320     This property holds the status of image loading.  It can be one of:
321     \list
322     \o Image.Null - no image has been set
323     \o Image.Ready - the image has been loaded
324     \o Image.Loading - the image is currently being loaded
325     \o Image.Error - an error occurred while loading the image
326     \endlist
327
328     Use this status to provide an update or respond to the status change in some way.
329     For example, you could:
330
331     \list
332     \o Trigger a state change:
333     \qml
334         State { name: 'loaded'; when: image.status == Image.Ready }
335     \endqml
336
337     \o Implement an \c onStatusChanged signal handler:
338     \qml
339         Image {
340             id: image
341             onStatusChanged: if (image.status == Image.Ready) console.log('Loaded')
342         }
343     \endqml
344
345     \o Bind to the status value:
346     \qml
347         Text { text: image.status == Image.Ready ? 'Loaded' : 'Not loaded' }
348     \endqml
349     \endlist
350
351     \sa progress
352 */
353
354 /*!
355     \qmlproperty real QtQuick2::Image::progress
356
357     This property holds the progress of image loading, from 0.0 (nothing loaded)
358     to 1.0 (finished).
359
360     \sa status
361 */
362
363 /*!
364     \qmlproperty bool QtQuick2::Image::smooth
365
366     Set this property if you want the image to be smoothly filtered when scaled or
367     transformed.  Smooth filtering gives better visual quality, but is slower.  If
368     the image is displayed at its natural size, this property has no visual or
369     performance effect.
370
371     \note Generally scaling artifacts are only visible if the image is stationary on
372     the screen.  A common pattern when animating an image is to disable smooth
373     filtering at the beginning of the animation and reenable it at the conclusion.
374 */
375
376 /*!
377     \qmlproperty QSize QtQuick2::Image::sourceSize
378
379     This property holds the actual width and height of the loaded image.
380
381     Unlike the \l {Item::}{width} and \l {Item::}{height} properties, which scale
382     the painting of the image, this property sets the actual number of pixels
383     stored for the loaded image so that large images do not use more
384     memory than necessary. For example, this ensures the image in memory is no
385     larger than 1024x1024 pixels, regardless of the Image's \l {Item::}{width} and
386     \l {Item::}{height} values:
387
388     \code
389     Rectangle {
390         width: ...
391         height: ...
392
393         Image {
394            anchors.fill: parent
395            source: "reallyBigImage.jpg"
396            sourceSize.width: 1024
397            sourceSize.height: 1024
398         }
399     }
400     \endcode
401
402     If the image's actual size is larger than the sourceSize, the image is scaled down.
403     If only one dimension of the size is set to greater than 0, the
404     other dimension is set in proportion to preserve the source image's aspect ratio.
405     (The \l fillMode is independent of this.)
406
407     If both the sourceSize.width and sourceSize.height are set the image will be scaled
408     down to fit within the specified size, maintaining the image's aspect ratio.  The actual
409     size of the image after scaling is available via \l implicitWidth and \l implicitHeight.
410
411     If the source is an intrinsically scalable image (eg. SVG), this property
412     determines the size of the loaded image regardless of intrinsic size.
413     Avoid changing this property dynamically; rendering an SVG is \e slow compared
414     to an image.
415
416     If the source is a non-scalable image (eg. JPEG), the loaded image will
417     be no greater than this property specifies. For some formats (currently only JPEG),
418     the whole image will never actually be loaded into memory.
419
420     sourceSize can be cleared to the natural size of the image
421     by setting sourceSize to \c undefined.
422
423     \note \e {Changing this property dynamically causes the image source to be reloaded,
424     potentially even from the network, if it is not in the disk cache.}
425 */
426
427 /*!
428     \qmlproperty url QtQuick2::Image::source
429
430     Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt.
431
432     The URL may be absolute, or relative to the URL of the component.
433
434     \sa QQmlImageProvider
435 */
436
437 /*!
438     \qmlproperty bool QtQuick2::Image::asynchronous
439
440     Specifies that images on the local filesystem should be loaded
441     asynchronously in a separate thread.  The default value is
442     false, causing the user interface thread to block while the
443     image is loaded.  Setting \a asynchronous to true is useful where
444     maintaining a responsive user interface is more desirable
445     than having images immediately visible.
446
447     Note that this property is only valid for images read from the
448     local filesystem.  Images loaded via a network resource (e.g. HTTP)
449     are always loaded asynchronously.
450 */
451
452 /*!
453     \qmlproperty bool QtQuick2::Image::cache
454
455     Specifies whether the image should be cached. The default value is
456     true. Setting \a cache to false is useful when dealing with large images,
457     to make sure that they aren't cached at the expense of small 'ui element' images.
458 */
459
460 /*!
461     \qmlproperty bool QtQuick2::Image::mirror
462
463     This property holds whether the image should be horizontally inverted
464     (effectively displaying a mirrored image).
465
466     The default value is false.
467 */
468
469 /*!
470     \qmlproperty enumeration QtQuick2::Image::horizontalAlignment
471     \qmlproperty enumeration QtQuick2::Image::verticalAlignment
472
473     Sets the horizontal and vertical alignment of the image. By default, the image is top-left aligned.
474
475     The valid values for \c horizontalAlignment are \c Image.AlignLeft, \c Image.AlignRight and \c Image.AlignHCenter.
476     The valid values for \c verticalAlignment are \c Image.AlignTop, \c Image.AlignBottom
477     and \c Image.AlignVCenter.
478 */
479 void QQuickImage::updatePaintedGeometry()
480 {
481     Q_D(QQuickImage);
482
483     if (d->fillMode == PreserveAspectFit) {
484         if (!d->pix.width() || !d->pix.height()) {
485             setImplicitSize(0, 0);
486             return;
487         }
488         qreal w = widthValid() ? width() : d->pix.width();
489         qreal widthScale = w / qreal(d->pix.width());
490         qreal h = heightValid() ? height() : d->pix.height();
491         qreal heightScale = h / qreal(d->pix.height());
492         if (widthScale <= heightScale) {
493             d->paintedWidth = w;
494             d->paintedHeight = widthScale * qreal(d->pix.height());
495         } else if (heightScale < widthScale) {
496             d->paintedWidth = heightScale * qreal(d->pix.width());
497             d->paintedHeight = h;
498         }
499         qreal iHeight = (widthValid() && !heightValid()) ? d->paintedHeight : d->pix.height();
500         qreal iWidth = (heightValid() && !widthValid()) ? d->paintedWidth : d->pix.width();
501         setImplicitSize(iWidth, iHeight);
502
503     } else if (d->fillMode == PreserveAspectCrop) {
504         if (!d->pix.width() || !d->pix.height())
505             return;
506         qreal widthScale = width() / qreal(d->pix.width());
507         qreal heightScale = height() / qreal(d->pix.height());
508         if (widthScale < heightScale) {
509             widthScale = heightScale;
510         } else if (heightScale < widthScale) {
511             heightScale = widthScale;
512         }
513
514         d->paintedHeight = heightScale * qreal(d->pix.height());
515         d->paintedWidth = widthScale * qreal(d->pix.width());
516     } else if (d->fillMode == Pad) {
517         d->paintedWidth = d->pix.width();
518         d->paintedHeight = d->pix.height();
519     } else {
520         d->paintedWidth = width();
521         d->paintedHeight = height();
522     }
523     emit paintedGeometryChanged();
524 }
525
526 void QQuickImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
527 {
528     QQuickImageBase::geometryChanged(newGeometry, oldGeometry);
529     updatePaintedGeometry();
530 }
531
532 QRectF QQuickImage::boundingRect() const
533 {
534     Q_D(const QQuickImage);
535     return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
536 }
537
538 QSGTextureProvider *QQuickImage::textureProvider() const
539 {
540     Q_D(const QQuickImage);
541     if (!d->provider) {
542         // Make sure it gets thread affinity on the rendering thread so deletion works properly..
543         Q_ASSERT_X(d->canvas
544                    && d->sceneGraphContext()
545                    && QThread::currentThread() == d->sceneGraphContext()->thread(),
546                    "QQuickImage::textureProvider",
547                    "Cannot be used outside the GUI thread");
548         QQuickImagePrivate *dd = const_cast<QQuickImagePrivate *>(d);
549         dd->provider = new QQuickImageTextureProvider;
550         dd->provider->m_smooth = d->smooth;
551         dd->provider->m_texture = d->sceneGraphContext()->textureForFactory(d->pix.textureFactory(), canvas());
552     }
553
554     return d->provider;
555 }
556
557 QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
558 {
559     Q_D(QQuickImage);
560
561     QSGTexture *texture = d->sceneGraphContext()->textureForFactory(d->pix.textureFactory(), canvas());
562
563     // Copy over the current texture state into the texture provider...
564     if (d->provider) {
565         d->provider->m_smooth = d->smooth;
566         d->provider->m_texture = texture;
567     }
568
569     if (!texture || width() <= 0 || height() <= 0) {
570         delete oldNode;
571         return 0;
572     }
573
574     QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
575     if (!node) {
576         d->pixmapChanged = true;
577         node = d->sceneGraphContext()->createImageNode();
578         node->setTexture(texture);
579     }
580
581     if (d->pixmapChanged) {
582         // force update the texture in the node to trigger reconstruction of
583         // geometry and the likes when a atlas segment has changed.
584         node->setTexture(0);
585         node->setTexture(texture);
586         d->pixmapChanged = false;
587     }
588
589     QRectF targetRect;
590     QRectF sourceRect;
591     QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
592     QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
593
594     qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width();
595     qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->pix.height();
596
597     int xOffset = 0;
598     if (d->hAlign == QQuickImage::AlignHCenter)
599         xOffset = qCeil((width() - pixWidth) / 2.);
600     else if (d->hAlign == QQuickImage::AlignRight)
601         xOffset = qCeil(width() - pixWidth);
602
603     int yOffset = 0;
604     if (d->vAlign == QQuickImage::AlignVCenter)
605         yOffset = qCeil((height() - pixHeight) / 2.);
606     else if (d->vAlign == QQuickImage::AlignBottom)
607         yOffset = qCeil(height() - pixHeight);
608
609     switch (d->fillMode) {
610     default:
611     case Stretch:
612         targetRect = QRectF(0, 0, width(), height());
613         sourceRect = d->pix.rect();
614         break;
615
616     case PreserveAspectFit:
617         targetRect = QRectF(xOffset, yOffset, d->paintedWidth, d->paintedHeight);
618         sourceRect = d->pix.rect();
619         break;
620
621     case PreserveAspectCrop: {
622         targetRect = QRect(0, 0, width(), height());
623         qreal wscale = width() / qreal(d->pix.width());
624         qreal hscale = height() / qreal(d->pix.height());
625
626         if (wscale > hscale) {
627             int src = (hscale / wscale) * qreal(d->pix.height());
628             int y = 0;
629             if (d->vAlign == QQuickImage::AlignVCenter)
630                 y = qCeil((d->pix.height() - src) / 2.);
631             else if (d->vAlign == QQuickImage::AlignBottom)
632                 y = qCeil(d->pix.height() - src);
633             sourceRect = QRectF(0, y, d->pix.width(), src);
634
635         } else {
636             int src = (wscale / hscale) * qreal(d->pix.width());
637             int x = 0;
638             if (d->hAlign == QQuickImage::AlignHCenter)
639                 x = qCeil((d->pix.width() - src) / 2.);
640             else if (d->hAlign == QQuickImage::AlignRight)
641                 x = qCeil(d->pix.width() - src);
642             sourceRect = QRectF(x, 0, src, d->pix.height());
643         }
644         }
645         break;
646
647     case Tile:
648         targetRect = QRectF(0, 0, width(), height());
649         sourceRect = QRectF(-xOffset, -yOffset, width(), height());
650         hWrap = QSGTexture::Repeat;
651         vWrap = QSGTexture::Repeat;
652         break;
653
654     case TileHorizontally:
655         targetRect = QRectF(0, 0, width(), height());
656         sourceRect = QRectF(-xOffset, 0, width(), d->pix.height());
657         hWrap = QSGTexture::Repeat;
658         break;
659
660     case TileVertically:
661         targetRect = QRectF(0, 0, width(), height());
662         sourceRect = QRectF(0, -yOffset, d->pix.width(), height());
663         vWrap = QSGTexture::Repeat;
664         break;
665
666     case Pad:
667         qreal w = qMin(qreal(d->pix.width()), width());
668         qreal h = qMin(qreal(d->pix.height()), height());
669         qreal x = (d->pix.width() > width()) ? -xOffset : 0;
670         qreal y = (d->pix.height() > height()) ? -yOffset : 0;
671         targetRect = QRectF(x + xOffset, y + yOffset, w, h);
672         sourceRect = QRectF(x, y, w, h);
673         break;
674     };
675
676     QRectF nsrect(sourceRect.x() / d->pix.width(),
677                   sourceRect.y() / d->pix.height(),
678                   sourceRect.width() / d->pix.width(),
679                   sourceRect.height() / d->pix.height());
680
681     if (d->mirror) {
682         qreal oldLeft = nsrect.left();
683         nsrect.setLeft(nsrect.right());
684         nsrect.setRight(oldLeft);
685     }
686
687     node->setHorizontalWrapMode(hWrap);
688     node->setVerticalWrapMode(vWrap);
689     node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
690
691     node->setTargetRect(targetRect);
692     node->setSourceRect(nsrect);
693     node->update();
694
695     return node;
696 }
697
698 void QQuickImage::pixmapChange()
699 {
700     Q_D(QQuickImage);
701     // PreserveAspectFit calculates the implicit size differently so we
702     // don't call our superclass pixmapChange(), since that would
703     // result in the implicit size being set incorrectly, then updated
704     // in updatePaintedGeometry()
705     if (d->fillMode != PreserveAspectFit)
706         QQuickImageBase::pixmapChange();
707     updatePaintedGeometry();
708     d->pixmapChanged = true;
709
710     // When the pixmap changes, such as being deleted, we need to update the textures
711     update();
712 }
713
714 QQuickImage::VAlignment QQuickImage::verticalAlignment() const
715 {
716     Q_D(const QQuickImage);
717     return d->vAlign;
718 }
719
720 void QQuickImage::setVerticalAlignment(VAlignment align)
721 {
722     Q_D(QQuickImage);
723     if (d->vAlign == align)
724         return;
725
726     d->vAlign = align;
727     update();
728     updatePaintedGeometry();
729     emit verticalAlignmentChanged(align);
730 }
731
732 QQuickImage::HAlignment QQuickImage::horizontalAlignment() const
733 {
734     Q_D(const QQuickImage);
735     return d->hAlign;
736 }
737
738 void QQuickImage::setHorizontalAlignment(HAlignment align)
739 {
740     Q_D(QQuickImage);
741     if (d->hAlign == align)
742         return;
743
744     d->hAlign = align;
745     update();
746     updatePaintedGeometry();
747     emit horizontalAlignmentChanged(align);
748 }
749
750 QT_END_NAMESPACE