1/****************************************************************************
2**
3** Copyright (C) 2017 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
29#include <qtest.h>
30#include <QtTest/qsignalspy.h>
31
32#include <QtCore/qmath.h>
33#include <QtCore/qsize.h>
34#include <QtGui/private/qhighdpiscaling_p.h>
35#include <QtQml/qqmlengine.h>
36#include <QtQuick/qquickitem.h>
37#include <QtQuick/qquickview.h>
38#include <QtQuick/qquickitemgrabresult.h>
39#include <QtQuick/private/qquickimage_p.h>
40
41#include "../shared/util.h"
42#include "../shared/visualtestutil.h"
43
44using namespace QQuickVisualTestUtil;
45
46class tst_qquickninepatchimage : public QQmlDataTest
47{
48 Q_OBJECT
49
50private slots:
51 void ninePatch_data();
52 void ninePatch();
53 void padding_data();
54 void padding();
55 void inset_data();
56 void inset();
57 void implicitSize_data();
58 void implicitSize();
59};
60
61static QImage grabItemToImage(QQuickItem *item)
62{
63 QSharedPointer<QQuickItemGrabResult> result = item->grabToImage();
64 QSignalSpy spy(result.data(), SIGNAL(ready()));
65 spy.wait();
66 return result->image();
67}
68
69void tst_qquickninepatchimage::ninePatch_data()
70{
71 QTest::addColumn<int>(name: "dpr");
72 QTest::addColumn<QSize>(name: "size");
73
74 // original size, downsized, stretched
75 const QList<QSize> sizes = QList<QSize>()
76 << QSize(40, 40) // original
77 << QSize(10, 40) // downsized (h)
78 << QSize(40, 10) // downsized (v)
79 << QSize(10, 10) // downsized (h & v)
80 << QSize(80, 40) // stretched (h)
81 << QSize(40, 80) // stretched (v)
82 << QSize(80, 80) // stretched (h & v)
83 << QSize(8, 8); // minimal (borders only)
84
85 for (const QSize &sz : sizes) {
86 for (int dpr = 1; dpr <= 4; ++dpr)
87 QTest::newRow(qPrintable(QString::fromLatin1("DPR=%1, %2x%3").arg(dpr).arg(sz.width()).arg(sz.height()))) << dpr << sz;
88 }
89}
90
91void tst_qquickninepatchimage::ninePatch()
92{
93 QFETCH(int, dpr);
94 QFETCH(QSize, size);
95
96 QHighDpiScaling::setGlobalFactor(dpr);
97
98 QQuickView view(testFileUrl(fileName: "ninepatchimage.qml"));
99 QCOMPARE(view.status(), QQuickView::Ready);
100 view.show();
101 view.requestActivate();
102 QVERIFY(QTest::qWaitForWindowActive(&view));
103
104 QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(object: view.rootObject());
105 QVERIFY(ninePatchImage);
106 ninePatchImage->setSource(testFileUrl(fileName: "foo.9.png"));
107 ninePatchImage->setSize(size);
108
109 const QImage ninePatchImageGrab = grabItemToImage(item: ninePatchImage).scaled(s: size * dpr);
110
111 // Generate an image to compare against the actual 9-patch image.
112 QImage generatedImage(size * dpr, ninePatchImageGrab.format());
113 generatedImage.fill(color: Qt::red);
114
115 QImage blueRect(4 * dpr, 4 * dpr, ninePatchImageGrab.format());
116 blueRect.fill(color: Qt::blue);
117
118 QPainter painter(&generatedImage);
119 // Top-left
120 painter.drawImage(x: 0, y: 0, image: blueRect);
121 // Top-right
122 painter.drawImage(x: generatedImage.width() - blueRect.width(), y: 0, image: blueRect);
123 // Bottom-right
124 painter.drawImage(x: generatedImage.width() - blueRect.width(), y: generatedImage.height() - blueRect.height(), image: blueRect);
125 // Bottom-left
126 painter.drawImage(x: 0, y: generatedImage.height() - blueRect.height(), image: blueRect);
127
128 if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
129 || (QGuiApplication::platformName() == QLatin1String("minimal")))
130 QEXPECT_FAIL("", "Grabbing does not work on offscreen/minimal platforms", Abort);
131
132 QCOMPARE(ninePatchImageGrab, generatedImage);
133}
134
135void tst_qquickninepatchimage::padding_data()
136{
137 QTest::addColumn<int>(name: "dpr");
138
139 for (int dpr = 1; dpr <= 4; ++dpr)
140 QTest::newRow(qPrintable(QString::fromLatin1("DPR=%1").arg(dpr))) << dpr;
141}
142
143void tst_qquickninepatchimage::padding()
144{
145 QFETCH(int, dpr);
146
147 QHighDpiScaling::setGlobalFactor(dpr);
148
149 QQuickView view(testFileUrl(fileName: "ninepatchimage.qml"));
150 QCOMPARE(view.status(), QQuickView::Ready);
151 view.show();
152 view.requestActivate();
153 QVERIFY(QTest::qWaitForWindowActive(&view));
154
155 QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(object: view.rootObject());
156 QVERIFY(ninePatchImage);
157 ninePatchImage->setSource(testFileUrl(fileName: "padding.9.png"));
158
159 QCOMPARE(ninePatchImage->property("topPadding").toReal(), 8);
160 QCOMPARE(ninePatchImage->property("leftPadding").toReal(), 18);
161 QCOMPARE(ninePatchImage->property("rightPadding").toReal(), 20);
162 QCOMPARE(ninePatchImage->property("bottomPadding").toReal(), 10);
163}
164
165void tst_qquickninepatchimage::inset_data()
166{
167 QTest::addColumn<int>(name: "dpr");
168 QTest::addColumn<QString>(name: "file");
169 QTest::addColumn<QMarginsF>(name: "insets");
170
171 const QStringList files = QStringList() << "inset-all.9.png" << "inset-topleft.9.png" << "inset-bottomright.9.png";
172 const QList<QMarginsF> insets = QList<QMarginsF>() << QMarginsF(2, 1, 3, 4) << QMarginsF(2, 1, 0, 0) << QMarginsF(0, 0, 3, 4);
173
174 for (int i = 0; i < files.count(); ++i) {
175 QString file = files.at(i);
176 for (int dpr = 1; dpr <= 4; ++dpr)
177 QTest::newRow(qPrintable(QString::fromLatin1("%1 DPR=%2").arg(file).arg(dpr))) << dpr << file << insets.at(i);
178 }
179}
180
181Q_DECLARE_METATYPE(QMarginsF)
182
183void tst_qquickninepatchimage::inset()
184{
185 QFETCH(int, dpr);
186 QFETCH(QString, file);
187 QFETCH(QMarginsF, insets);
188
189 QHighDpiScaling::setGlobalFactor(dpr);
190
191 QQuickView view(testFileUrl(fileName: "ninepatchimage.qml"));
192 QCOMPARE(view.status(), QQuickView::Ready);
193 view.show();
194 view.requestActivate();
195 QVERIFY(QTest::qWaitForWindowActive(&view));
196
197 QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(object: view.rootObject());
198 QVERIFY(ninePatchImage);
199 ninePatchImage->setSource(testFileUrl(fileName: file));
200
201 QCOMPARE(ninePatchImage->property("topInset").toReal(), insets.top());
202 QCOMPARE(ninePatchImage->property("leftInset").toReal(), insets.left());
203 QCOMPARE(ninePatchImage->property("rightInset").toReal(), insets.right());
204 QCOMPARE(ninePatchImage->property("bottomInset").toReal(), insets.bottom());
205}
206
207void tst_qquickninepatchimage::implicitSize_data()
208{
209 QTest::addColumn<int>(name: "dpr");
210 QTest::addColumn<QString>(name: "file");
211 QTest::addColumn<QSizeF>(name: "implicitSize");
212
213 const struct TestFile {
214 QString name;
215 QSizeF sizeHint;
216 } testFiles [] = {
217 { .name: "foo.9.png", .sizeHint: QSizeF(40, 40) },
218 { .name: "padding.9.png", .sizeHint: QSizeF(40, 40) },
219 { .name: "inset-all.9.png", .sizeHint: QSizeF(45, 45) },
220 { .name: "inset-topleft.9.png", .sizeHint: QSizeF(42, 41) },
221 { .name: "inset-bottomright.9.png", .sizeHint: QSizeF(43, 44) }
222 };
223
224 for (const TestFile &file : testFiles) {
225 for (int dpr = 1; dpr <= 4; ++dpr)
226 QTest::newRow(qPrintable(QString::fromLatin1("%1 DPR=%2").arg(file.name).arg(dpr))) << dpr << file.name << file.sizeHint;
227 }
228}
229
230void tst_qquickninepatchimage::implicitSize()
231{
232 QFETCH(int, dpr);
233 QFETCH(QString, file);
234 QFETCH(QSizeF, implicitSize);
235
236 QHighDpiScaling::setGlobalFactor(dpr);
237
238 QQuickView view(testFileUrl(fileName: "ninepatchimage.qml"));
239 QCOMPARE(view.status(), QQuickView::Ready);
240 view.show();
241 view.requestActivate();
242 QVERIFY(QTest::qWaitForWindowActive(&view));
243
244 QQuickImage *ninePatchImage = qobject_cast<QQuickImage *>(object: view.rootObject());
245 QVERIFY(ninePatchImage);
246 ninePatchImage->setSource(testFileUrl(fileName: file));
247
248 QCOMPARE(ninePatchImage->implicitWidth(), implicitSize.width());
249 QCOMPARE(ninePatchImage->implicitHeight(), implicitSize.height());
250}
251
252QTEST_MAIN(tst_qquickninepatchimage)
253
254#include "tst_qquickninepatchimage.moc"
255

source code of qtquickcontrols2/tests/auto/qquickninepatchimage/tst_qquickninepatchimage.cpp