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#include "paintcommands.h"
30#include <qbaselinetest.h>
31#include <QDir>
32#include <QPainter>
33#include <QPdfWriter>
34#include <QTemporaryFile>
35#include <QProcess>
36
37#ifndef QT_NO_OPENGL
38#include <QOpenGLFramebufferObjectFormat>
39#include <QOpenGLContext>
40#include <QOpenGLPaintDevice>
41#endif
42
43#include <algorithm>
44
45#ifndef GL_RGB10
46#define GL_RGB10 0x8052
47#endif
48
49class tst_Lancelot : public QObject
50{
51Q_OBJECT
52
53public:
54 tst_Lancelot();
55
56private:
57 enum GraphicsEngine {
58 Raster = 0,
59 OpenGL = 1,
60 Pdf = 2
61 };
62
63 void setupTestSuite(const QStringList& blacklist = QStringList());
64 void runTestSuite(GraphicsEngine engine, QImage::Format format, const QSurfaceFormat &contextFormat = QSurfaceFormat());
65 void paint(QPaintDevice *device, GraphicsEngine engine, QImage::Format format, const QStringList &script, const QString &filePath);
66
67 QStringList qpsFiles;
68 QHash<QString, QStringList> scripts;
69 QHash<QString, quint16> scriptChecksums;
70 QString scriptsDir;
71
72private slots:
73 void initTestCase();
74 void cleanupTestCase() {}
75
76 void testRasterARGB32PM_data();
77 void testRasterARGB32PM();
78 void testRasterRGB32_data();
79 void testRasterRGB32();
80 void testRasterARGB32_data();
81 void testRasterARGB32();
82 void testRasterRGB16_data();
83 void testRasterRGB16();
84 void testRasterA2RGB30PM_data();
85 void testRasterA2RGB30PM();
86 void testRasterBGR30_data();
87 void testRasterBGR30();
88 void testRasterARGB8565PM_data();
89 void testRasterARGB8565PM();
90 void testRasterGrayscale8_data();
91 void testRasterGrayscale8();
92 void testRasterRGBA64PM_data();
93 void testRasterRGBA64PM();
94
95 void testPdf_data();
96 void testPdf();
97
98#ifndef QT_NO_OPENGL
99 void testOpenGL_data();
100 void testOpenGL();
101 void testOpenGLBGR30_data();
102 void testOpenGLBGR30();
103 void testCoreOpenGL_data();
104 void testCoreOpenGL();
105private:
106 bool checkSystemGLSupport();
107 bool checkSystemCoreGLSupport();
108#endif
109};
110
111tst_Lancelot::tst_Lancelot()
112{
113}
114
115void tst_Lancelot::initTestCase()
116{
117 // Check and setup the environment. We treat failures because of test environment
118 // (e.g. script files not found) as just warnings, and not QFAILs, to avoid false negatives
119 // caused by environment or server instability
120
121 QByteArray msg;
122 if (!QBaselineTest::connectToBaselineServer(msg: &msg))
123 QSKIP(msg);
124
125 QString baseDir = QFINDTESTDATA("scripts/text.qps");
126 scriptsDir = baseDir.left(n: baseDir.lastIndexOf(c: '/')) + '/';
127 QDir qpsDir(scriptsDir);
128 qpsFiles = qpsDir.entryList(nameFilters: QStringList() << QLatin1String("*.qps"), filters: QDir::Files | QDir::Readable);
129 if (qpsFiles.isEmpty()) {
130 QWARN("No qps script files found in " + qpsDir.path().toLatin1());
131 QSKIP("Aborted due to errors.");
132 }
133
134 std::sort(first: qpsFiles.begin(), last: qpsFiles.end());
135 foreach (const QString& fileName, qpsFiles) {
136 QFile file(scriptsDir + fileName);
137 file.open(flags: QFile::ReadOnly);
138 QByteArray cont = file.readAll();
139 scripts.insert(akey: fileName, avalue: QString::fromUtf8(str: cont).split(sep: QLatin1Char('\n'), behavior: Qt::SkipEmptyParts));
140 scriptChecksums.insert(akey: fileName, avalue: qChecksum(s: cont.constData(), len: cont.size()));
141 }
142}
143
144
145void tst_Lancelot::testRasterARGB32PM_data()
146{
147 setupTestSuite();
148}
149
150
151void tst_Lancelot::testRasterARGB32PM()
152{
153 runTestSuite(engine: Raster, format: QImage::Format_ARGB32_Premultiplied);
154}
155
156
157void tst_Lancelot::testRasterARGB32_data()
158{
159 setupTestSuite();
160}
161
162void tst_Lancelot::testRasterARGB32()
163{
164 runTestSuite(engine: Raster, format: QImage::Format_ARGB32);
165}
166
167
168void tst_Lancelot::testRasterRGB32_data()
169{
170 setupTestSuite();
171}
172
173
174void tst_Lancelot::testRasterRGB32()
175{
176 runTestSuite(engine: Raster, format: QImage::Format_RGB32);
177}
178
179
180void tst_Lancelot::testRasterRGB16_data()
181{
182 setupTestSuite();
183}
184
185
186void tst_Lancelot::testRasterRGB16()
187{
188 runTestSuite(engine: Raster, format: QImage::Format_RGB16);
189}
190
191
192void tst_Lancelot::testRasterA2RGB30PM_data()
193{
194 setupTestSuite();
195}
196
197
198void tst_Lancelot::testRasterA2RGB30PM()
199{
200 runTestSuite(engine: Raster, format: QImage::Format_A2RGB30_Premultiplied);
201}
202
203
204void tst_Lancelot::testRasterBGR30_data()
205{
206 setupTestSuite();
207}
208
209
210void tst_Lancelot::testRasterBGR30()
211{
212 runTestSuite(engine: Raster, format: QImage::Format_BGR30);
213}
214
215
216void tst_Lancelot::testRasterARGB8565PM_data()
217{
218 setupTestSuite();
219}
220
221void tst_Lancelot::testRasterARGB8565PM()
222{
223 runTestSuite(engine: Raster, format: QImage::Format_ARGB8565_Premultiplied);
224}
225
226
227void tst_Lancelot::testRasterGrayscale8_data()
228{
229 setupTestSuite();
230}
231
232void tst_Lancelot::testRasterGrayscale8()
233{
234 runTestSuite(engine: Raster, format: QImage::Format_Grayscale8);
235}
236
237
238void tst_Lancelot::testRasterRGBA64PM_data()
239{
240 setupTestSuite();
241}
242
243void tst_Lancelot::testRasterRGBA64PM()
244{
245 runTestSuite(engine: Raster, format: QImage::Format_RGBA64_Premultiplied);
246}
247
248
249void tst_Lancelot::testPdf_data()
250{
251#ifdef Q_OS_MACOS
252 setupTestSuite();
253#else
254 QSKIP("Pdf testing only implemented for macOS");
255#endif
256}
257
258void tst_Lancelot::testPdf()
259{
260 runTestSuite(engine: Pdf, format: QImage::Format_RGB32);
261}
262
263
264#ifndef QT_NO_OPENGL
265bool tst_Lancelot::checkSystemGLSupport()
266{
267 QWindow win;
268 win.setSurfaceType(QSurface::OpenGLSurface);
269 win.create();
270 QOpenGLFramebufferObjectFormat fmt;
271 fmt.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
272 fmt.setSamples(4);
273 QOpenGLContext ctx;
274 if (!ctx.create() || !ctx.makeCurrent(surface: &win))
275 return false;
276 QOpenGLFramebufferObject fbo(800, 800, fmt);
277 if (!fbo.isValid() || !fbo.bind())
278 return false;
279
280 return true;
281}
282
283bool tst_Lancelot::checkSystemCoreGLSupport()
284{
285 if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL)
286 return false;
287
288 QSurfaceFormat coreFormat;
289 coreFormat.setVersion(major: 3, minor: 2);
290 coreFormat.setProfile(QSurfaceFormat::CoreProfile);
291 QWindow win;
292 win.setSurfaceType(QSurface::OpenGLSurface);
293 win.setFormat(coreFormat);
294 win.create();
295 QOpenGLFramebufferObjectFormat fmt;
296 fmt.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
297 fmt.setSamples(4);
298 QOpenGLContext ctx;
299 ctx.setFormat(coreFormat);
300 if (!ctx.create() || !ctx.makeCurrent(surface: &win))
301 return false;
302 QOpenGLFramebufferObject fbo(800, 800, fmt);
303 if (!fbo.isValid() || !fbo.bind())
304 return false;
305
306 return true;
307}
308
309void tst_Lancelot::testOpenGL_data()
310{
311 if (!checkSystemGLSupport())
312 QSKIP("System under test does not meet preconditions for GL testing. Skipping.");
313 QStringList localBlacklist = QStringList() << QLatin1String("rasterops.qps");
314 setupTestSuite(localBlacklist);
315}
316
317
318void tst_Lancelot::testOpenGL()
319{
320 runTestSuite(engine: OpenGL, format: QImage::Format_RGB32);
321}
322
323void tst_Lancelot::testOpenGLBGR30_data()
324{
325 tst_Lancelot::testOpenGL_data();
326}
327
328void tst_Lancelot::testOpenGLBGR30()
329{
330 runTestSuite(engine: OpenGL, format: QImage::Format_BGR30);
331}
332
333void tst_Lancelot::testCoreOpenGL_data()
334{
335 if (!checkSystemCoreGLSupport())
336 QSKIP("System under test does not meet preconditions for Core Profile GL testing. Skipping.");
337 QStringList localBlacklist = QStringList() << QLatin1String("rasterops.qps");
338 setupTestSuite(localBlacklist);
339}
340
341void tst_Lancelot::testCoreOpenGL()
342{
343 QSurfaceFormat coreFormat;
344 coreFormat.setVersion(major: 3, minor: 2);
345 coreFormat.setProfile(QSurfaceFormat::CoreProfile);
346 runTestSuite(engine: OpenGL, format: QImage::Format_RGB32, contextFormat: coreFormat);
347}
348#endif
349
350
351void tst_Lancelot::setupTestSuite(const QStringList& blacklist)
352{
353 QTest::addColumn<QString>(name: "qpsFile");
354 foreach (const QString &fileName, qpsFiles) {
355 if (blacklist.contains(str: fileName))
356 continue;
357 QBaselineTest::newRow(dataTag: fileName.toLatin1(), checksum: scriptChecksums.value(akey: fileName)) << fileName;
358 }
359}
360
361
362void tst_Lancelot::runTestSuite(GraphicsEngine engine, QImage::Format format, const QSurfaceFormat &contextFormat)
363{
364 QFETCH(QString, qpsFile);
365
366 QString filePath = scriptsDir + qpsFile;
367 QStringList script = scripts.value(akey: qpsFile);
368 QImage rendered;
369
370 if (engine == Raster) {
371 QImage img(800, 800, format);
372 paint(device: &img, engine, format, script, filePath: QFileInfo(filePath).absoluteFilePath());
373 rendered = img;
374#ifndef QT_NO_OPENGL
375 } else if (engine == OpenGL) {
376 QWindow win;
377 win.setSurfaceType(QSurface::OpenGLSurface);
378 win.setFormat(contextFormat);
379 win.create();
380 QOpenGLFramebufferObjectFormat fmt;
381 fmt.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
382 fmt.setSamples(4);
383 if (format == QImage::Format_BGR30)
384 fmt.setInternalTextureFormat(GL_RGB10);
385 QOpenGLContext ctx;
386 ctx.setFormat(contextFormat);
387 QVERIFY(ctx.create());
388 QVERIFY(ctx.makeCurrent(&win));
389 QOpenGLFramebufferObject fbo(800, 800, fmt);
390 fbo.bind();
391 QOpenGLPaintDevice pdv(800, 800);
392 paint(device: &pdv, engine, format, script, filePath: QFileInfo(filePath).absoluteFilePath());
393 rendered = fbo.toImage().convertToFormat(f: format);
394#endif
395 } else if (engine == Pdf) {
396 QString tempStem(QDir::tempPath() + QLatin1String("/lancelot_XXXXXX_") + qpsFile.chopped(n: 4));
397
398 QTemporaryFile pdfFile(tempStem + QLatin1String(".pdf"));
399 pdfFile.open();
400 QPdfWriter writer(&pdfFile);
401 writer.setPdfVersion(QPdfWriter::PdfVersion_1_6);
402 writer.setResolution(150);
403 paint(device: &writer, engine, format, script, filePath: QFileInfo(filePath).absoluteFilePath());
404 pdfFile.close();
405
406 // Convert pdf to something we can read into a QImage, using macOS' sips utility
407 QTemporaryFile pngFile(tempStem + QLatin1String(".png"));
408 pngFile.open(); // Just create the file name
409 pngFile.close();
410 QProcess proc;
411 const char *rawArgs = "-s format png --cropOffset 20 20 -c 800 800 -o";
412 QStringList argList = QString::fromLatin1(str: rawArgs).split(sep: QLatin1Char(' '));
413 proc.start(program: QLatin1String("sips"), arguments: argList << pngFile.fileName() << pdfFile.fileName());
414 proc.waitForFinished(msecs: 2 * 60 * 1000); // May need some time
415
416 rendered = QImage(pngFile.fileName());
417 }
418
419 QBASELINE_TEST(rendered);
420}
421
422void tst_Lancelot::paint(QPaintDevice *device, GraphicsEngine engine, QImage::Format format, const QStringList &script, const QString &filePath)
423{
424 QPainter p(device);
425 PaintCommands pcmd(script, 800, 800, format);
426 //pcmd.setShouldDrawText(false);
427 switch (engine) {
428 case OpenGL:
429 pcmd.setType(OpenGLBufferType); // version/profile is communicated through the context's format()
430 break;
431 case Pdf:
432 pcmd.setType(PdfType);
433 break;
434 case Raster: // fallthrough
435 default:
436 pcmd.setType(ImageType);
437 break;
438 }
439 pcmd.setPainter(&p);
440 pcmd.setFilePath(filePath);
441 pcmd.runCommands();
442 p.end();
443}
444
445#define main _realmain
446QTEST_MAIN(tst_Lancelot)
447#undef main
448
449int main(int argc, char *argv[])
450{
451 qSetGlobalQHashSeed(newSeed: 0); // Avoid rendering variations caused by QHash randomization
452
453 QBaselineTest::handleCmdLineArgs(argcp: &argc, argvp: &argv);
454 return _realmain(argc, argv);
455}
456
457#include "tst_lancelot.moc"
458

source code of qtbase/tests/auto/other/lancelot/tst_lancelot.cpp