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