1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | #include <qtest.h> |
29 | #include <QtTest/QSignalSpy> |
30 | |
31 | #include <QtGui/qscreen.h> |
32 | #include <QtQml/qqmlengine.h> |
33 | #include <QtQml/qqmlcomponent.h> |
34 | #include <QtQuick/qquickview.h> |
35 | #include <private/qquickitem_p.h> |
36 | #include <private/qquickrectangle_p.h> |
37 | |
38 | #include "../../shared/util.h" |
39 | |
40 | class tst_qquickrectangle : public QQmlDataTest |
41 | { |
42 | Q_OBJECT |
43 | public: |
44 | tst_qquickrectangle(); |
45 | |
46 | private slots: |
47 | void color(); |
48 | void gradient(); |
49 | void gradient_border(); |
50 | void gradient_separate(); |
51 | void gradient_multiple(); |
52 | void gradient_preset(); |
53 | void antialiasing(); |
54 | |
55 | private: |
56 | QQmlEngine engine; |
57 | }; |
58 | |
59 | tst_qquickrectangle::tst_qquickrectangle() |
60 | { |
61 | } |
62 | |
63 | void tst_qquickrectangle::color() |
64 | { |
65 | if (QGuiApplication::primaryScreen()->depth() < 24) |
66 | QSKIP("This test does not work at display depths < 24" ); |
67 | |
68 | QQuickView view; |
69 | view.setSource(testFileUrl(fileName: "color.qml" )); |
70 | view.show(); |
71 | |
72 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
73 | |
74 | if ((QGuiApplication::platformName() == QLatin1String("offscreen" )) |
75 | || (QGuiApplication::platformName() == QLatin1String("minimal" ))) |
76 | QEXPECT_FAIL("" , "Failure due to grabWindow not functional on offscreen/minimal platforms" , Abort); |
77 | |
78 | QImage image = view.grabWindow(); |
79 | QVERIFY(image.pixel(0,0) == QColor("#020202" ).rgba()); |
80 | } |
81 | |
82 | void tst_qquickrectangle::gradient() |
83 | { |
84 | QQmlComponent component(&engine, testFileUrl(fileName: "gradient.qml" )); |
85 | QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(object: component.create()); |
86 | QVERIFY(rect); |
87 | |
88 | QQuickGradient *grad = qobject_cast<QQuickGradient *>(object: rect->gradient().toQObject()); |
89 | QVERIFY(grad); |
90 | |
91 | QQmlListProperty<QQuickGradientStop> stops = grad->stops(); |
92 | QCOMPARE(stops.count(&stops), 2); |
93 | QCOMPARE(stops.at(&stops, 0)->position(), 0.0); |
94 | QCOMPARE(stops.at(&stops, 0)->color(), QColor("gray" )); |
95 | QCOMPARE(stops.at(&stops, 1)->position(), 1.0); |
96 | QCOMPARE(stops.at(&stops, 1)->color(), QColor("white" )); |
97 | |
98 | QGradientStops gradientStops = grad->gradientStops(); |
99 | QCOMPARE(gradientStops.count(), 2); |
100 | QCOMPARE(gradientStops.at(0).first, 0.0); |
101 | QCOMPARE(gradientStops.at(0).second, QColor("gray" )); |
102 | QCOMPARE(gradientStops.at(1).first, 1.0); |
103 | QCOMPARE(gradientStops.at(1).second, QColor("white" )); |
104 | |
105 | QMetaObject::invokeMethod(obj: rect, member: "resetGradient" ); |
106 | |
107 | grad = qobject_cast<QQuickGradient *>(object: rect->gradient().toQObject()); |
108 | QVERIFY(!grad); |
109 | |
110 | delete rect; |
111 | } |
112 | |
113 | void tst_qquickrectangle::gradient_border() |
114 | { |
115 | QQuickView view; |
116 | view.setSource(testFileUrl(fileName: "gradient-border.qml" )); |
117 | view.show(); |
118 | |
119 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
120 | } |
121 | |
122 | // A gradient not defined inline with the Rectangle using it should still change |
123 | // that Rectangle. |
124 | void tst_qquickrectangle::gradient_separate() |
125 | { |
126 | QQuickView view; |
127 | view.setSource(testFileUrl(fileName: "gradient-separate.qml" )); |
128 | view.show(); |
129 | |
130 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
131 | |
132 | QQuickRectangle *rect = qobject_cast<QQuickRectangle*>(object: view.rootObject()); |
133 | QVERIFY(rect); |
134 | |
135 | // Start off clean |
136 | QQuickItemPrivate *rectPriv = QQuickItemPrivate::get(item: rect); |
137 | QTRY_COMPARE(rectPriv->dirtyAttributes & QQuickItemPrivate::Content, 0u); |
138 | |
139 | QMetaObject::invokeMethod(obj: rect, member: "changeGradient" ); |
140 | |
141 | // Changing the gradient should have scheduled an update of the item. |
142 | QVERIFY((rectPriv->dirtyAttributes & QQuickItemPrivate::Content) != 0); |
143 | } |
144 | |
145 | // When a gradient is changed, every Rectangle connected to it must update. |
146 | void tst_qquickrectangle::gradient_multiple() |
147 | { |
148 | QQuickView view; |
149 | view.setSource(testFileUrl(fileName: "gradient-multiple.qml" )); |
150 | view.show(); |
151 | |
152 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
153 | |
154 | QQuickRectangle *firstRect = qobject_cast<QQuickRectangle*>(object: view.rootObject()->property(name: "firstRectangle" ).value<QObject*>()); |
155 | QQuickRectangle *secondRect = qobject_cast<QQuickRectangle*>(object: view.rootObject()->property(name: "secondRectangle" ).value<QObject*>()); |
156 | QVERIFY(firstRect); |
157 | QVERIFY(secondRect); |
158 | |
159 | // Start off clean |
160 | QQuickItemPrivate *firstRectPriv = QQuickItemPrivate::get(item: firstRect); |
161 | QQuickItemPrivate *secondRectPriv = QQuickItemPrivate::get(item: secondRect); |
162 | QTRY_VERIFY(!(firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content)); |
163 | bool secondIsDirty = secondRectPriv->dirtyAttributes & QQuickItemPrivate::Content; |
164 | QVERIFY(!secondIsDirty); |
165 | |
166 | QMetaObject::invokeMethod(obj: view.rootObject(), member: "changeGradient" ); |
167 | |
168 | // Changing the gradient should have scheduled an update of both items |
169 | QTRY_VERIFY(firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content); |
170 | secondIsDirty = secondRectPriv->dirtyAttributes & QQuickItemPrivate::Content; |
171 | QVERIFY(secondIsDirty); |
172 | } |
173 | |
174 | void tst_qquickrectangle::gradient_preset() |
175 | { |
176 | QQuickView view; |
177 | view.setSource(testFileUrl(fileName: "gradient-preset.qml" )); |
178 | view.show(); |
179 | |
180 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
181 | |
182 | QQuickRectangle *enumRect = view.rootObject()->findChild<QQuickRectangle *>(aName: "enum" ); |
183 | QVERIFY(enumRect); |
184 | QVERIFY(enumRect->gradient().isNumber()); |
185 | QCOMPARE(enumRect->gradient().toUInt(), QGradient::NightFade); |
186 | |
187 | QQuickRectangle *stringRect = view.rootObject()->findChild<QQuickRectangle *>(aName: "string" ); |
188 | QVERIFY(stringRect); |
189 | QVERIFY(stringRect->gradient().isString()); |
190 | QCOMPARE(stringRect->gradient().toString(), QLatin1String("NightFade" )); |
191 | |
192 | for (int i = 1; i <= 5; ++i) { |
193 | QQuickRectangle *invalidRect = view.rootObject()->findChild<QQuickRectangle *>(qPrintable(QString("invalid%1" ).arg(i))); |
194 | QVERIFY(invalidRect); |
195 | QVERIFY(invalidRect->gradient().isUndefined()); |
196 | } |
197 | } |
198 | |
199 | void tst_qquickrectangle::antialiasing() |
200 | { |
201 | QQmlComponent component(&engine); |
202 | component.setData("import QtQuick 2.0\n Rectangle {}" , baseUrl: QUrl()); |
203 | QScopedPointer<QObject> object(component.create()); |
204 | QQuickRectangle *rect = qobject_cast<QQuickRectangle *>(object: object.data()); |
205 | QVERIFY(rect); |
206 | |
207 | QSignalSpy spy(rect, SIGNAL(antialiasingChanged(bool))); |
208 | |
209 | QCOMPARE(rect->antialiasing(), false); |
210 | |
211 | rect->setAntialiasing(true); |
212 | QCOMPARE(rect->antialiasing(), true); |
213 | QCOMPARE(spy.count(), 1); |
214 | |
215 | rect->setAntialiasing(true); |
216 | QCOMPARE(spy.count(), 1); |
217 | |
218 | rect->resetAntialiasing(); |
219 | QCOMPARE(rect->antialiasing(), false); |
220 | QCOMPARE(spy.count(), 2); |
221 | |
222 | rect->setRadius(5); |
223 | QCOMPARE(rect->antialiasing(), true); |
224 | QCOMPARE(spy.count(), 3); |
225 | |
226 | rect->resetAntialiasing(); |
227 | QCOMPARE(rect->antialiasing(), true); |
228 | QCOMPARE(spy.count(), 3); |
229 | |
230 | rect->setRadius(0); |
231 | QCOMPARE(rect->antialiasing(), false); |
232 | QCOMPARE(spy.count(), 4); |
233 | |
234 | rect->resetAntialiasing(); |
235 | QCOMPARE(rect->antialiasing(), false); |
236 | QCOMPARE(spy.count(), 4); |
237 | |
238 | rect->setRadius(5); |
239 | QCOMPARE(rect->antialiasing(), true); |
240 | QCOMPARE(spy.count(), 5); |
241 | |
242 | rect->resetAntialiasing(); |
243 | QCOMPARE(rect->antialiasing(), true); |
244 | QCOMPARE(spy.count(), 5); |
245 | |
246 | rect->setAntialiasing(false); |
247 | QCOMPARE(rect->antialiasing(), false); |
248 | QCOMPARE(spy.count(), 6); |
249 | |
250 | rect->resetAntialiasing(); |
251 | QCOMPARE(rect->antialiasing(), true); |
252 | QCOMPARE(spy.count(), 7); |
253 | } |
254 | |
255 | QTEST_MAIN(tst_qquickrectangle) |
256 | |
257 | #include "tst_qquickrectangle.moc" |
258 | |