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
29
30#include <QtTest/QtTest>
31
32#include <qpicture.h>
33#include <qpainter.h>
34#include <qimage.h>
35#include <qpaintengine.h>
36#include <qguiapplication.h>
37#include <qscreen.h>
38#include <limits.h>
39
40class tst_QPicture : public QObject
41{
42 Q_OBJECT
43
44public:
45 tst_QPicture();
46
47private slots:
48 void getSetCheck();
49 void devType();
50 void paintingActive();
51 void boundingRect();
52 void swap();
53 void serialization();
54 void save_restore();
55 void boundaryValues_data();
56 void boundaryValues();
57};
58
59// Testing get/set functions
60void tst_QPicture::getSetCheck()
61{
62 QPictureIO obj1;
63 // const QPicture & QPictureIO::picture()
64 // void QPictureIO::setPicture(const QPicture &)
65 // const char * QPictureIO::format()
66 // void QPictureIO::setFormat(const char *)
67 const char var2[] = "PNG";
68 obj1.setFormat(var2);
69 QCOMPARE(var2, obj1.format());
70 obj1.setFormat((char *)0);
71 // The format is stored internally in a QString, so return is always a valid char *
72 QVERIFY(QString(obj1.format()).isEmpty());
73
74 // const char * QPictureIO::parameters()
75 // void QPictureIO::setParameters(const char *)
76 const char var3[] = "Bogus data";
77 obj1.setParameters(var3);
78 QCOMPARE(var3, obj1.parameters());
79 obj1.setParameters((char *)0);
80 // The format is stored internally in a QString, so return is always a valid char *
81 QVERIFY(QString(obj1.parameters()).isEmpty());
82}
83
84tst_QPicture::tst_QPicture()
85{
86}
87
88void tst_QPicture::devType()
89{
90 QPicture p;
91 QCOMPARE( p.devType(), (int)QInternal::Picture );
92}
93
94void tst_QPicture::paintingActive()
95{
96 // actually implemented in QPainter but QPicture is a good
97 // example of an external paint device
98 QPicture p;
99 QVERIFY( !p.paintingActive() );
100 QPainter pt( &p );
101 QVERIFY( p.paintingActive() );
102 pt.end();
103 QVERIFY( !p.paintingActive() );
104}
105
106void tst_QPicture::boundingRect()
107{
108 QPicture p1;
109 // default value
110 QVERIFY( !p1.boundingRect().isValid() );
111
112 QRect r1( 20, 30, 5, 15 );
113 p1.setBoundingRect( r1 );
114 QCOMPARE( p1.boundingRect(), r1 );
115 p1.setBoundingRect(QRect());
116
117 QPainter pt( &p1 );
118 pt.drawLine( x1: 10, y1: 20, x2: 110, y2: 80 );
119 pt.end();
120
121 // assignment and copy constructor
122 QRect r2( 10, 20, 100, 60 );
123 QCOMPARE( p1.boundingRect(), r2 );
124 QPicture p2( p1 );
125 QCOMPARE( p2.boundingRect(), r2 );
126 QPicture p3;
127 p3 = p1;
128 QCOMPARE( p3.boundingRect(), r2 );
129
130 {
131 QPicture p4;
132 QPainter p(&p4);
133 p.drawLine(x1: 0, y1: 0, x2: 5, y2: 0);
134 p.drawLine(x1: 0, y1: 0, x2: 0, y2: 5);
135 p.end();
136
137 QRect r3(0, 0, 5, 5);
138 QCOMPARE(p4.boundingRect(), r3);
139 }
140}
141
142void tst_QPicture::swap()
143{
144 QPicture p1, p2;
145 QPainter(&p1).drawLine(x1: 0, y1: 0, x2: 5, y2: 5);
146 QPainter(&p2).drawLine(x1: 0, y1: 3, x2: 3, y2: 0);
147 QCOMPARE(p1.boundingRect(), QRect(0,0,5,5));
148 QCOMPARE(p2.boundingRect(), QRect(0,0,3,3));
149 p1.swap(other&: p2);
150 QCOMPARE(p1.boundingRect(), QRect(0,0,3,3));
151 QCOMPARE(p2.boundingRect(), QRect(0,0,5,5));
152}
153
154Q_DECLARE_METATYPE(QDataStream::Version)
155Q_DECLARE_METATYPE(QPicture)
156
157void ensureSerializesCorrectly(const QPicture &picture, QDataStream::Version version)
158 {
159 QDataStream stream;
160
161 QBuffer buffer;
162 buffer.open(openMode: QIODevice::WriteOnly);
163 stream.setDevice(&buffer);
164 stream.setVersion(version);
165 stream << picture;
166 buffer.close();
167
168 buffer.open(openMode: QIODevice::ReadOnly);
169 QPicture readpicture;
170 stream >> readpicture;
171 QVERIFY2(memcmp(picture.data(), readpicture.data(), picture.size()) == 0,
172 qPrintable(QString::fromLatin1("Picture data does not compare equal for QDataStream version %1").arg(version)));
173}
174
175class PaintEngine : public QPaintEngine
176{
177public:
178 PaintEngine() : QPaintEngine() {}
179 bool begin(QPaintDevice *) { return true; }
180 bool end() { return true; }
181 void updateState(const QPaintEngineState &) {}
182 void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
183 Type type() const { return Raster; }
184
185 QFont font() { return state->font(); }
186};
187
188class Picture : public QPicture
189{
190public:
191 Picture() : QPicture() {}
192 QPaintEngine *paintEngine() const { return (QPaintEngine*)&mPaintEngine; }
193private:
194 PaintEngine mPaintEngine;
195};
196
197void tst_QPicture::serialization()
198{
199 QDataStream stream;
200 const int thisVersion = stream.version();
201
202 for (int version = QDataStream::Qt_1_0; version <= thisVersion; ++version) {
203 const QDataStream::Version versionEnum = static_cast<QDataStream::Version>(version);
204
205 {
206 // streaming of null pictures
207 ensureSerializesCorrectly(picture: QPicture(), version: versionEnum);
208 }
209 {
210 // picture with a simple line, checking bitwise equality
211 QPicture picture;
212 QPainter painter(&picture);
213 painter.drawLine(x1: 10, y1: 20, x2: 30, y2: 40);
214 ensureSerializesCorrectly(picture, version: versionEnum);
215 }
216 }
217
218 {
219 // Test features that were added after Qt 4.5, as that was hard-coded as the major
220 // version for a while, which was incorrect. In this case, we'll test font hints.
221 QPicture picture;
222 QPainter painter;
223 QFont font;
224 font.setStyleName("Blah");
225 font.setHintingPreference(QFont::PreferFullHinting);
226 painter.begin(&picture);
227 painter.setFont(font);
228 painter.drawText(x: 20, y: 20, s: "Hello");
229 painter.end();
230
231 Picture customPicture;
232 painter.begin(&customPicture);
233 picture.play(p: &painter);
234 const QFont actualFont = ((PaintEngine*)customPicture.paintEngine())->font();
235 painter.end();
236 QCOMPARE(actualFont.styleName(), QStringLiteral("Blah"));
237 QCOMPARE(actualFont.hintingPreference(), QFont::PreferFullHinting);
238 }
239}
240
241static QRectF scaleRect(const QRectF &rect, qreal xf, qreal yf)
242{
243 return QRectF(rect.left() * xf, rect.top() * yf, rect.width() * xf, rect.height() * yf);
244}
245
246static void paintStuff(QPainter *p)
247{
248 const QScreen *screen = QGuiApplication::primaryScreen();
249 // Calculate factors from the screen resolution against QPicture's 96DPI
250 // (enforced by Qt::AA_Use96Dpi as set by QTEST_MAIN).
251 const qreal xf = qreal(p->device()->logicalDpiX()) / screen->logicalDotsPerInchX();
252 const qreal yf = qreal(p->device()->logicalDpiY()) / screen->logicalDotsPerInchY();
253 p->drawRect(rect: scaleRect(rect: QRectF(100, 100, 100, 100), xf, yf));
254 p->save();
255 p->translate(dx: 10 * xf, dy: 10 * yf);
256 p->restore();
257 p->drawRect(rect: scaleRect(rect: QRectF(100, 100, 100, 100), xf, yf));
258}
259
260/* See task: 41469
261 Problem is that the state is not properly restored if the basestate of
262 the painter is different when the picture data was created compared to
263 the base state of the painter when it is played back.
264 */
265void tst_QPicture::save_restore()
266{
267 QPicture pic;
268 QPainter p;
269 p.begin(&pic);
270 paintStuff(p: &p);
271 p.end();
272
273 QPixmap pix1(300, 300);
274 pix1.fill(fillColor: Qt::white);
275 p.begin(&pix1);
276 p.drawPicture(x: 50, y: 50, p: pic);
277 p.end();
278
279 QPixmap pix2(300, 300);
280 pix2.fill(fillColor: Qt::white);
281 p.begin(&pix2);
282 p.translate(dx: 50, dy: 50);
283 paintStuff(p: &p);
284 p.end();
285
286 QVERIFY( pix1.toImage() == pix2.toImage() );
287}
288
289void tst_QPicture::boundaryValues_data()
290{
291 QTest::addColumn<int>(name: "x");
292 QTest::addColumn<int>(name: "y");
293 QTest::newRow(dataTag: "max x") << INT_MAX << 50;
294 QTest::newRow(dataTag: "max y") << 50 << INT_MAX;
295 QTest::newRow(dataTag: "max x and y") << INT_MAX << INT_MAX;
296
297 QTest::newRow(dataTag: "min x") << INT_MIN << 50;
298 QTest::newRow(dataTag: "min y") << 50 << INT_MIN;
299 QTest::newRow(dataTag: "min x and y") << INT_MIN << INT_MIN;
300
301 QTest::newRow(dataTag: "min x, max y") << INT_MIN << INT_MAX;
302 QTest::newRow(dataTag: "max x, min y") << INT_MAX << INT_MIN;
303}
304
305void tst_QPicture::boundaryValues()
306{
307 QPicture picture;
308
309 QPainter painter;
310 painter.begin(&picture);
311
312 QFETCH(int, x);
313 QFETCH(int, y);
314 painter.drawPoint(p: QPoint(x, y));
315
316 painter.end();
317}
318
319
320QTEST_MAIN(tst_QPicture)
321#include "tst_qpicture.moc"
322

source code of qtbase/tests/auto/gui/image/qpicture/tst_qpicture.cpp