Pass the QQuickCanvas to texture factories.
[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 QtDeclarative 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/declarative/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}, QDeclarativeImageProvider
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 the source is an intrinsically scalable image (eg. SVG), this property
408     determines the size of the loaded image regardless of intrinsic size.
409     Avoid changing this property dynamically; rendering an SVG is \e slow compared
410     to an image.
411
412     If the source is a non-scalable image (eg. JPEG), the loaded image will
413     be no greater than this property specifies. For some formats (currently only JPEG),
414     the whole image will never actually be loaded into memory.
415
416     Since QtQuick 1.1 the sourceSize can be cleared to the natural size of the image
417     by setting sourceSize to \c undefined.
418
419     \note \e {Changing this property dynamically causes the image source to be reloaded,
420     potentially even from the network, if it is not in the disk cache.}
421 */
422
423 /*!
424     \qmlproperty url QtQuick2::Image::source
425
426     Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt.
427
428     The URL may be absolute, or relative to the URL of the component.
429
430     \sa QDeclarativeImageProvider
431 */
432
433 /*!
434     \qmlproperty bool QtQuick2::Image::asynchronous
435
436     Specifies that images on the local filesystem should be loaded
437     asynchronously in a separate thread.  The default value is
438     false, causing the user interface thread to block while the
439     image is loaded.  Setting \a asynchronous to true is useful where
440     maintaining a responsive user interface is more desirable
441     than having images immediately visible.
442
443     Note that this property is only valid for images read from the
444     local filesystem.  Images loaded via a network resource (e.g. HTTP)
445     are always loaded asynchronously.
446 */
447
448 /*!
449     \qmlproperty bool QtQuick2::Image::cache
450
451     Specifies whether the image should be cached. The default value is
452     true. Setting \a cache to false is useful when dealing with large images,
453     to make sure that they aren't cached at the expense of small 'ui element' images.
454 */
455
456 /*!
457     \qmlproperty bool QtQuick2::Image::mirror
458
459     This property holds whether the image should be horizontally inverted
460     (effectively displaying a mirrored image).
461
462     The default value is false.
463 */
464
465 /*!
466     \qmlproperty enumeration QtQuick2::Image::horizontalAlignment
467     \qmlproperty enumeration QtQuick2::Image::verticalAlignment
468
469     Sets the horizontal and vertical alignment of the image. By default, the image is top-left aligned.
470
471     The valid values for \c horizontalAlignment are \c Image.AlignLeft, \c Image.AlignRight and \c Image.AlignHCenter.
472     The valid values for \c verticalAlignment are \c Image.AlignTop, \c Image.AlignBottom
473     and \c Image.AlignVCenter.
474 */
475 void QQuickImage::updatePaintedGeometry()
476 {
477     Q_D(QQuickImage);
478
479     if (d->fillMode == PreserveAspectFit) {
480         if (!d->pix.width() || !d->pix.height()) {
481             setImplicitSize(0, 0);
482             return;
483         }
484         qreal w = widthValid() ? width() : d->pix.width();
485         qreal widthScale = w / qreal(d->pix.width());
486         qreal h = heightValid() ? height() : d->pix.height();
487         qreal heightScale = h / qreal(d->pix.height());
488         if (widthScale <= heightScale) {
489             d->paintedWidth = w;
490             d->paintedHeight = widthScale * qreal(d->pix.height());
491         } else if (heightScale < widthScale) {
492             d->paintedWidth = heightScale * qreal(d->pix.width());
493             d->paintedHeight = h;
494         }
495         qreal iHeight = (widthValid() && !heightValid()) ? d->paintedHeight : d->pix.height();
496         qreal iWidth = (heightValid() && !widthValid()) ? d->paintedWidth : d->pix.width();
497         setImplicitSize(iWidth, iHeight);
498
499     } else if (d->fillMode == PreserveAspectCrop) {
500         if (!d->pix.width() || !d->pix.height())
501             return;
502         qreal widthScale = width() / qreal(d->pix.width());
503         qreal heightScale = height() / qreal(d->pix.height());
504         if (widthScale < heightScale) {
505             widthScale = heightScale;
506         } else if (heightScale < widthScale) {
507             heightScale = widthScale;
508         }
509
510         d->paintedHeight = heightScale * qreal(d->pix.height());
511         d->paintedWidth = widthScale * qreal(d->pix.width());
512     } else if (d->fillMode == Pad) {
513         d->paintedWidth = d->pix.width();
514         d->paintedHeight = d->pix.height();
515     } else {
516         d->paintedWidth = width();
517         d->paintedHeight = height();
518     }
519     emit paintedGeometryChanged();
520 }
521
522 void QQuickImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
523 {
524     QQuickImageBase::geometryChanged(newGeometry, oldGeometry);
525     updatePaintedGeometry();
526 }
527
528 QRectF QQuickImage::boundingRect() const
529 {
530     Q_D(const QQuickImage);
531     return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
532 }
533
534 QSGTextureProvider *QQuickImage::textureProvider() const
535 {
536     Q_D(const QQuickImage);
537     if (!d->provider) {
538         // Make sure it gets thread affinity on the rendering thread so deletion works properly..
539         Q_ASSERT_X(d->canvas
540                    && d->sceneGraphContext()
541                    && QThread::currentThread() == d->sceneGraphContext()->thread(),
542                    "QQuickImage::textureProvider",
543                    "Cannot be used outside the GUI thread");
544         QQuickImagePrivate *dd = const_cast<QQuickImagePrivate *>(d);
545         dd->provider = new QQuickImageTextureProvider;
546         dd->provider->m_smooth = d->smooth;
547         dd->provider->m_texture = d->sceneGraphContext()->textureForFactory(d->pix.textureFactory(), canvas());
548     }
549
550     return d->provider;
551 }
552
553 QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
554 {
555     Q_D(QQuickImage);
556
557     QSGTexture *texture = d->sceneGraphContext()->textureForFactory(d->pix.textureFactory(), canvas());
558
559     // Copy over the current texture state into the texture provider...
560     if (d->provider) {
561         d->provider->m_smooth = d->smooth;
562         d->provider->m_texture = texture;
563     }
564
565     if (!texture || width() <= 0 || height() <= 0) {
566         delete oldNode;
567         return 0;
568     }
569
570     QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
571     if (!node) {
572         d->pixmapChanged = true;
573         node = d->sceneGraphContext()->createImageNode();
574         node->setTexture(texture);
575     }
576
577     if (d->pixmapChanged) {
578         // force update the texture in the node to trigger reconstruction of
579         // geometry and the likes when a atlas segment has changed.
580         node->setTexture(0);
581         node->setTexture(texture);
582         d->pixmapChanged = false;
583     }
584
585     QRectF targetRect;
586     QRectF sourceRect;
587     QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
588     QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
589
590     qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width();
591     qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->pix.height();
592
593     int xOffset = 0;
594     if (d->hAlign == QQuickImage::AlignHCenter)
595         xOffset = qCeil((width() - pixWidth) / 2.);
596     else if (d->hAlign == QQuickImage::AlignRight)
597         xOffset = qCeil(width() - pixWidth);
598
599     int yOffset = 0;
600     if (d->vAlign == QQuickImage::AlignVCenter)
601         yOffset = qCeil((height() - pixHeight) / 2.);
602     else if (d->vAlign == QQuickImage::AlignBottom)
603         yOffset = qCeil(height() - pixHeight);
604
605     switch (d->fillMode) {
606     default:
607     case Stretch:
608         targetRect = QRectF(0, 0, width(), height());
609         sourceRect = d->pix.rect();
610         break;
611
612     case PreserveAspectFit:
613         targetRect = QRectF(xOffset, yOffset, d->paintedWidth, d->paintedHeight);
614         sourceRect = d->pix.rect();
615         break;
616
617     case PreserveAspectCrop: {
618         targetRect = QRect(0, 0, width(), height());
619         qreal wscale = width() / qreal(d->pix.width());
620         qreal hscale = height() / qreal(d->pix.height());
621
622         if (wscale > hscale) {
623             int src = (hscale / wscale) * qreal(d->pix.height());
624             int y = 0;
625             if (d->vAlign == QQuickImage::AlignVCenter)
626                 y = qCeil((d->pix.height() - src) / 2.);
627             else if (d->vAlign == QQuickImage::AlignBottom)
628                 y = qCeil(d->pix.height() - src);
629             sourceRect = QRectF(0, y, d->pix.width(), src);
630
631         } else {
632             int src = (wscale / hscale) * qreal(d->pix.width());
633             int x = 0;
634             if (d->hAlign == QQuickImage::AlignHCenter)
635                 x = qCeil((d->pix.width() - src) / 2.);
636             else if (d->hAlign == QQuickImage::AlignRight)
637                 x = qCeil(d->pix.width() - src);
638             sourceRect = QRectF(x, 0, src, d->pix.height());
639         }
640         }
641         break;
642
643     case Tile:
644         targetRect = QRectF(0, 0, width(), height());
645         sourceRect = QRectF(-xOffset, -yOffset, width(), height());
646         hWrap = QSGTexture::Repeat;
647         vWrap = QSGTexture::Repeat;
648         break;
649
650     case TileHorizontally:
651         targetRect = QRectF(0, 0, width(), height());
652         sourceRect = QRectF(-xOffset, 0, width(), d->pix.height());
653         hWrap = QSGTexture::Repeat;
654         break;
655
656     case TileVertically:
657         targetRect = QRectF(0, 0, width(), height());
658         sourceRect = QRectF(0, -yOffset, d->pix.width(), height());
659         vWrap = QSGTexture::Repeat;
660         break;
661
662     case Pad:
663         qreal w = qMin(qreal(d->pix.width()), width());
664         qreal h = qMin(qreal(d->pix.height()), height());
665         qreal x = (d->pix.width() > width()) ? -xOffset : 0;
666         qreal y = (d->pix.height() > height()) ? -yOffset : 0;
667         targetRect = QRectF(x + xOffset, y + yOffset, w, h);
668         sourceRect = QRectF(x, y, w, h);
669         break;
670     };
671
672     QRectF nsrect(sourceRect.x() / d->pix.width(),
673                   sourceRect.y() / d->pix.height(),
674                   sourceRect.width() / d->pix.width(),
675                   sourceRect.height() / d->pix.height());
676
677     if (d->mirror) {
678         qreal oldLeft = nsrect.left();
679         nsrect.setLeft(nsrect.right());
680         nsrect.setRight(oldLeft);
681     }
682
683     node->setHorizontalWrapMode(hWrap);
684     node->setVerticalWrapMode(vWrap);
685     node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
686
687     node->setTargetRect(targetRect);
688     node->setSourceRect(nsrect);
689     node->update();
690
691     return node;
692 }
693
694 void QQuickImage::pixmapChange()
695 {
696     Q_D(QQuickImage);
697     // PreserveAspectFit calculates the implicit size differently so we
698     // don't call our superclass pixmapChange(), since that would
699     // result in the implicit size being set incorrectly, then updated
700     // in updatePaintedGeometry()
701     if (d->fillMode != PreserveAspectFit)
702         QQuickImageBase::pixmapChange();
703     updatePaintedGeometry();
704     d->pixmapChanged = true;
705
706     // When the pixmap changes, such as being deleted, we need to update the textures
707     update();
708 }
709
710 QQuickImage::VAlignment QQuickImage::verticalAlignment() const
711 {
712     Q_D(const QQuickImage);
713     return d->vAlign;
714 }
715
716 void QQuickImage::setVerticalAlignment(VAlignment align)
717 {
718     Q_D(QQuickImage);
719     if (d->vAlign == align)
720         return;
721
722     d->vAlign = align;
723     update();
724     updatePaintedGeometry();
725     emit verticalAlignmentChanged(align);
726 }
727
728 QQuickImage::HAlignment QQuickImage::horizontalAlignment() const
729 {
730     Q_D(const QQuickImage);
731     return d->hAlign;
732 }
733
734 void QQuickImage::setHorizontalAlignment(HAlignment align)
735 {
736     Q_D(QQuickImage);
737     if (d->hAlign == align)
738         return;
739
740     d->hAlign = align;
741     update();
742     updatePaintedGeometry();
743     emit horizontalAlignmentChanged(align);
744 }
745
746 QT_END_NAMESPACE