When we create textureprovider, initialize it with the texture if we got it
[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()
60         : m_texture(0)
61         , m_smooth(false)
62     {
63     }
64
65     QSGTexture *texture() const {
66         if (m_texture) {
67             m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest);
68             m_texture->setMipmapFiltering(QSGTexture::Nearest);
69             m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
70             m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);
71         }
72         return m_texture;
73     }
74
75     friend class QSGImage;
76
77     QSGTexture *m_texture;
78     bool m_smooth;
79 };
80
81 #include "qsgimage.moc"
82
83 QSGImagePrivate::QSGImagePrivate()
84     : fillMode(QSGImage::Stretch)
85     , paintedWidth(0)
86     , paintedHeight(0)
87     , pixmapChanged(false)
88     , hAlign(QSGImage::AlignHCenter)
89     , vAlign(QSGImage::AlignVCenter)
90     , provider(0)
91 {
92 }
93
94 /*!
95     \qmlclass Image QSGImage
96     \inqmlmodule QtQuick 2
97     \ingroup qml-basic-visual-elements
98     \brief The Image element displays an image in a declarative user interface
99     \inherits Item
100
101     The Image element is used to display images in a declarative user interface.
102
103     The source of the image is specified as a URL using the \l source property.
104     Images can be supplied in any of the standard image formats supported by Qt,
105     including bitmap formats such as PNG and JPEG, and vector graphics formats
106     such as SVG. If you need to display animated images, use the \l AnimatedImage
107     element.
108
109     If the \l{Item::width}{width} and \l{Item::height}{height} properties are not
110     specified, the Image element automatically uses the size of the loaded image.
111     By default, specifying the width and height of the element causes the image
112     to be scaled to that size. This behavior can be changed by setting the
113     \l fillMode property, allowing the image to be stretched and tiled instead.
114
115     \section1 Example Usage
116
117     The following example shows the simplest usage of the Image element.
118
119     \snippet doc/src/snippets/declarative/image.qml document
120
121     \beginfloatleft
122     \image declarative-qtlogo.png
123     \endfloat
124
125     \clearfloat
126
127     \section1 Performance
128
129     By default, locally available images are loaded immediately, and the user interface
130     is blocked until loading is complete. If a large image is to be loaded, it may be
131     preferable to load the image in a low priority thread, by enabling the \l asynchronous
132     property.
133
134     If the image is obtained from a network rather than a local resource, it is
135     automatically loaded asynchronously, and the \l progress and \l status properties
136     are updated as appropriate.
137
138     Images are cached and shared internally, so if several Image elements have the same \l source,
139     only one copy of the image will be loaded.
140
141     \bold Note: Images are often the greatest user of memory in QML user interfaces.  It is recommended
142     that images which do not form part of the user interface have their
143     size bounded via the \l sourceSize property. This is especially important for content
144     that is loaded from external sources or provided by the user.
145
146     \sa {declarative/imageelements/image}{Image example}, QDeclarativeImageProvider
147 */
148
149 QSGImage::QSGImage(QSGItem *parent)
150     : QSGImageBase(*(new QSGImagePrivate), parent)
151 {
152 }
153
154 QSGImage::QSGImage(QSGImagePrivate &dd, QSGItem *parent)
155     : QSGImageBase(dd, parent)
156 {
157 }
158
159 QSGImage::~QSGImage()
160 {
161     Q_D(QSGImage);
162     if (d->provider)
163         d->provider->deleteLater();
164 }
165
166 void QSGImagePrivate::setPixmap(const QPixmap &pixmap)
167 {
168     Q_Q(QSGImage);
169     pix.setPixmap(pixmap);
170
171     q->pixmapChange();
172     status = pix.isNull() ? QSGImageBase::Null : QSGImageBase::Ready;
173
174     q->update();
175 }
176
177 /*!
178     \qmlproperty enumeration QtQuick2::Image::fillMode
179
180     Set this property to define what happens when the source image has a different size
181     than the item.
182
183     \list
184     \o Image.Stretch - the image is scaled to fit
185     \o Image.PreserveAspectFit - the image is scaled uniformly to fit without cropping
186     \o Image.PreserveAspectCrop - the image is scaled uniformly to fill, cropping if necessary
187     \o Image.Tile - the image is duplicated horizontally and vertically
188     \o Image.TileVertically - the image is stretched horizontally and tiled vertically
189     \o Image.TileHorizontally - the image is stretched vertically and tiled horizontally
190     \o Image.Pad - the image is not transformed
191     \endlist
192
193     \table
194
195     \row
196     \o \image declarative-qtlogo-stretch.png
197     \o Stretch (default)
198     \qml
199     Image {
200         width: 130; height: 100
201         smooth: true
202         source: "qtlogo.png"
203     }
204     \endqml
205
206     \row
207     \o \image declarative-qtlogo-preserveaspectfit.png
208     \o PreserveAspectFit
209     \qml
210     Image {
211         width: 130; height: 100
212         fillMode: Image.PreserveAspectFit
213         smooth: true
214         source: "qtlogo.png"
215     }
216     \endqml
217
218     \row
219     \o \image declarative-qtlogo-preserveaspectcrop.png
220     \o PreserveAspectCrop
221     \qml
222     Image {
223         width: 130; height: 100
224         fillMode: Image.PreserveAspectCrop
225         smooth: true
226         source: "qtlogo.png"
227         clip: true
228     }
229     \endqml
230
231     \row
232     \o \image declarative-qtlogo-tile.png
233     \o Tile
234     \qml
235     Image {
236         width: 120; height: 120
237         fillMode: Image.Tile
238         source: "qtlogo.png"
239     }
240     \endqml
241
242     \row
243     \o \image declarative-qtlogo-tilevertically.png
244     \o TileVertically
245     \qml
246     Image {
247         width: 120; height: 120
248         fillMode: Image.TileVertically
249         smooth: true
250         source: "qtlogo.png"
251     }
252     \endqml
253
254     \row
255     \o \image declarative-qtlogo-tilehorizontally.png
256     \o TileHorizontally
257     \qml
258     Image {
259         width: 120; height: 120
260         fillMode: Image.TileHorizontally
261         smooth: true
262         source: "qtlogo.png"
263     }
264     \endqml
265
266     \endtable
267
268     Note that \c clip is \c false by default which means that the element might
269     paint outside its bounding rectangle even if the fillMode is set to \c PreserveAspectCrop.
270
271     \sa {declarative/imageelements/image}{Image example}
272 */
273 QSGImage::FillMode QSGImage::fillMode() const
274 {
275     Q_D(const QSGImage);
276     return d->fillMode;
277 }
278
279 void QSGImage::setFillMode(FillMode mode)
280 {
281     Q_D(QSGImage);
282     if (d->fillMode == mode)
283         return;
284     d->fillMode = mode;
285     update();
286     updatePaintedGeometry();
287     emit fillModeChanged();
288 }
289
290 /*!
291
292     \qmlproperty real QtQuick2::Image::paintedWidth
293     \qmlproperty real QtQuick2::Image::paintedHeight
294
295     These properties hold the size of the image that is actually painted.
296     In most cases it is the same as \c width and \c height, but when using a
297     \c fillMode \c PreserveAspectFit or \c fillMode \c PreserveAspectCrop
298     \c paintedWidth or \c paintedHeight can be smaller or larger than
299     \c width and \c height of the Image element.
300 */
301 qreal QSGImage::paintedWidth() const
302 {
303     Q_D(const QSGImage);
304     return d->paintedWidth;
305 }
306
307 qreal QSGImage::paintedHeight() const
308 {
309     Q_D(const QSGImage);
310     return d->paintedHeight;
311 }
312
313 /*!
314     \qmlproperty enumeration QtQuick2::Image::status
315
316     This property holds the status of image loading.  It can be one of:
317     \list
318     \o Image.Null - no image has been set
319     \o Image.Ready - the image has been loaded
320     \o Image.Loading - the image is currently being loaded
321     \o Image.Error - an error occurred while loading the image
322     \endlist
323
324     Use this status to provide an update or respond to the status change in some way.
325     For example, you could:
326
327     \list
328     \o Trigger a state change:
329     \qml
330         State { name: 'loaded'; when: image.status == Image.Ready }
331     \endqml
332
333     \o Implement an \c onStatusChanged signal handler:
334     \qml
335         Image {
336             id: image
337             onStatusChanged: if (image.status == Image.Ready) console.log('Loaded')
338         }
339     \endqml
340
341     \o Bind to the status value:
342     \qml
343         Text { text: image.status == Image.Ready ? 'Loaded' : 'Not loaded' }
344     \endqml
345     \endlist
346
347     \sa progress
348 */
349
350 /*!
351     \qmlproperty real QtQuick2::Image::progress
352
353     This property holds the progress of image loading, from 0.0 (nothing loaded)
354     to 1.0 (finished).
355
356     \sa status
357 */
358
359 /*!
360     \qmlproperty bool QtQuick2::Image::smooth
361
362     Set this property if you want the image to be smoothly filtered when scaled or
363     transformed.  Smooth filtering gives better visual quality, but is slower.  If
364     the image is displayed at its natural size, this property has no visual or
365     performance effect.
366
367     \note Generally scaling artifacts are only visible if the image is stationary on
368     the screen.  A common pattern when animating an image is to disable smooth
369     filtering at the beginning of the animation and reenable it at the conclusion.
370 */
371
372 /*!
373     \qmlproperty QSize QtQuick2::Image::sourceSize
374
375     This property holds the actual width and height of the loaded image.
376
377     Unlike the \l {Item::}{width} and \l {Item::}{height} properties, which scale
378     the painting of the image, this property sets the actual number of pixels
379     stored for the loaded image so that large images do not use more
380     memory than necessary. For example, this ensures the image in memory is no
381     larger than 1024x1024 pixels, regardless of the Image's \l {Item::}{width} and
382     \l {Item::}{height} values:
383
384     \code
385     Rectangle {
386         width: ...
387         height: ...
388
389         Image {
390            anchors.fill: parent
391            source: "reallyBigImage.jpg"
392            sourceSize.width: 1024
393            sourceSize.height: 1024
394         }
395     }
396     \endcode
397
398     If the image's actual size is larger than the sourceSize, the image is scaled down.
399     If only one dimension of the size is set to greater than 0, the
400     other dimension is set in proportion to preserve the source image's aspect ratio.
401     (The \l fillMode is independent of this.)
402
403     If the source is an instrinsically scalable image (eg. SVG), this property
404     determines the size of the loaded image regardless of intrinsic size.
405     Avoid changing this property dynamically; rendering an SVG is \e slow compared
406     to an image.
407
408     If the source is a non-scalable image (eg. JPEG), the loaded image will
409     be no greater than this property specifies. For some formats (currently only JPEG),
410     the whole image will never actually be loaded into memory.
411
412     Since QtQuick 1.1 the sourceSize can be cleared to the natural size of the image
413     by setting sourceSize to \c undefined.
414
415     \note \e {Changing this property dynamically causes the image source to be reloaded,
416     potentially even from the network, if it is not in the disk cache.}
417 */
418
419 /*!
420     \qmlproperty url QtQuick2::Image::source
421
422     Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt.
423
424     The URL may be absolute, or relative to the URL of the component.
425
426     \sa QDeclarativeImageProvider
427 */
428
429 /*!
430     \qmlproperty bool QtQuick2::Image::asynchronous
431
432     Specifies that images on the local filesystem should be loaded
433     asynchronously in a separate thread.  The default value is
434     false, causing the user interface thread to block while the
435     image is loaded.  Setting \a asynchronous to true is useful where
436     maintaining a responsive user interface is more desirable
437     than having images immediately visible.
438
439     Note that this property is only valid for images read from the
440     local filesystem.  Images loaded via a network resource (e.g. HTTP)
441     are always loaded asynchonously.
442 */
443
444 /*!
445     \qmlproperty bool QtQuick2::Image::cache
446
447     Specifies whether the image should be cached. The default value is
448     true. Setting \a cache to false is useful when dealing with large images,
449     to make sure that they aren't cached at the expense of small 'ui element' images.
450 */
451
452 /*!
453     \qmlproperty bool QtQuick2::Image::mirror
454
455     This property holds whether the image should be horizontally inverted
456     (effectively displaying a mirrored image).
457
458     The default value is false.
459 */
460
461 /*!
462     \qmlproperty enumeration QtQuick2::Image::horizontalAlignment
463     \qmlproperty enumeration QtQuick2::Image::verticalAlignment
464
465     Sets the horizontal and vertical alignment of the image. By default, the image is top-left aligned.
466
467     The valid values for \c horizontalAlignment are \c Image.AlignLeft, \c Image.AlignRight and \c Image.AlignHCenter.
468     The valid values for \c verticalAlignment are \c Image.AlignTop, \c Image.AlignBottom
469     and \c Image.AlignVCenter.
470 */
471 void QSGImage::updatePaintedGeometry()
472 {
473     Q_D(QSGImage);
474
475     if (d->fillMode == PreserveAspectFit) {
476         if (!d->pix.width() || !d->pix.height()) {
477             setImplicitWidth(0);
478             setImplicitHeight(0);
479             return;
480         }
481         qreal w = widthValid() ? width() : d->pix.width();
482         qreal widthScale = w / qreal(d->pix.width());
483         qreal h = heightValid() ? height() : d->pix.height();
484         qreal heightScale = h / qreal(d->pix.height());
485         if (widthScale <= heightScale) {
486             d->paintedWidth = w;
487             d->paintedHeight = widthScale * qreal(d->pix.height());
488         } else if(heightScale < widthScale) {
489             d->paintedWidth = heightScale * qreal(d->pix.width());
490             d->paintedHeight = h;
491         }
492         if (widthValid() && !heightValid()) {
493             setImplicitHeight(d->paintedHeight);
494         } else {
495             setImplicitHeight(d->pix.height());
496         }
497         if (heightValid() && !widthValid()) {
498             setImplicitWidth(d->paintedWidth);
499         } else {
500             setImplicitWidth(d->pix.width());
501         }
502     } else if (d->fillMode == PreserveAspectCrop) {
503         if (!d->pix.width() || !d->pix.height())
504             return;
505         qreal widthScale = width() / qreal(d->pix.width());
506         qreal heightScale = height() / qreal(d->pix.height());
507         if (widthScale < heightScale) {
508             widthScale = heightScale;
509         } else if(heightScale < widthScale) {
510             heightScale = widthScale;
511         }
512
513         d->paintedHeight = heightScale * qreal(d->pix.height());
514         d->paintedWidth = widthScale * qreal(d->pix.width());
515     } else if (d->fillMode == Pad) {
516         d->paintedWidth = d->pix.width();
517         d->paintedHeight = d->pix.height();
518     } else {
519         d->paintedWidth = width();
520         d->paintedHeight = height();
521     }
522     emit paintedGeometryChanged();
523 }
524
525 void QSGImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
526 {
527     QSGImageBase::geometryChanged(newGeometry, oldGeometry);
528     updatePaintedGeometry();
529 }
530
531 QRectF QSGImage::boundingRect() const
532 {
533     Q_D(const QSGImage);
534     return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
535 }
536
537 QSGTextureProvider *QSGImage::textureProvider() const
538 {
539     Q_D(const QSGImage);
540     if (!d->provider) {
541         // Make sure it gets thread affinity on the rendering thread so deletion works properly..
542         Q_ASSERT_X(d->canvas
543                    && d->sceneGraphContext()
544                    && QThread::currentThread() == d->sceneGraphContext()->thread(),
545                    "QSGImage::textureProvider",
546                    "Cannot be used outside the GUI thread");
547         QSGImagePrivate *dd = const_cast<QSGImagePrivate *>(d);
548         dd->provider = new QSGImageTextureProvider;
549         dd->provider->m_texture = d->pix.texture(d->sceneGraphContext());
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