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 | |
40 | class tst_QPicture : public QObject |
41 | { |
42 | Q_OBJECT |
43 | |
44 | public: |
45 | tst_QPicture(); |
46 | |
47 | private 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 |
60 | void 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 | |
84 | tst_QPicture::tst_QPicture() |
85 | { |
86 | } |
87 | |
88 | void tst_QPicture::devType() |
89 | { |
90 | QPicture p; |
91 | QCOMPARE( p.devType(), (int)QInternal::Picture ); |
92 | } |
93 | |
94 | void 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 | |
106 | void 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 | |
142 | void 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 | |
154 | Q_DECLARE_METATYPE(QDataStream::Version) |
155 | Q_DECLARE_METATYPE(QPicture) |
156 | |
157 | void 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 | |
175 | class PaintEngine : public QPaintEngine |
176 | { |
177 | public: |
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 | |
188 | class Picture : public QPicture |
189 | { |
190 | public: |
191 | Picture() : QPicture() {} |
192 | QPaintEngine *paintEngine() const { return (QPaintEngine*)&mPaintEngine; } |
193 | private: |
194 | PaintEngine mPaintEngine; |
195 | }; |
196 | |
197 | void 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 | |
241 | static 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 | |
246 | static 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 | */ |
265 | void 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 | |
289 | void 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 | |
305 | void 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 | |
320 | QTEST_MAIN(tst_QPicture) |
321 | #include "tst_qpicture.moc" |
322 | |