|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 test suite of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 |
|
43 #include <QtTest/QtTest> |
|
44 |
|
45 #include <QDomDocument> |
|
46 #include <QDomElement> |
|
47 #include <QDomNode> |
|
48 |
|
49 #include <qapplication.h> |
|
50 #include <qdebug.h> |
|
51 #include <qpainter.h> |
|
52 #include <qsvggenerator.h> |
|
53 #include <qsvgrenderer.h> |
|
54 |
|
55 //TESTED_CLASS= |
|
56 //TESTED_FILES= |
|
57 |
|
58 #ifdef Q_OS_SYMBIAN |
|
59 #define SRCDIR "" |
|
60 #endif |
|
61 |
|
62 class tst_QSvgGenerator : public QObject |
|
63 { |
|
64 Q_OBJECT |
|
65 |
|
66 public: |
|
67 tst_QSvgGenerator(); |
|
68 virtual ~tst_QSvgGenerator(); |
|
69 |
|
70 private slots: |
|
71 void construction(); |
|
72 void fileName(); |
|
73 void outputDevice(); |
|
74 void sizeAndViewBox(); |
|
75 void metric(); |
|
76 void radialGradient(); |
|
77 void fileEncoding(); |
|
78 void fractionalFontSize(); |
|
79 void titleAndDescription(); |
|
80 void gradientInterpolation(); |
|
81 }; |
|
82 |
|
83 tst_QSvgGenerator::tst_QSvgGenerator() |
|
84 { |
|
85 } |
|
86 |
|
87 tst_QSvgGenerator::~tst_QSvgGenerator() |
|
88 { |
|
89 QFile::remove(QLatin1String("fileName_output.svg")); |
|
90 QFile::remove(QLatin1String("outputDevice_output.svg")); |
|
91 QFile::remove(QLatin1String("radial_gradient.svg")); |
|
92 } |
|
93 |
|
94 void tst_QSvgGenerator::construction() |
|
95 { |
|
96 QSvgGenerator generator; |
|
97 QCOMPARE(generator.fileName(), QString()); |
|
98 QCOMPARE(generator.outputDevice(), (QIODevice *)0); |
|
99 QCOMPARE(generator.resolution(), 72); |
|
100 QCOMPARE(generator.size(), QSize()); |
|
101 } |
|
102 |
|
103 static void removeAttribute(const QDomNode &node, const QString &attribute) |
|
104 { |
|
105 if (node.isNull()) |
|
106 return; |
|
107 |
|
108 node.toElement().removeAttribute(attribute); |
|
109 |
|
110 removeAttribute(node.firstChild(), attribute); |
|
111 removeAttribute(node.nextSibling(), attribute); |
|
112 } |
|
113 |
|
114 static void compareWithoutFontInfo(const QByteArray &source, const QByteArray &reference) |
|
115 { |
|
116 QDomDocument sourceDoc; |
|
117 sourceDoc.setContent(source); |
|
118 |
|
119 QDomDocument referenceDoc; |
|
120 referenceDoc.setContent(reference); |
|
121 |
|
122 QList<QString> fontAttributes; |
|
123 fontAttributes << "font-family" << "font-size" << "font-weight" << "font-style"; |
|
124 |
|
125 foreach (QString attribute, fontAttributes) { |
|
126 removeAttribute(sourceDoc, attribute); |
|
127 removeAttribute(referenceDoc, attribute); |
|
128 } |
|
129 |
|
130 QCOMPARE(sourceDoc.toByteArray(), referenceDoc.toByteArray()); |
|
131 } |
|
132 |
|
133 static void checkFile(const QString &fileName) |
|
134 { |
|
135 QVERIFY(QFile::exists(fileName));; |
|
136 |
|
137 QFile file(fileName); |
|
138 QVERIFY(file.open(QIODevice::ReadOnly)); |
|
139 |
|
140 QFile referenceFile(SRCDIR "referenceSvgs/" + fileName); |
|
141 QVERIFY(referenceFile.open(QIODevice::ReadOnly)); |
|
142 |
|
143 compareWithoutFontInfo(file.readAll(), referenceFile.readAll()); |
|
144 } |
|
145 |
|
146 void tst_QSvgGenerator::fileName() |
|
147 { |
|
148 QString fileName = "fileName_output.svg"; |
|
149 QFile::remove(fileName); |
|
150 |
|
151 QSvgGenerator generator; |
|
152 generator.setFileName(fileName); |
|
153 QCOMPARE(generator.fileName(), fileName); |
|
154 |
|
155 QPainter painter(&generator); |
|
156 painter.fillRect(0, 0, 100, 100, Qt::red); |
|
157 painter.end(); |
|
158 |
|
159 checkFile(fileName); |
|
160 } |
|
161 |
|
162 void tst_QSvgGenerator::outputDevice() |
|
163 { |
|
164 QString fileName = "outputDevice_output.svg"; |
|
165 QFile::remove(fileName); |
|
166 |
|
167 QFile file(fileName); |
|
168 |
|
169 { |
|
170 // Device is not open |
|
171 QSvgGenerator generator; |
|
172 generator.setOutputDevice(&file); |
|
173 QCOMPARE(generator.outputDevice(), (QIODevice *)&file); |
|
174 |
|
175 QPainter painter; |
|
176 QVERIFY(painter.begin(&generator)); |
|
177 QCOMPARE(file.openMode(), QIODevice::OpenMode(QIODevice::Text | QIODevice::WriteOnly)); |
|
178 file.close(); |
|
179 } |
|
180 { |
|
181 // Device is not open, WriteOnly |
|
182 file.open(QIODevice::WriteOnly); |
|
183 |
|
184 QSvgGenerator generator; |
|
185 generator.setOutputDevice(&file); |
|
186 QCOMPARE(generator.outputDevice(), (QIODevice *)&file); |
|
187 |
|
188 QPainter painter; |
|
189 QVERIFY(painter.begin(&generator)); |
|
190 QCOMPARE(file.openMode(), QIODevice::OpenMode(QIODevice::WriteOnly)); |
|
191 file.close(); |
|
192 } |
|
193 { |
|
194 // Device is not open, ReadOnly |
|
195 file.open(QIODevice::ReadOnly); |
|
196 |
|
197 QSvgGenerator generator; |
|
198 generator.setOutputDevice(&file); |
|
199 QCOMPARE(generator.outputDevice(), (QIODevice *)&file); |
|
200 |
|
201 QPainter painter; |
|
202 QTest::ignoreMessage(QtWarningMsg, "QSvgPaintEngine::begin(), could not write to read-only output device: 'Unknown error'"); |
|
203 QVERIFY(!painter.begin(&generator)); |
|
204 QCOMPARE(file.openMode(), QIODevice::OpenMode(QIODevice::ReadOnly)); |
|
205 file.close(); |
|
206 } |
|
207 } |
|
208 |
|
209 void tst_QSvgGenerator::sizeAndViewBox() |
|
210 { |
|
211 { // Setting neither properties should result in |
|
212 // none of the attributes written to the SVG |
|
213 QSvgGenerator generator; |
|
214 QByteArray byteArray; |
|
215 QBuffer buffer(&byteArray); |
|
216 generator.setOutputDevice(&buffer); |
|
217 QPainter painter(&generator); |
|
218 painter.end(); |
|
219 |
|
220 QVERIFY(!byteArray.contains("<svg width=\"")); |
|
221 QVERIFY(!byteArray.contains("viewBox=\"")); |
|
222 } |
|
223 |
|
224 { // Setting size only should write size only |
|
225 QSvgGenerator generator; |
|
226 QByteArray byteArray; |
|
227 QBuffer buffer(&byteArray); |
|
228 generator.setOutputDevice(&buffer); |
|
229 generator.setResolution(254); |
|
230 generator.setSize(QSize(100, 100)); |
|
231 QPainter painter(&generator); |
|
232 painter.end(); |
|
233 |
|
234 QVERIFY(byteArray.contains("<svg width=\"10mm\" height=\"10mm\"")); |
|
235 QVERIFY(!byteArray.contains("viewBox=\"")); |
|
236 } |
|
237 |
|
238 { // Setting viewBox only should write viewBox only |
|
239 QSvgGenerator generator; |
|
240 QByteArray byteArray; |
|
241 QBuffer buffer(&byteArray); |
|
242 generator.setOutputDevice(&buffer); |
|
243 generator.setViewBox(QRectF(20, 20, 50.666, 50.666)); |
|
244 QPainter painter(&generator); |
|
245 painter.end(); |
|
246 |
|
247 QVERIFY(!byteArray.contains("<svg width=\"")); |
|
248 QVERIFY(byteArray.contains("<svg viewBox=\"20 20 50.666 50.666\"")); |
|
249 } |
|
250 |
|
251 { // Setting both properties should result in |
|
252 // both of the attributes written to the SVG |
|
253 QSvgGenerator generator; |
|
254 QByteArray byteArray; |
|
255 QBuffer buffer(&byteArray); |
|
256 generator.setOutputDevice(&buffer); |
|
257 generator.setResolution(254); |
|
258 generator.setSize(QSize(500, 500)); |
|
259 generator.setViewBox(QRectF(20.666, 20.666, 50, 50)); |
|
260 QPainter painter(&generator); |
|
261 painter.end(); |
|
262 |
|
263 QVERIFY(byteArray.contains("<svg width=\"50mm\" height=\"50mm\"")); |
|
264 QVERIFY(byteArray.contains("viewBox=\"20.666 20.666 50 50\"")); |
|
265 } |
|
266 } |
|
267 |
|
268 void tst_QSvgGenerator::metric() |
|
269 { |
|
270 QSvgGenerator generator; |
|
271 generator.setSize(QSize(100, 100)); |
|
272 generator.setResolution(254); // 254 dots per inch == 10 dots per mm |
|
273 |
|
274 QCOMPARE(generator.widthMM(), 10); |
|
275 QCOMPARE(generator.heightMM(), 10); |
|
276 } |
|
277 |
|
278 void tst_QSvgGenerator::radialGradient() |
|
279 { |
|
280 QString fileName = "radial_gradient.svg"; |
|
281 QFile::remove(fileName); |
|
282 |
|
283 QSvgGenerator generator; |
|
284 generator.setSize(QSize(200, 100)); |
|
285 generator.setFileName(fileName); |
|
286 QCOMPARE(generator.fileName(), fileName); |
|
287 |
|
288 QRadialGradient gradient(QPointF(0.5, 0.5), 0.5, QPointF(0.5, 0.5)); |
|
289 gradient.setInterpolationMode(QGradient::ComponentInterpolation); |
|
290 gradient.setColorAt(0, Qt::red); |
|
291 gradient.setColorAt(1, Qt::blue); |
|
292 gradient.setCoordinateMode(QGradient::ObjectBoundingMode); |
|
293 |
|
294 QPainter painter(&generator); |
|
295 painter.fillRect(0, 0, 100, 100, gradient); |
|
296 |
|
297 gradient = QRadialGradient(QPointF(150, 50), 50, QPointF(150, 50)); |
|
298 gradient.setInterpolationMode(QGradient::ComponentInterpolation); |
|
299 gradient.setColorAt(0, Qt::red); |
|
300 gradient.setColorAt(1, Qt::blue); |
|
301 painter.fillRect(100, 0, 100, 100, gradient); |
|
302 painter.end(); |
|
303 |
|
304 checkFile(fileName); |
|
305 } |
|
306 |
|
307 void tst_QSvgGenerator::fileEncoding() |
|
308 { |
|
309 QTextCodec::setCodecForLocale(QTextCodec::codecForName("ISO-8859-1")); |
|
310 |
|
311 QByteArray byteArray; |
|
312 QBuffer buffer(&byteArray); |
|
313 |
|
314 QSvgGenerator generator; |
|
315 generator.setOutputDevice(&buffer); |
|
316 |
|
317 static const QChar unicode[] = { 'f', 'o', 'o', |
|
318 0x00F8, 'b', 'a', 'r'}; |
|
319 |
|
320 int size = sizeof(unicode) / sizeof(QChar); |
|
321 QString unicodeString = QString::fromRawData(unicode, size); |
|
322 |
|
323 QPainter painter(&generator); |
|
324 painter.drawText(100, 100, unicodeString); |
|
325 painter.end(); |
|
326 |
|
327 QVERIFY(byteArray.contains(unicodeString.toUtf8())); |
|
328 } |
|
329 |
|
330 void tst_QSvgGenerator::fractionalFontSize() |
|
331 { |
|
332 QByteArray byteArray; |
|
333 QBuffer buffer(&byteArray); |
|
334 |
|
335 QSvgGenerator generator; |
|
336 generator.setResolution(72); |
|
337 generator.setOutputDevice(&buffer); |
|
338 |
|
339 QPainter painter(&generator); |
|
340 QFont fractionalFont = painter.font(); |
|
341 fractionalFont.setPointSizeF(7.5); |
|
342 painter.setFont(fractionalFont); |
|
343 painter.drawText(100, 100, "foo"); |
|
344 painter.end(); |
|
345 |
|
346 QVERIFY(byteArray.contains("7.5")); |
|
347 } |
|
348 |
|
349 void tst_QSvgGenerator::titleAndDescription() |
|
350 { |
|
351 QByteArray byteArray; |
|
352 QBuffer buffer(&byteArray); |
|
353 |
|
354 QSvgGenerator generator; |
|
355 generator.setTitle("foo"); |
|
356 QCOMPARE(generator.title(), QString("foo")); |
|
357 generator.setDescription("bar"); |
|
358 QCOMPARE(generator.description(), QString("bar")); |
|
359 generator.setOutputDevice(&buffer); |
|
360 |
|
361 QPainter painter(&generator); |
|
362 painter.end(); |
|
363 |
|
364 QVERIFY(byteArray.contains("<title>foo</title>")); |
|
365 QVERIFY(byteArray.contains("<desc>bar</desc>")); |
|
366 } |
|
367 |
|
368 static void drawTestGradients(QPainter &painter) |
|
369 { |
|
370 int w = painter.device()->width(); |
|
371 int h = painter.device()->height(); |
|
372 if (w <= 0 || h <= 0) |
|
373 h = w = 72; |
|
374 |
|
375 QLinearGradient gradient(QPoint(0, 0), QPoint(1, 1)); |
|
376 gradient.setCoordinateMode(QGradient::ObjectBoundingMode); |
|
377 gradient.setColorAt(0, QColor(255, 0, 0, 0)); |
|
378 gradient.setColorAt(1, QColor(0, 0, 255, 255)); |
|
379 painter.fillRect(QRectF(0, 0, w/2, h/2), gradient); |
|
380 |
|
381 gradient.setInterpolationMode(QGradient::ComponentInterpolation); |
|
382 painter.fillRect(QRectF(0, h/2, w/2, h - h/2), gradient); |
|
383 |
|
384 gradient.setInterpolationMode(QGradient::ColorInterpolation); |
|
385 gradient.setColorAt(0, QColor(255, 0, 0, 123)); |
|
386 gradient.setColorAt(1, QColor(0, 0, 255, 123)); |
|
387 painter.fillRect(QRectF(w/2, 0, w - w/2, h/2), gradient); |
|
388 |
|
389 gradient.setInterpolationMode(QGradient::ComponentInterpolation); |
|
390 painter.fillRect(QRectF(w/2, h/2, w - w/2, h - h/2), gradient); |
|
391 } |
|
392 |
|
393 static qreal sqrImageDiff(const QImage &image1, const QImage &image2) |
|
394 { |
|
395 if (image1.size() != image2.size()) |
|
396 return 1e30; |
|
397 quint64 sum = 0; |
|
398 for (int y = 0; y < image1.height(); ++y) { |
|
399 const quint8 *line1 = reinterpret_cast<const quint8 *>(image1.scanLine(y)); |
|
400 const quint8 *line2 = reinterpret_cast<const quint8 *>(image2.scanLine(y)); |
|
401 for (int x = 0; x < image1.width() * 4; ++x) |
|
402 sum += quint64((int(line1[x]) - int(line2[x])) * (int(line1[x]) - int(line2[x]))); |
|
403 } |
|
404 return qreal(sum) / qreal(image1.width() * image1.height()); |
|
405 } |
|
406 |
|
407 void tst_QSvgGenerator::gradientInterpolation() |
|
408 { |
|
409 QByteArray byteArray; |
|
410 QPainter painter; |
|
411 QImage image(576, 576, QImage::Format_ARGB32_Premultiplied); |
|
412 QImage refImage(576, 576, QImage::Format_ARGB32_Premultiplied); |
|
413 image.fill(0x80208050); |
|
414 refImage.fill(0x80208050); |
|
415 |
|
416 { |
|
417 QSvgGenerator generator; |
|
418 QBuffer buffer(&byteArray); |
|
419 generator.setOutputDevice(&buffer); |
|
420 |
|
421 QVERIFY(painter.begin(&generator)); |
|
422 drawTestGradients(painter); |
|
423 painter.end(); |
|
424 } |
|
425 |
|
426 { |
|
427 QVERIFY(painter.begin(&image)); |
|
428 QSvgRenderer renderer(byteArray); |
|
429 renderer.render(&painter, image.rect()); |
|
430 painter.end(); |
|
431 } |
|
432 |
|
433 { |
|
434 QVERIFY(painter.begin(&refImage)); |
|
435 drawTestGradients(painter); |
|
436 painter.end(); |
|
437 } |
|
438 |
|
439 QVERIFY(sqrImageDiff(image, refImage) < 2); // pixel error < 1.41 (L2-norm) |
|
440 } |
|
441 |
|
442 QTEST_MAIN(tst_QSvgGenerator) |
|
443 #include "tst_qsvggenerator.moc" |