summaryrefslogtreecommitdiffstats
path: root/tests/baseline
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2021-11-15 13:36:48 +0100
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2021-11-16 14:01:50 +0100
commite8f93e38debf4f46dbda4de198b9dd475df42d5c (patch)
treec042e1fea11d2b63788f1b8855030ecd96e13c19 /tests/baseline
parent9a131b59ee561e300fb6078886a85dd7b3c53599 (diff)
Rename and restructure the baseline (lancelot) testing code
In preparation for addition of new baseline tests, establish a new test category, "baseline". This is similar to the category "benchmarks" in that it contains tests that use the QTest framework, but conceptually are not unit tests, in contrast to those under auto/. Move the existing QPainter baseline test, tst_lancelot, into this new category, and rename it accordingly. Baseline tests use the QBaselineTest extension to QTest. Move that extension too into the tests/baseline directory, allowing the clean out of the baselineserver directory. Pick-to: 6.2 Change-Id: I1b527f5867c953b1d22be73798fcf7d1494712ea Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io> Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'tests/baseline')
-rw-r--r--tests/baseline/CMakeLists.txt3
-rw-r--r--tests/baseline/painting/.gitignore1
-rw-r--r--tests/baseline/painting/CMakeLists.txt73
-rw-r--r--tests/baseline/painting/images.qrc34
-rw-r--r--tests/baseline/painting/images/alpha.pngbin0 -> 2422 bytes
-rw-r--r--tests/baseline/painting/images/alpha2x2.pngbin0 -> 78 bytes
-rw-r--r--tests/baseline/painting/images/bitmap.pngbin0 -> 254 bytes
-rw-r--r--tests/baseline/painting/images/border.pngbin0 -> 182 bytes
-rw-r--r--tests/baseline/painting/images/borderimage.pngbin0 -> 826 bytes
-rw-r--r--tests/baseline/painting/images/dome_argb32.pngbin0 -> 18234 bytes
-rw-r--r--tests/baseline/painting/images/dome_indexed.pngbin0 -> 7946 bytes
-rw-r--r--tests/baseline/painting/images/dome_indexed_mask.pngbin0 -> 5411 bytes
-rw-r--r--tests/baseline/painting/images/dome_mono.pngbin0 -> 1391 bytes
-rw-r--r--tests/baseline/painting/images/dome_mono_128.pngbin0 -> 2649 bytes
-rw-r--r--tests/baseline/painting/images/dome_mono_palette.pngbin0 -> 1404 bytes
-rw-r--r--tests/baseline/painting/images/dome_rgb32.pngbin0 -> 17890 bytes
-rw-r--r--tests/baseline/painting/images/dot.pngbin0 -> 287 bytes
-rw-r--r--tests/baseline/painting/images/face.pngbin0 -> 2414 bytes
-rw-r--r--tests/baseline/painting/images/gam030.pngbin0 -> 213 bytes
-rw-r--r--tests/baseline/painting/images/gam045.pngbin0 -> 216 bytes
-rw-r--r--tests/baseline/painting/images/gam056.pngbin0 -> 216 bytes
-rw-r--r--tests/baseline/painting/images/gam100.pngbin0 -> 205 bytes
-rw-r--r--tests/baseline/painting/images/gam200.pngbin0 -> 187 bytes
-rw-r--r--tests/baseline/painting/images/image.pngbin0 -> 169554 bytes
-rw-r--r--tests/baseline/painting/images/mask.pngbin0 -> 274 bytes
-rw-r--r--tests/baseline/painting/images/mask_100.pngbin0 -> 319 bytes
-rw-r--r--tests/baseline/painting/images/masked.pngbin0 -> 788 bytes
-rw-r--r--tests/baseline/painting/images/sign.pngbin0 -> 10647 bytes
-rw-r--r--tests/baseline/painting/images/solid.pngbin0 -> 607 bytes
-rw-r--r--tests/baseline/painting/images/solid2x2.pngbin0 -> 75 bytes
-rw-r--r--tests/baseline/painting/images/struct-image-01.jpgbin0 -> 4751 bytes
-rw-r--r--tests/baseline/painting/images/struct-image-01.pngbin0 -> 63238 bytes
-rw-r--r--tests/baseline/painting/images/zebra.pngbin0 -> 426 bytes
-rw-r--r--tests/baseline/painting/paintcommands.cpp2826
-rw-r--r--tests/baseline/painting/paintcommands.h348
-rw-r--r--tests/baseline/painting/scripts/aliasing.qps156
-rw-r--r--tests/baseline/painting/scripts/arcs.qps68
-rw-r--r--tests/baseline/painting/scripts/arcs2.qps54
-rw-r--r--tests/baseline/painting/scripts/background.qps136
-rw-r--r--tests/baseline/painting/scripts/background_brush.qps5
-rw-r--r--tests/baseline/painting/scripts/beziers.qps148
-rw-r--r--tests/baseline/painting/scripts/bitmaps.qps166
-rw-r--r--tests/baseline/painting/scripts/borderimage.qps120
-rw-r--r--tests/baseline/painting/scripts/brush_pens.qps104
-rw-r--r--tests/baseline/painting/scripts/brushes.qps88
-rw-r--r--tests/baseline/painting/scripts/clippath_antialiasing.qps76
-rw-r--r--tests/baseline/painting/scripts/clippaths.qps60
-rw-r--r--tests/baseline/painting/scripts/clipping.qps182
-rw-r--r--tests/baseline/painting/scripts/clipping_state.qps47
-rw-r--r--tests/baseline/painting/scripts/cliprects.qps59
-rw-r--r--tests/baseline/painting/scripts/conical_gradients.qps85
-rw-r--r--tests/baseline/painting/scripts/conical_gradients_perspectives.qps64
-rw-r--r--tests/baseline/painting/scripts/cosmetic.qps55
-rw-r--r--tests/baseline/painting/scripts/dashes.qps268
-rw-r--r--tests/baseline/painting/scripts/degeneratebeziers.qps47
-rw-r--r--tests/baseline/painting/scripts/deviceclipping.qps48
-rw-r--r--tests/baseline/painting/scripts/drawpoints.qps101
-rw-r--r--tests/baseline/painting/scripts/ellipses.qps86
-rw-r--r--tests/baseline/painting/scripts/fillrect.qps121
-rw-r--r--tests/baseline/painting/scripts/fillrect_aa.qps121
-rw-r--r--tests/baseline/painting/scripts/filltest.qps413
-rw-r--r--tests/baseline/painting/scripts/glyphruns.qps175
-rw-r--r--tests/baseline/painting/scripts/gradients.qps44
-rw-r--r--tests/baseline/painting/scripts/gradientxform_device.qps67
-rw-r--r--tests/baseline/painting/scripts/gradientxform_logical.qps67
-rw-r--r--tests/baseline/painting/scripts/gradientxform_object.qps83
-rw-r--r--tests/baseline/painting/scripts/hinting.qps26
-rw-r--r--tests/baseline/painting/scripts/image_dpr.qps43
-rw-r--r--tests/baseline/painting/scripts/image_formats.qps81
-rw-r--r--tests/baseline/painting/scripts/images.qps106
-rw-r--r--tests/baseline/painting/scripts/images2.qps145
-rw-r--r--tests/baseline/painting/scripts/join_cap_styles.qps63
-rw-r--r--tests/baseline/painting/scripts/join_cap_styles_duplicate_control_points.qps68
-rw-r--r--tests/baseline/painting/scripts/linear_gradients.qps144
-rw-r--r--tests/baseline/painting/scripts/linear_gradients_perspectives.qps62
-rw-r--r--tests/baseline/painting/scripts/linear_resolving_gradients.qps66
-rw-r--r--tests/baseline/painting/scripts/lineconsistency.qps72
-rw-r--r--tests/baseline/painting/scripts/linedashes.qps132
-rw-r--r--tests/baseline/painting/scripts/linedashes2.qps196
-rw-r--r--tests/baseline/painting/scripts/linedashes2_aa.qps5
-rw-r--r--tests/baseline/painting/scripts/lines.qps433
-rw-r--r--tests/baseline/painting/scripts/lines2.qps179
-rw-r--r--tests/baseline/painting/scripts/lines3.qps171
-rw-r--r--tests/baseline/painting/scripts/pathfill.qps38
-rw-r--r--tests/baseline/painting/scripts/paths.qps49
-rw-r--r--tests/baseline/painting/scripts/paths_aa.qps4
-rw-r--r--tests/baseline/painting/scripts/pens.qps133
-rw-r--r--tests/baseline/painting/scripts/pens_aa.qps6
-rw-r--r--tests/baseline/painting/scripts/pens_cosmetic.qps116
-rw-r--r--tests/baseline/painting/scripts/perspectives.qps72
-rw-r--r--tests/baseline/painting/scripts/perspectives2.qps309
-rw-r--r--tests/baseline/painting/scripts/pixmap_rotation.qps31
-rw-r--r--tests/baseline/painting/scripts/pixmap_rotation2.qps8
-rw-r--r--tests/baseline/painting/scripts/pixmap_scaling.qps224
-rw-r--r--tests/baseline/painting/scripts/pixmap_subpixel.qps117
-rw-r--r--tests/baseline/painting/scripts/pixmaps.qps106
-rw-r--r--tests/baseline/painting/scripts/porter_duff.qps251
-rw-r--r--tests/baseline/painting/scripts/porter_duff2.qps261
-rw-r--r--tests/baseline/painting/scripts/primitives.qps184
-rw-r--r--tests/baseline/painting/scripts/radial_gradients.qps99
-rw-r--r--tests/baseline/painting/scripts/radial_gradients_perspectives.qps62
-rw-r--r--tests/baseline/painting/scripts/rasterops.qps87
-rw-r--r--tests/baseline/painting/scripts/richtext.qps9
-rw-r--r--tests/baseline/painting/scripts/sizes.qps90
-rw-r--r--tests/baseline/painting/scripts/smallcaps_path.qps9
-rw-r--r--tests/baseline/painting/scripts/statictext.qps175
-rw-r--r--tests/baseline/painting/scripts/text.qps199
-rw-r--r--tests/baseline/painting/scripts/text_perspectives.qps102
-rw-r--r--tests/baseline/painting/scripts/thinlines.qps79
-rw-r--r--tests/baseline/painting/scripts/tiled_pixmap.qps84
-rw-r--r--tests/baseline/painting/scripts/tinydashes.qps34
-rw-r--r--tests/baseline/painting/tst_baseline_painting.cpp489
-rw-r--r--tests/baseline/shared/baselineprotocol.cpp546
-rw-r--r--tests/baseline/shared/baselineprotocol.h187
-rw-r--r--tests/baseline/shared/baselineprotocol.pri10
-rw-r--r--tests/baseline/shared/lookup3.cpp846
-rw-r--r--tests/baseline/shared/qbaselinetest.cpp423
-rw-r--r--tests/baseline/shared/qbaselinetest.h70
-rw-r--r--tests/baseline/shared/qbaselinetest.pri13
119 files changed, 14113 insertions, 0 deletions
diff --git a/tests/baseline/CMakeLists.txt b/tests/baseline/CMakeLists.txt
new file mode 100644
index 0000000000..935df36ef9
--- /dev/null
+++ b/tests/baseline/CMakeLists.txt
@@ -0,0 +1,3 @@
+if(TARGET Qt::Network)
+ add_subdirectory(painting)
+endif()
diff --git a/tests/baseline/painting/.gitignore b/tests/baseline/painting/.gitignore
new file mode 100644
index 0000000000..0a70416d57
--- /dev/null
+++ b/tests/baseline/painting/.gitignore
@@ -0,0 +1 @@
+tst_lancelot
diff --git a/tests/baseline/painting/CMakeLists.txt b/tests/baseline/painting/CMakeLists.txt
new file mode 100644
index 0000000000..95a006da75
--- /dev/null
+++ b/tests/baseline/painting/CMakeLists.txt
@@ -0,0 +1,73 @@
+#####################################################################
+## tst_baseline_painting Test:
+#####################################################################
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ scripts/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_baseline_painting
+ SOURCES
+ ../shared/baselineprotocol.cpp ../shared/baselineprotocol.h ../shared/lookup3.cpp
+ ../shared/qbaselinetest.cpp ../shared/qbaselinetest.h
+ paintcommands.cpp paintcommands.h
+ tst_baseline_painting.cpp
+ INCLUDE_DIRECTORIES
+ ../shared
+ PUBLIC_LIBRARIES
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::Network
+ TESTDATA ${test_data}
+)
+
+# Resources:
+set(images_resource_files
+ "images/alpha.png"
+ "images/alpha2x2.png"
+ "images/bitmap.png"
+ "images/border.png"
+ "images/borderimage.png"
+ "images/dome_argb32.png"
+ "images/dome_indexed.png"
+ "images/dome_indexed_mask.png"
+ "images/dome_mono.png"
+ "images/dome_mono_128.png"
+ "images/dome_mono_palette.png"
+ "images/dome_rgb32.png"
+ "images/dot.png"
+ "images/face.png"
+ "images/gam030.png"
+ "images/gam045.png"
+ "images/gam056.png"
+ "images/gam100.png"
+ "images/gam200.png"
+ "images/image.png"
+ "images/mask.png"
+ "images/mask_100.png"
+ "images/masked.png"
+ "images/sign.png"
+ "images/solid.png"
+ "images/solid2x2.png"
+ "images/struct-image-01.jpg"
+ "images/struct-image-01.png"
+ "images/zebra.png"
+)
+
+qt_internal_add_resource(tst_baseline_painting "images"
+ PREFIX
+ "/"
+ FILES
+ ${images_resource_files}
+)
+
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_baseline_painting CONDITION QT_FEATURE_opengl
+ PUBLIC_LIBRARIES
+ Qt::OpenGL
+)
diff --git a/tests/baseline/painting/images.qrc b/tests/baseline/painting/images.qrc
new file mode 100644
index 0000000000..060b52c85a
--- /dev/null
+++ b/tests/baseline/painting/images.qrc
@@ -0,0 +1,34 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+<qresource>
+ <file>images/alpha.png</file>
+ <file>images/border.png</file>
+ <file>images/borderimage.png</file>
+ <file>images/dome_argb32.png</file>
+ <file>images/dome_indexed.png</file>
+ <file>images/dome_mono_palette.png</file>
+ <file>images/dome_rgb32.png</file>
+ <file>images/face.png</file>
+ <file>images/gam045.png</file>
+ <file>images/gam100.png</file>
+ <file>images/image.png</file>
+ <file>images/masked.png</file>
+ <file>images/sign.png</file>
+ <file>images/struct-image-01.jpg</file>
+ <file>images/bitmap.png</file>
+ <file>images/dome_indexed_mask.png</file>
+ <file>images/dome_mono_128.png</file>
+ <file>images/dome_mono.png</file>
+ <file>images/dot.png</file>
+ <file>images/gam030.png</file>
+ <file>images/gam056.png</file>
+ <file>images/gam200.png</file>
+ <file>images/mask_100.png</file>
+ <file>images/mask.png</file>
+ <file>images/solid.png</file>
+ <file>images/struct-image-01.png</file>
+ <file>images/zebra.png</file>
+ <file>images/alpha2x2.png</file>
+ <file>images/solid2x2.png</file>
+</qresource>
+</RCC>
diff --git a/tests/baseline/painting/images/alpha.png b/tests/baseline/painting/images/alpha.png
new file mode 100644
index 0000000000..e465b2586d
--- /dev/null
+++ b/tests/baseline/painting/images/alpha.png
Binary files differ
diff --git a/tests/baseline/painting/images/alpha2x2.png b/tests/baseline/painting/images/alpha2x2.png
new file mode 100644
index 0000000000..8e99feb4cc
--- /dev/null
+++ b/tests/baseline/painting/images/alpha2x2.png
Binary files differ
diff --git a/tests/baseline/painting/images/bitmap.png b/tests/baseline/painting/images/bitmap.png
new file mode 100644
index 0000000000..d21f8f51bb
--- /dev/null
+++ b/tests/baseline/painting/images/bitmap.png
Binary files differ
diff --git a/tests/baseline/painting/images/border.png b/tests/baseline/painting/images/border.png
new file mode 100644
index 0000000000..a3d2fed0a3
--- /dev/null
+++ b/tests/baseline/painting/images/border.png
Binary files differ
diff --git a/tests/baseline/painting/images/borderimage.png b/tests/baseline/painting/images/borderimage.png
new file mode 100644
index 0000000000..f7f6b66227
--- /dev/null
+++ b/tests/baseline/painting/images/borderimage.png
Binary files differ
diff --git a/tests/baseline/painting/images/dome_argb32.png b/tests/baseline/painting/images/dome_argb32.png
new file mode 100644
index 0000000000..e3ccba0c13
--- /dev/null
+++ b/tests/baseline/painting/images/dome_argb32.png
Binary files differ
diff --git a/tests/baseline/painting/images/dome_indexed.png b/tests/baseline/painting/images/dome_indexed.png
new file mode 100644
index 0000000000..beefcd514e
--- /dev/null
+++ b/tests/baseline/painting/images/dome_indexed.png
Binary files differ
diff --git a/tests/baseline/painting/images/dome_indexed_mask.png b/tests/baseline/painting/images/dome_indexed_mask.png
new file mode 100644
index 0000000000..a62f29f40e
--- /dev/null
+++ b/tests/baseline/painting/images/dome_indexed_mask.png
Binary files differ
diff --git a/tests/baseline/painting/images/dome_mono.png b/tests/baseline/painting/images/dome_mono.png
new file mode 100644
index 0000000000..950c2a7494
--- /dev/null
+++ b/tests/baseline/painting/images/dome_mono.png
Binary files differ
diff --git a/tests/baseline/painting/images/dome_mono_128.png b/tests/baseline/painting/images/dome_mono_128.png
new file mode 100644
index 0000000000..77e48aaab7
--- /dev/null
+++ b/tests/baseline/painting/images/dome_mono_128.png
Binary files differ
diff --git a/tests/baseline/painting/images/dome_mono_palette.png b/tests/baseline/painting/images/dome_mono_palette.png
new file mode 100644
index 0000000000..dca3f59245
--- /dev/null
+++ b/tests/baseline/painting/images/dome_mono_palette.png
Binary files differ
diff --git a/tests/baseline/painting/images/dome_rgb32.png b/tests/baseline/painting/images/dome_rgb32.png
new file mode 100644
index 0000000000..27bc02a545
--- /dev/null
+++ b/tests/baseline/painting/images/dome_rgb32.png
Binary files differ
diff --git a/tests/baseline/painting/images/dot.png b/tests/baseline/painting/images/dot.png
new file mode 100644
index 0000000000..17a7b6a0ba
--- /dev/null
+++ b/tests/baseline/painting/images/dot.png
Binary files differ
diff --git a/tests/baseline/painting/images/face.png b/tests/baseline/painting/images/face.png
new file mode 100644
index 0000000000..4f6172d83b
--- /dev/null
+++ b/tests/baseline/painting/images/face.png
Binary files differ
diff --git a/tests/baseline/painting/images/gam030.png b/tests/baseline/painting/images/gam030.png
new file mode 100644
index 0000000000..904c9721bd
--- /dev/null
+++ b/tests/baseline/painting/images/gam030.png
Binary files differ
diff --git a/tests/baseline/painting/images/gam045.png b/tests/baseline/painting/images/gam045.png
new file mode 100644
index 0000000000..b649a8a54f
--- /dev/null
+++ b/tests/baseline/painting/images/gam045.png
Binary files differ
diff --git a/tests/baseline/painting/images/gam056.png b/tests/baseline/painting/images/gam056.png
new file mode 100644
index 0000000000..e5f959dc96
--- /dev/null
+++ b/tests/baseline/painting/images/gam056.png
Binary files differ
diff --git a/tests/baseline/painting/images/gam100.png b/tests/baseline/painting/images/gam100.png
new file mode 100644
index 0000000000..6c7ba5f1ed
--- /dev/null
+++ b/tests/baseline/painting/images/gam100.png
Binary files differ
diff --git a/tests/baseline/painting/images/gam200.png b/tests/baseline/painting/images/gam200.png
new file mode 100644
index 0000000000..daa20fcbc4
--- /dev/null
+++ b/tests/baseline/painting/images/gam200.png
Binary files differ
diff --git a/tests/baseline/painting/images/image.png b/tests/baseline/painting/images/image.png
new file mode 100644
index 0000000000..85d486a790
--- /dev/null
+++ b/tests/baseline/painting/images/image.png
Binary files differ
diff --git a/tests/baseline/painting/images/mask.png b/tests/baseline/painting/images/mask.png
new file mode 100644
index 0000000000..c3f3b1b6ca
--- /dev/null
+++ b/tests/baseline/painting/images/mask.png
Binary files differ
diff --git a/tests/baseline/painting/images/mask_100.png b/tests/baseline/painting/images/mask_100.png
new file mode 100644
index 0000000000..fc950dc7ed
--- /dev/null
+++ b/tests/baseline/painting/images/mask_100.png
Binary files differ
diff --git a/tests/baseline/painting/images/masked.png b/tests/baseline/painting/images/masked.png
new file mode 100644
index 0000000000..6debec534d
--- /dev/null
+++ b/tests/baseline/painting/images/masked.png
Binary files differ
diff --git a/tests/baseline/painting/images/sign.png b/tests/baseline/painting/images/sign.png
new file mode 100644
index 0000000000..6aac7e150a
--- /dev/null
+++ b/tests/baseline/painting/images/sign.png
Binary files differ
diff --git a/tests/baseline/painting/images/solid.png b/tests/baseline/painting/images/solid.png
new file mode 100644
index 0000000000..371e9c1aee
--- /dev/null
+++ b/tests/baseline/painting/images/solid.png
Binary files differ
diff --git a/tests/baseline/painting/images/solid2x2.png b/tests/baseline/painting/images/solid2x2.png
new file mode 100644
index 0000000000..f34562f964
--- /dev/null
+++ b/tests/baseline/painting/images/solid2x2.png
Binary files differ
diff --git a/tests/baseline/painting/images/struct-image-01.jpg b/tests/baseline/painting/images/struct-image-01.jpg
new file mode 100644
index 0000000000..a74e07223b
--- /dev/null
+++ b/tests/baseline/painting/images/struct-image-01.jpg
Binary files differ
diff --git a/tests/baseline/painting/images/struct-image-01.png b/tests/baseline/painting/images/struct-image-01.png
new file mode 100644
index 0000000000..4ed08406dc
--- /dev/null
+++ b/tests/baseline/painting/images/struct-image-01.png
Binary files differ
diff --git a/tests/baseline/painting/images/zebra.png b/tests/baseline/painting/images/zebra.png
new file mode 100644
index 0000000000..ef35f20785
--- /dev/null
+++ b/tests/baseline/painting/images/zebra.png
Binary files differ
diff --git a/tests/baseline/painting/paintcommands.cpp b/tests/baseline/painting/paintcommands.cpp
new file mode 100644
index 0000000000..d2e48688f9
--- /dev/null
+++ b/tests/baseline/painting/paintcommands.cpp
@@ -0,0 +1,2826 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "paintcommands.h"
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qpainter.h>
+#include <qpainterpath.h>
+#include <qbitmap.h>
+#include <qtextstream.h>
+#include <qtextlayout.h>
+#include <qdebug.h>
+#include <QStaticText>
+#include <QTextDocument>
+#include <private/qimage_p.h>
+
+#ifndef QT_NO_OPENGL
+#include <QOpenGLFramebufferObjectFormat>
+#include <QOpenGLContext>
+#include <QOpenGLPaintDevice>
+#endif
+
+/*********************************************************************************
+** everything to populate static tables
+**********************************************************************************/
+const char *PaintCommands::brushStyleTable[] = {
+ "NoBrush",
+ "SolidPattern",
+ "Dense1Pattern",
+ "Dense2Pattern",
+ "Dense3Pattern",
+ "Dense4Pattern",
+ "Dense5Pattern",
+ "Dense6Pattern",
+ "Dense7Pattern",
+ "HorPattern",
+ "VerPattern",
+ "CrossPattern",
+ "BDiagPattern",
+ "FDiagPattern",
+ "DiagCrossPattern",
+ "LinearGradientPattern"
+};
+
+const char *PaintCommands::penStyleTable[] = {
+ "NoPen",
+ "SolidLine",
+ "DashLine",
+ "DotLine",
+ "DashDotLine",
+ "DashDotDotLine"
+};
+
+const char *PaintCommands::fontWeightTable[] = {
+ "Light",
+ "Normal",
+ "DemiBold",
+ "Bold",
+ "Black"
+};
+
+const char *PaintCommands::fontHintingTable[] = {
+ "Default",
+ "None",
+ "Vertical",
+ "Full"
+};
+
+const char *PaintCommands::fontCapitalizationTable[] = {
+ "MixedCase",
+ "AllUppercase",
+ "AllLowercase",
+ "SmallCaps",
+ "Capitalize"
+};
+
+const char *PaintCommands::clipOperationTable[] = {
+ "NoClip",
+ "ReplaceClip",
+ "IntersectClip",
+ "UniteClip"
+};
+
+const char *PaintCommands::spreadMethodTable[] = {
+ "PadSpread",
+ "ReflectSpread",
+ "RepeatSpread"
+};
+
+const char *PaintCommands::coordinateMethodTable[] = {
+ "LogicalMode",
+ "StretchToDeviceMode",
+ "ObjectBoundingMode",
+ "ObjectMode"
+};
+
+const char *PaintCommands::sizeModeTable[] = {
+ "AbsoluteSize",
+ "RelativeSize"
+};
+
+const char *PaintCommands::compositionModeTable[] = {
+ "SourceOver",
+ "DestinationOver",
+ "Clear",
+ "Source",
+ "Destination",
+ "SourceIn",
+ "DestinationIn",
+ "SourceOut",
+ "DestinationOut",
+ "SourceAtop",
+ "DestinationAtop",
+ "Xor",
+ "Plus",
+ "Multiply",
+ "Screen",
+ "Overlay",
+ "Darken",
+ "Lighten",
+ "ColorDodge",
+ "ColorBurn",
+ "HardLight",
+ "SoftLight",
+ "Difference",
+ "Exclusion",
+ "SourceOrDestination",
+ "SourceAndDestination",
+ "SourceXorDestination",
+ "NotSourceAndNotDestination",
+ "NotSourceOrNotDestination",
+ "NotSourceXorDestination",
+ "NotSource",
+ "NotSourceAndDestination",
+ "SourceAndNotDestination"
+};
+
+const char *PaintCommands::imageFormatTable[] = {
+ "Invalid",
+ "Mono",
+ "MonoLSB",
+ "Indexed8",
+ "RGB32",
+ "ARGB32",
+ "ARGB32_Premultiplied",
+ "Format_RGB16",
+ "Format_ARGB8565_Premultiplied",
+ "Format_RGB666",
+ "Format_ARGB6666_Premultiplied",
+ "Format_RGB555",
+ "Format_ARGB8555_Premultiplied",
+ "Format_RGB888",
+ "Format_RGB444",
+ "Format_ARGB4444_Premultiplied",
+ "Format_RGBX8888",
+ "Format_RGBA8888",
+ "Format_RGBA8888_Premultiplied",
+ "Format_BGR30",
+ "Format_A2BGR30_Premultiplied",
+ "Format_RGB30",
+ "Format_A2RGB30_Premultiplied",
+ "Alpha8",
+ "Grayscale8",
+ "RGBx64",
+ "RGBA64",
+ "RGBA64_Premultiplied",
+ "Grayscale16",
+ "BGR888",
+ "RGBx16FPx4",
+ "RGBA16FPx4",
+ "RGBA16FPx4_Premultiplied",
+ "RGBx32FPx4",
+ "RGBA32FPx4",
+ "RGBA32FPx4_Premultiplied",
+};
+
+int PaintCommands::translateEnum(const char *table[], const QString &pattern, int limit)
+{
+ QByteArray p = pattern.toLatin1().toLower();
+ for (int i=0; i<limit; ++i)
+ if (p == QByteArray::fromRawData(table[i], qstrlen(table[i])).toLower())
+ return i;
+ return -1;
+}
+
+QList<PaintCommands::PaintCommandInfos> PaintCommands::s_commandInfoTable = QList<PaintCommands::PaintCommandInfos>();
+QList<QPair<QString,QStringList> > PaintCommands::s_enumsTable = QList<QPair<QString,QStringList> >();
+QMultiHash<QString, int> PaintCommands::s_commandHash;
+
+#define DECL_PAINTCOMMAND(identifier, method, regexp, syntax, sample) \
+ s_commandInfoTable << PaintCommandInfos(QLatin1String(identifier), &PaintCommands::method, QRegularExpression(regexp), \
+ QLatin1String(syntax), QLatin1String(sample) );
+
+#define DECL_PAINTCOMMANDSECTION(title) \
+ s_commandInfoTable << PaintCommandInfos(QLatin1String(title));
+
+#define ADD_ENUMLIST(listCaption, cStrArray) { \
+ QStringList list; \
+ for (int i=0; i<int(sizeof(cStrArray)/sizeof(char*)); i++) \
+ list << cStrArray[i]; \
+ s_enumsTable << qMakePair(QString(listCaption), list); \
+ }
+
+void PaintCommands::staticInit()
+{
+ // check if already done
+ if (!s_commandInfoTable.isEmpty()) return;
+
+ // populate the command list
+ DECL_PAINTCOMMANDSECTION("misc");
+ DECL_PAINTCOMMAND("comment", command_comment,
+ "^\\s*#",
+ "# this is some comments",
+ "# place your comments here");
+ DECL_PAINTCOMMAND("import", command_import,
+ "^import\\s+\"(.*)\"$",
+ "import <qrcFilename>",
+ "import \"myfile.qrc\"");
+ DECL_PAINTCOMMAND("begin_block", command_begin_block,
+ "^begin_block\\s+(\\w*)$",
+ "begin_block <blockName>",
+ "begin_block blockName");
+ DECL_PAINTCOMMAND("end_block", command_end_block,
+ "^end_block\\s*(\\w*)$",
+ "end_block [blockName]",
+ "end_block blockName");
+ DECL_PAINTCOMMAND("repeat_block", command_repeat_block,
+ "^repeat_block\\s+(\\w*)$",
+ "repeat_block <blockName>",
+ "repeat_block blockName");
+ DECL_PAINTCOMMAND("textlayout_draw", command_textlayout_draw,
+ "^textlayout_draw\\s+\"(.*)\"\\s+([0-9.]*)$",
+ "textlayout_draw <text> <width>",
+ "textlayout_draw \"your text\" 1.0");
+ DECL_PAINTCOMMAND("abort", command_abort,
+ "^abort$",
+ "abort",
+ "abort");
+ DECL_PAINTCOMMAND("noop", command_noop,
+ "^$",
+ "-",
+ "\n");
+
+ DECL_PAINTCOMMANDSECTION("setters");
+ DECL_PAINTCOMMAND("setBackgroundMode", command_setBgMode,
+ "^(setBackgroundMode|setBgMode)\\s+(\\w*)$",
+ "setBackgroundMode <OpaqueMode|TransparentMode>",
+ "setBackgroundMode TransparentMode");
+ DECL_PAINTCOMMAND("setBackground", command_setBackground,
+ "^setBackground\\s+#?(\\w*)\\s*(\\w*)?$",
+ "setBackground <color> [brush style enum]",
+ "setBackground black SolidPattern");
+ DECL_PAINTCOMMAND("setOpacity", command_setOpacity,
+ "^setOpacity\\s+(-?\\d*\\.?\\d*)$",
+ "setOpacity <opacity>\n - opacity is in [0,1]",
+ "setOpacity 1.0");
+ DECL_PAINTCOMMAND("path_setFillRule", command_path_setFillRule,
+ "^path_setFillRule\\s+(\\w*)\\s+(\\w*)$",
+ "path_setFillRule <pathName> [Winding|OddEven]",
+ "path_setFillRule pathName Winding");
+ DECL_PAINTCOMMAND("setBrush", command_setBrush,
+ "^setBrush\\s+(#?[\\w.:\\/]*)\\s*(\\w*)?$",
+ "setBrush <imageFileName>\nsetBrush noBrush\nsetBrush <color> <brush style enum>",
+ "setBrush white SolidPattern");
+ DECL_PAINTCOMMAND("setBrushOrigin", command_setBrushOrigin,
+ "^setBrushOrigin\\s*(-?\\w*)\\s+(-?\\w*)$",
+ "setBrushOrigin <dx> <dy>",
+ "setBrushOrigin 0 0");
+ DECL_PAINTCOMMAND("brushTranslate", command_brushTranslate,
+ "^brushTranslate\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "brushTranslate <tx> <ty>",
+ "brushTranslate 0.0 0.0");
+ DECL_PAINTCOMMAND("brushScale", command_brushScale,
+ "^brushScale\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "brushScale <kx> <ky>",
+ "brushScale 0.0 0.0");
+ DECL_PAINTCOMMAND("brushRotate", command_brushRotate,
+ "^brushRotate\\s+(-?[\\w.]*)$",
+ "brushRotate <angle>\n - angle in degrees",
+ "brushRotate 0.0");
+ DECL_PAINTCOMMAND("brushShear", command_brushShear,
+ "^brushShear\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "brushShear <sx> <sy>",
+ "brushShear 0.0 0.0");
+ DECL_PAINTCOMMAND("setCompositionMode", command_setCompositionMode,
+ "^setCompositionMode\\s+([\\w_0-9]*)$",
+ "setCompositionMode <composition mode enum>",
+ "setCompositionMode SourceOver");
+ DECL_PAINTCOMMAND("setFont", command_setFont,
+ "^setFont\\s+\"([\\w\\s]*)\"\\s*(\\w*)\\s*(\\w*)\\s*(\\w*)\\s*(\\w*)\\s*(\\w*)\\s*(\\w*)\\s*(\\w*)\\s*(\\w*)$",
+ "setFont <fontFace> [size] [font weight|font weight enum] [italic] [hinting enum] [underline] [strikeout] [overline] [capitalization enum]\n - font weight is an integer between 0 and 99",
+ "setFont \"times\" 12");
+ DECL_PAINTCOMMAND("setPen", command_setPen,
+ "^setPen\\s+#?(\\w*)$",
+ "setPen <color>\nsetPen <pen style enum>\nsetPen brush",
+ "setPen black");
+ DECL_PAINTCOMMAND("setPen", command_setPen2,
+ "^setPen\\s+(#?\\w*)\\s+([\\w.]+)\\s*(\\w*)\\s*(\\w*)\\s*(\\w*)$",
+ "setPen brush|<color> [width] [pen style enum] [FlatCap|SquareCap|RoundCap] [MiterJoin|BevelJoin|RoundJoin]",
+ "setPen black 1 FlatCap MiterJoin");
+ DECL_PAINTCOMMAND("pen_setDashOffset", command_pen_setDashOffset,
+ "^pen_setDashOffset\\s+(-?[\\w.]+)$",
+ "pen_setDashOffset <offset>\n",
+ "pen_setDashOffset 1.0");
+ DECL_PAINTCOMMAND("pen_setDashPattern", command_pen_setDashPattern,
+ "^pen_setDashPattern\\s+\\[([\\w\\s.]*)\\]$",
+ "pen_setDashPattern <[ <dash_1> <space_1> ... <dash_n> <space_n> ]>",
+ "pen_setDashPattern [ 2 1 4 1 3 3 ]");
+ DECL_PAINTCOMMAND("pen_setCosmetic", command_pen_setCosmetic,
+ "^pen_setCosmetic\\s+(\\w*)$",
+ "pen_setCosmetic <true|false>",
+ "pen_setCosmetic true");
+ DECL_PAINTCOMMAND("setRenderHint", command_setRenderHint,
+ "^setRenderHint\\s+([\\w_0-9]*)\\s*(\\w*)$",
+ "setRenderHint <Antialiasing|SmoothPixmapTransform> <true|false>",
+ "setRenderHint Antialiasing true");
+ DECL_PAINTCOMMAND("clearRenderHint", command_clearRenderHint,
+ "^clearRenderHint$",
+ "clearRenderHint",
+ "clearRenderHint");
+
+ DECL_PAINTCOMMANDSECTION("gradients");
+ DECL_PAINTCOMMAND("gradient_appendStop", command_gradient_appendStop,
+ "^gradient_appendStop\\s+([\\w.]*)\\s+#?(\\w*)$",
+ "gradient_appendStop <pos> <color>",
+ "gradient_appendStop 1.0 red");
+ DECL_PAINTCOMMAND("gradient_clearStops", command_gradient_clearStops,
+ "^gradient_clearStops$",
+ "gradient_clearStops",
+ "gradient_clearStops");
+ DECL_PAINTCOMMAND("gradient_setConical", command_gradient_setConical,
+ "^gradient_setConical\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)$",
+ "gradient_setConical <cx> <cy> <angle>\n - angle in degrees",
+ "gradient_setConical 5.0 5.0 45.0");
+ DECL_PAINTCOMMAND("gradient_setLinear", command_gradient_setLinear,
+ "^gradient_setLinear\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)$",
+ "gradient_setLinear <x1> <y1> <x2> <y2>",
+ "gradient_setLinear 1.0 1.0 2.0 2.0");
+ DECL_PAINTCOMMAND("gradient_setRadial", command_gradient_setRadial,
+ "^gradient_setRadial\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$",
+ "gradient_setRadial <cx> <cy> <rad> <fx> <fy>\n - C is the center\n - rad is the radius\n - F is the focal point",
+ "gradient_setRadial 1.0 1.0 45.0 2.0 2.0");
+ DECL_PAINTCOMMAND("gradient_setRadialExtended", command_gradient_setRadialExtended,
+ "^gradient_setRadialExtended\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$",
+ "gradient_setRadialExtended <cx> <cy> <rad> <fx> <fy> <frad>\n - C is the center\n - rad is the center radius\n - F is the focal point\n - frad is the focal radius",
+ "gradient_setRadialExtended 1.0 1.0 45.0 2.0 2.0 45.0");
+ DECL_PAINTCOMMAND("gradient_setLinearPen", command_gradient_setLinearPen,
+ "^gradient_setLinearPen\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)$",
+ "gradient_setLinearPen <x1> <y1> <x2> <y2>",
+ "gradient_setLinearPen 1.0 1.0 2.0 2.0");
+ DECL_PAINTCOMMAND("gradient_setSpread", command_gradient_setSpread,
+ "^gradient_setSpread\\s+(\\w*)$",
+ "gradient_setSpread <spread method enum>",
+ "gradient_setSpread PadSpread");
+ DECL_PAINTCOMMAND("gradient_setCoordinateMode", command_gradient_setCoordinateMode,
+ "^gradient_setCoordinateMode\\s+(\\w*)$",
+ "gradient_setCoordinateMode <coordinate method enum>",
+ "gradient_setCoordinateMode ObjectBoundingMode");
+
+ DECL_PAINTCOMMANDSECTION("drawing ops");
+ DECL_PAINTCOMMAND("drawPoint", command_drawPoint,
+ "^drawPoint\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "drawPoint <x> <y>",
+ "drawPoint 10.0 10.0");
+ DECL_PAINTCOMMAND("drawLine", command_drawLine,
+ "^drawLine\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "drawLine <x1> <y1> <x2> <y2>",
+ "drawLine 10.0 10.0 20.0 20.0");
+ DECL_PAINTCOMMAND("drawLines", command_drawLines,
+ "^drawLines\\s+\\[([\\w\\s\\-.]*)\\]$",
+ "drawLines <[ <l1x1> <l1y1> <l1x2> <l1y2> <l2x1> <l2y1> ... ]>",
+ "drawLines [ 10 10 50 10 50 20 10 20 ]");
+ DECL_PAINTCOMMAND("drawRect", command_drawRect,
+ "^drawRect\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "drawRect <x> <y> <w> <h>",
+ "drawRect 10.0 10.0 20.0 20.0");
+ DECL_PAINTCOMMAND("drawRoundRect", command_drawRoundRect,
+ "^drawRoundRect\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s*(-?\\w*)?\\s*(-?\\w*)?$",
+ "drawRoundRect <x> <y> <w> <h> [rx] [ry]",
+ "drawRoundRect 10 10 20 20 3 3");
+ DECL_PAINTCOMMAND("drawRoundedRect", command_drawRoundedRect,
+ "^drawRoundedRect\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s*(\\w*)?$",
+ "drawRoundedRect <x> <y> <w> <h> <rx> <ry> [SizeMode enum]",
+ "drawRoundedRect 10 10 20 20 4 4 AbsoluteSize");
+ DECL_PAINTCOMMAND("drawArc", command_drawArc,
+ "^drawArc\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+ "drawArc <x> <y> <w> <h> <angleStart> <angleArc>\n - angles are expressed in 1/16th of degree",
+ "drawArc 10 10 20 20 0 5760");
+ DECL_PAINTCOMMAND("drawChord", command_drawChord,
+ "^drawChord\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+ "drawChord <x> <y> <w> <h> <angleStart> <angleArc>\n - angles are expressed in 1/16th of degree",
+ "drawChord 10 10 20 20 0 5760");
+ DECL_PAINTCOMMAND("drawEllipse", command_drawEllipse,
+ "^drawEllipse\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "drawEllipse <x> <y> <w> <h>",
+ "drawEllipse 10.0 10.0 20.0 20.0");
+ DECL_PAINTCOMMAND("drawPath", command_drawPath,
+ "^drawPath\\s+(\\w*)$",
+ "drawPath <pathName>",
+ "drawPath mypath");
+ DECL_PAINTCOMMAND("drawPie", command_drawPie,
+ "^drawPie\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+ "drawPie <x> <y> <w> <h> <angleStart> <angleArc>\n - angles are expressed in 1/16th of degree",
+ "drawPie 10 10 20 20 0 5760");
+ DECL_PAINTCOMMAND("drawPixmap", command_drawPixmap,
+ "^drawPixmap\\s+([\\w.:\\-/]*)"
+ "\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s*(-?[\\w.]*)?\\s*(-?[\\w.]*)?" // target rect
+ "\\s*(-?[\\w.]*)?\\s*(-?[\\w.]*)?\\s*(-?[\\w.]*)?\\s*(-?[\\w.]*)?$", // source rect
+ "drawPixmap <filename> <tx> <ty> <tw> <th> <sx> <sy> <sw> <sh>"
+ "\n- where t means target and s means source"
+ "\n- a width or height of -1 means maximum space",
+ "drawPixmap :/images/face.png 0 0 -1 -1 0 0 -1 -1");
+ DECL_PAINTCOMMAND("drawImage", command_drawImage,
+ "^drawImage\\s+([\\w.:\\/]*)"
+ "\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s*(-?[\\w.]*)?\\s*(-?[\\w.]*)?" // target rect
+ "\\s*(-?[\\w.]*)?\\s*(-?[\\w.]*)?\\s*(-?[\\w.]*)?\\s*(-?[\\w.]*)?$", // source rect
+ "drawImage <filename> <tx> <ty> <tw> <th> <sx> <sy> <sw> <sh>"
+ "\n- where t means target and s means source"
+ "\n- a width or height of -1 means maximum space",
+ "drawImage :/images/face.png 0 0 -1 -1 0 0 -1 -1");
+ DECL_PAINTCOMMAND("drawPolygon", command_drawPolygon,
+ "^drawPolygon\\s+\\[([\\w\\s\\-.]*)\\]\\s*(\\w*)$",
+ "drawPolygon <[ <x1> <y1> ... <xn> <yn> ]> <Winding|OddEven>",
+ "drawPolygon [ 1 4 6 8 5 3 ] Winding");
+ DECL_PAINTCOMMAND("drawConvexPolygon", command_drawConvexPolygon,
+ "^drawConvexPolygon\\s+\\[([\\w\\s-.]*)\\]$",
+ "drawConvexPolygon <[ <x1> <y1> ... <xn> <yn> ]>",
+ "drawConvexPolygon [ 1 4 6 8 5 3 ]");
+ DECL_PAINTCOMMAND("drawPolyline", command_drawPolyline,
+ "^drawPolyline\\s+\\[([\\w\\s\\-.]*)\\]$",
+ "drawPolyline <[ <x1> <y1> ... <xn> <yn> ]>",
+ "drawPolyline [ 1 4 6 8 5 3 ]");
+ DECL_PAINTCOMMAND("drawText", command_drawText,
+ "^drawText\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$",
+ "drawText <x> <y> <text>",
+ "drawText 10 10 \"my text\"");
+ DECL_PAINTCOMMAND("drawStaticText", command_drawStaticText,
+ "^drawStaticText\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$",
+ "drawStaticText <x> <y> <text>",
+ "drawStaticText 10 10 \"my text\"");
+ DECL_PAINTCOMMAND("drawGlyphRun", command_drawGlyphRun,
+ "^drawGlyphRun\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$",
+ "drawGlyphRun <x> <y> <text> - Will create glyph run using QTextLayout and draw this",
+ "drawGlyphRun 10 10 \"my text\"");
+ DECL_PAINTCOMMAND("drawTextDocument", command_drawTextDocument,
+ "^drawTextDocument\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$",
+ "drawTextDocument <x> <y> <html>",
+ "drawTextDocument 10 10 \"html\"");
+ DECL_PAINTCOMMAND("drawTiledPixmap", command_drawTiledPixmap,
+ "^drawTiledPixmap\\s+([\\w.:\\/]*)"
+ "\\s+(-?\\w*)\\s+(-?\\w*)\\s*(-?\\w*)\\s*(-?\\w*)"
+ "\\s*(-?\\w*)\\s*(-?\\w*)$",
+ "drawTiledPixmap <tile image filename> <tx> <ty> <tx> <ty> <sx> <sy>"
+ "\n - where t means tile"
+ "\n - and s is an offset in the tile",
+ "drawTiledPixmap :/images/alpha.png ");
+ DECL_PAINTCOMMAND("fillRect", command_fillRect,
+ "^fillRect\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s*(\\w*)?$",
+ "fillRect <x> <y> <w> <h> [color]\n - Uses current brush if no color given",
+ "fillRect 10 10 20 20 blue");
+ DECL_PAINTCOMMAND("fillRectF", command_fillRectF,
+ "^fillRectF\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s*(\\w*)?$",
+ "fillRectF <x> <y> <w> <h> [color]\n - Uses current brush if no color given",
+ "fillRectF 10.5 10.5 20.2 20.2 blue");
+
+ DECL_PAINTCOMMANDSECTION("painterPaths");
+ DECL_PAINTCOMMAND("path_moveTo", command_path_moveTo,
+ "^path_moveTo\\s+([.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)$",
+ "path_moveTo <pathName> <x> <y>",
+ "path_moveTo mypath 1.0 1.0");
+ DECL_PAINTCOMMAND("path_lineTo", command_path_lineTo,
+ "^path_lineTo\\s+([.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)$",
+ "path_lineTo <pathName> <x> <y>",
+ "path_lineTo mypath 1.0 1.0");
+ DECL_PAINTCOMMAND("path_addEllipse", command_path_addEllipse,
+ "^path_addEllipse\\s+(\\w*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)$",
+ "path_addEllipse <pathName> <x1> <y1> <x2> <y2>",
+ "path_addEllipse mypath 10.0 10.0 20.0 20.0");
+ DECL_PAINTCOMMAND("path_addPolygon", command_path_addPolygon,
+ "^path_addPolygon\\s+(\\w*)\\s+\\[([\\w\\s]*)\\]\\s*(\\w*)$",
+ "path_addPolygon <pathName> <[ <x1> <y1> ... <xn> <yn> ]>",
+ "path_addPolygon mypath [ 1 4 6 8 5 3 ]");
+ DECL_PAINTCOMMAND("path_addRect", command_path_addRect,
+ "^path_addRect\\s+(\\w*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)$",
+ "path_addRect <pathName> <x1> <y1> <x2> <y2>",
+ "path_addRect mypath 10.0 10.0 20.0 20.0");
+ DECL_PAINTCOMMAND("path_addText", command_path_addText,
+ "^path_addText\\s+(\\w*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+\"(.*)\"$",
+ "path_addText <pathName> <x> <y> <text>",
+ "path_addText mypath 10.0 20.0 \"some text\"");
+ DECL_PAINTCOMMAND("path_arcTo", command_path_arcTo,
+ "^path_arcTo\\s+(\\w*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)$",
+ "path_arcTo <pathName> <x> <y> <w> <h> <angleStart> <angleArc>\n - angles are expressed in degrees",
+ "path_arcTo mypath 0.0 0.0 10.0 10.0 0.0 360.0");
+ DECL_PAINTCOMMAND("path_cubicTo", command_path_cubicTo,
+ "^path_cubicTo\\s+(\\w*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)$",
+ "path_cubicTo <pathName> <x1> <y1> <x2> <y2> <x3> <y3>",
+ "path_cubicTo mypath 0.0 0.0 10.0 10.0 20.0 20.0");
+ DECL_PAINTCOMMAND("path_closeSubpath", command_path_closeSubpath,
+ "^path_closeSubpath\\s+(\\w*)$",
+ "path_closeSubpath <pathName>",
+ "path_closeSubpath mypath");
+ DECL_PAINTCOMMAND("path_createOutline", command_path_createOutline,
+ "^path_createOutline\\s+(\\w*)\\s+(\\w*)$",
+ "path_createOutline <pathName> <newName>",
+ "path_createOutline mypath myoutline");
+ DECL_PAINTCOMMAND("path_debugPrint", command_path_debugPrint,
+ "^path_debugPrint\\s+(\\w*)$",
+ "path_debugPrint <pathName>",
+ "path_debugPrint mypath");
+
+ DECL_PAINTCOMMANDSECTION("regions");
+ DECL_PAINTCOMMAND("region_addRect", command_region_addRect,
+ "^region_addRect\\s+(\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+ "region_addRect <regionName> <x1> <y1> <x2> <y2>",
+ "region_addRect myregion 0.0 0.0 10.0 10.0");
+ DECL_PAINTCOMMAND("region_addEllipse", command_region_addEllipse,
+ "^region_addEllipse\\s+(\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+ "region_addEllipse <regionName> <x1> <y1> <x2> <y2>",
+ "region_addEllipse myregion 0.0 0.0 10.0 10.0");
+
+ DECL_PAINTCOMMANDSECTION("clipping");
+ DECL_PAINTCOMMAND("region_getClipRegion", command_region_getClipRegion,
+ "^region_getClipRegion\\s+(\\w*)$",
+ "region_getClipRegion <regionName>",
+ "region_getClipRegion myregion");
+ DECL_PAINTCOMMAND("setClipRegion", command_setClipRegion,
+ "^setClipRegion\\s+(\\w*)\\s*(\\w*)$",
+ "setClipRegion <regionName> <clip operation enum>",
+ "setClipRegion myregion ReplaceClip");
+ DECL_PAINTCOMMAND("path_getClipPath", command_path_getClipPath,
+ "^path_getClipPath\\s+([\\w0-9]*)$",
+ "path_getClipPath <pathName>",
+ "path_getClipPath mypath");
+ DECL_PAINTCOMMAND("setClipPath", command_setClipPath,
+ "^setClipPath\\s+(\\w*)\\s*(\\w*)$",
+ "setClipPath <pathName> <clip operation enum>",
+ "setClipPath mypath ReplaceClip");
+ DECL_PAINTCOMMAND("setClipRect", command_setClipRect,
+ "^setClipRect\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s*(\\w*)$",
+ "setClipRect <x1> <y1> <x2> <y2> <clip operation enum>",
+ "setClipRect 0.0 0.0 10.0 10.0 ReplaceClip");
+ DECL_PAINTCOMMAND("setClipping", command_setClipping,
+ "^setClipping\\s+(\\w*)$",
+ "setClipping <true|false>",
+ "setClipping true");
+
+ DECL_PAINTCOMMANDSECTION("surface");
+ DECL_PAINTCOMMAND("surface_begin", command_surface_begin,
+ "^surface_begin\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "surface_begin <x> <y> <w> <h>",
+ "surface_begin 0.0 0.0 10.0 10.0");
+ DECL_PAINTCOMMAND("surface_end", command_surface_end,
+ "^surface_end$",
+ "surface_end",
+ "surface_end");
+
+ DECL_PAINTCOMMANDSECTION("painter states");
+ DECL_PAINTCOMMAND("restore", command_restore,
+ "^restore$",
+ "restore",
+ "restore");
+ DECL_PAINTCOMMAND("save", command_save,
+ "^save$",
+ "save",
+ "save");
+
+ DECL_PAINTCOMMANDSECTION("pixmaps'n'images");
+ DECL_PAINTCOMMAND("pixmap_load", command_pixmap_load,
+ "^pixmap_load\\s+([\\w.:\\/]*)\\s*([\\w.:\\/]*)$",
+ "pixmap_load <image filename> <pixmapName>",
+ "pixmap_load :/images/face.png myPixmap");
+ DECL_PAINTCOMMAND("pixmap_setMask", command_pixmap_setMask,
+ "^pixmap_setMask\\s+([\\w.:\\/]*)\\s+([\\w.:\\/]*)$",
+ "pixmap_setMask <pixmapName> <bitmap filename>",
+ "pixmap_setMask myPixmap :/images/bitmap.png");
+ DECL_PAINTCOMMAND("bitmap_load", command_bitmap_load,
+ "^bitmap_load\\s+([\\w.:\\/]*)\\s*([\\w.:\\/]*)$",
+ "bitmap_load <bitmap filename> <bitmapName>\n - note that the image is stored as a pixmap",
+ "bitmap_load :/images/bitmap.png myBitmap");
+ DECL_PAINTCOMMAND("pixmap_setDevicePixelRatio", command_pixmap_setDevicePixelRatio,
+ "^pixmap_setDevicePixelRatio\\s+([\\w.:\\/]*)\\s+([.0-9]*)$",
+ "pixmap_setDevicePixelRatio <pixmapName> <dpr>",
+ "pixmap_setDevicePixelRatio myPixmap 2.0");
+ DECL_PAINTCOMMAND("image_convertToFormat", command_image_convertToFormat,
+ "^image_convertToFormat\\s+([\\w.:\\/]*)\\s+([\\w.:\\/]+)\\s+([\\w0-9_]*)$",
+ "image_convertToFormat <sourceImageName> <destImageName> <image format enum>",
+ "image_convertToFormat myImage myNewImage Indexed8");
+ DECL_PAINTCOMMAND("image_load", command_image_load,
+ "^image_load\\s+([\\w.:\\/]*)\\s*([\\w.:\\/]*)$",
+ "image_load <filename> <imageName>",
+ "image_load :/images/face.png myImage");
+ DECL_PAINTCOMMAND("image_setColor", command_image_setColor,
+ "^image_setColor\\s+([\\w.:\\/]*)\\s+([0-9]*)\\s+#([0-9]*)$",
+ "image_setColor <imageName> <index> <color>",
+ "image_setColor myImage 0 black");
+ DECL_PAINTCOMMAND("image_setColorCount", command_image_setColorCount,
+ "^image_setColorCount\\s+([\\w.:\\/]*)\\s+([0-9]*)$",
+ "image_setColorCount <imageName> <nbColors>",
+ "image_setColorCount myImage 128");
+ DECL_PAINTCOMMAND("image_setDevicePixelRatio", command_image_setDevicePixelRatio,
+ "^image_setDevicePixelRatio\\s+([\\w.:\\/]*)\\s+([.0-9]*)$",
+ "image_setDevicePixelRatio <imageName> <dpr>",
+ "image_setDevicePixelRatio myImage 2.0");
+
+ DECL_PAINTCOMMANDSECTION("transformations");
+ DECL_PAINTCOMMAND("resetMatrix", command_resetMatrix,
+ "^resetMatrix$",
+ "resetMatrix",
+ "resetMatrix");
+ DECL_PAINTCOMMAND("setMatrix", command_setMatrix,
+ "^setMatrix\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)$",
+ "setMatrix <m11> <m12> <m13> <m21> <m22> <m23> <m31> <m32> <m33>",
+ "setMatrix 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0");
+ DECL_PAINTCOMMAND("translate", command_translate,
+ "^translate\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "translate <tx> <ty>",
+ "translate 10.0 10.0");
+ DECL_PAINTCOMMAND("rotate", command_rotate,
+ "^rotate\\s+(-?[\\w.]*)$",
+ "rotate <angle>\n - with angle in degrees",
+ "rotate 30.0");
+ DECL_PAINTCOMMAND("rotate_x", command_rotate_x,
+ "^rotate_x\\s+(-?[\\w.]*)$",
+ "rotate_x <angle>\n - with angle in degrees",
+ "rotate_x 30.0");
+ DECL_PAINTCOMMAND("rotate_y", command_rotate_y,
+ "^rotate_y\\s+(-?[\\w.]*)$",
+ "rotate_y <angle>\n - with angle in degrees",
+ "rotate_y 30.0");
+ DECL_PAINTCOMMAND("scale", command_scale,
+ "^scale\\s+(-?[\\w.]*)\\s+(-?[\\w.]*)$",
+ "scale <sx> <sy>",
+ "scale 2.0 1.0");
+ DECL_PAINTCOMMAND("mapQuadToQuad", command_mapQuadToQuad,
+ "^mapQuadToQuad\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)$",
+ "mapQuadToQuad <x1> <y1> <x2> <y2> <x3> <y3> <x4> <y4> <x5> <y5> <x6> <y6> <x7> <y7> <x8> <y8>"
+ "\n - where vertices 1 to 4 defines the source quad and 5 to 8 the destination quad",
+ "mapQuadToQuad 0.0 0.0 1.0 1.0 0.0 0.0 -1.0 -1.0");
+
+ // populate the command lookup hash
+ for (int i=0; i<s_commandInfoTable.size(); i++) {
+ // and pre-optimize the regexps.
+ s_commandInfoTable.at(i).regExp.optimize();
+ if (s_commandInfoTable.at(i).isSectionHeader() ||
+ s_commandInfoTable.at(i).identifier == QLatin1String("comment") ||
+ s_commandInfoTable.at(i).identifier == QLatin1String("noop"))
+ continue;
+ s_commandHash.insert(s_commandInfoTable.at(i).identifier, i);
+ }
+
+ // populate the enums list
+ ADD_ENUMLIST("brush styles", brushStyleTable);
+ ADD_ENUMLIST("pen styles", penStyleTable);
+ ADD_ENUMLIST("font weights", fontWeightTable);
+ ADD_ENUMLIST("font hintings", fontHintingTable);
+ ADD_ENUMLIST("clip operations", clipOperationTable);
+ ADD_ENUMLIST("spread methods", spreadMethodTable);
+ ADD_ENUMLIST("composition modes", compositionModeTable);
+ ADD_ENUMLIST("image formats", imageFormatTable);
+ ADD_ENUMLIST("coordinate modes", coordinateMethodTable);
+ ADD_ENUMLIST("size modes", sizeModeTable);
+}
+
+#undef DECL_PAINTCOMMAND
+#undef ADD_ENUMLIST
+/*********************************************************************************
+** utility
+**********************************************************************************/
+template <typename T> T PaintCommands::image_load(const QString &filepath)
+{
+ T t(filepath);
+
+ if (t.isNull())
+ t = T(":images/" + filepath);
+
+ if (t.isNull())
+ t = T("images/" + filepath);
+
+ if (t.isNull()) {
+ QFileInfo fi(filepath);
+ QDir dir = fi.absoluteDir();
+ dir.cdUp();
+ dir.cd("images");
+ QString fileName = dir.absolutePath() + QLatin1Char('/') + fi.fileName();
+ t = T(fileName);
+ if (t.isNull() && !fileName.endsWith(".png")) {
+ fileName.append(".png");
+ t = T(fileName);
+ }
+ }
+
+ return t;
+}
+
+/*********************************************************************************
+** setters
+**********************************************************************************/
+void PaintCommands::insertAt(int commandIndex, const QStringList &newCommands)
+{
+ int index = 0;
+ int left = newCommands.size();
+ while (left--)
+ m_commands.insert(++commandIndex, newCommands.at(index++));
+}
+
+/*********************************************************************************
+** run
+**********************************************************************************/
+void PaintCommands::runCommand(const QString &scriptLine)
+{
+ static QRegularExpression separators("\\s");
+ if (scriptLine.isEmpty()) {
+ command_noop(QRegularExpressionMatch());
+ return;
+ }
+ if (scriptLine.startsWith('#')) {
+ command_comment(QRegularExpressionMatch());
+ return;
+ }
+ QString firstWord = scriptLine.section(separators, 0, 0);
+ QList<int> indices = s_commandHash.values(firstWord);
+ foreach(int idx, indices) {
+ PaintCommandInfos command = s_commandInfoTable.at(idx);
+ Q_ASSERT(command.regExp.isValid());
+ QRegularExpressionMatch match = command.regExp.match(scriptLine);
+ if (match.hasMatch()) {
+ (this->*(command.paintMethod))(match);
+ return;
+ }
+ }
+ qWarning("ERROR: unknown command or argument syntax error in \"%s\"", qPrintable(scriptLine));
+}
+
+void PaintCommands::runCommands()
+{
+ staticInit();
+ int width = m_painter->window().width();
+ int height = m_painter->window().height();
+
+ if (width <= 0)
+ width = 800;
+ if (height <= 0)
+ height = 800;
+
+ m_pathMap.clear();
+ m_imageMap.clear();
+ m_pixmapMap.clear();
+ m_regionMap.clear();
+ m_gradientStops.clear();
+ m_blockMap.clear();
+
+ // paint background
+ if (m_checkers_background) {
+ QPixmap pm(20, 20);
+ pm.fill(Qt::white);
+ QPainter pt(&pm);
+ pt.fillRect(0, 0, 10, 10, QColor::fromRgba(0xffdfdfdf));
+ pt.fillRect(10, 10, 10, 10, QColor::fromRgba(0xffdfdfdf));
+ pt.end();
+ m_painter->drawTiledPixmap(0, 0, width, height, pm);
+ } else {
+ m_painter->fillRect(0, 0, width, height, Qt::white);
+ }
+
+ // run each command
+ m_abort = false;
+ for (int i=0; i<m_commands.size() && !m_abort; ++i) {
+ const QString &commandNow = m_commands.at(i);
+ m_currentCommand = commandNow;
+ m_currentCommandIndex = i;
+ runCommand(commandNow.trimmed());
+ }
+}
+
+/*********************************************************************************
+** conversions
+**********************************************************************************/
+int PaintCommands::convertToInt(const QString &str)
+{
+ return qRound(convertToDouble(str));
+}
+
+float PaintCommands::convertToFloat(const QString &str)
+{
+ return float(convertToDouble(str));
+}
+
+double PaintCommands::convertToDouble(const QString &str)
+{
+ static QRegularExpression re("cp([0-9])([xy])");
+ if (str.toLower() == "width") {
+ if (m_painter->device()->devType() == Qt::Widget)
+ return m_painter->window().width();
+ else
+ return 800;
+ }
+ if (str.toLower() == "height") {
+ if (m_painter->device()->devType() == Qt::Widget)
+ return m_painter->window().height();
+ else
+ return 800;
+ }
+ QRegularExpressionMatch match = re.match(str);
+ if (match.hasMatch()) {
+ int index = match.captured(1).toInt();
+ bool is_it_x = match.captured(2) == "x";
+ if (index < 0 || index >= m_controlPoints.size()) {
+ qWarning("ERROR: control point index=%d is out of bounds", index);
+ return 0;
+ }
+ return is_it_x ? m_controlPoints.at(index).x() : m_controlPoints.at(index).y();
+ }
+ return str.toDouble();
+}
+
+QColor PaintCommands::convertToColor(const QString &str)
+{
+ static QRegularExpression alphaColorRe("#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})");
+ static QRegularExpression opaqueColorRe("#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})");
+
+ Q_ASSERT(alphaColorRe.isValid());
+ Q_ASSERT(opaqueColorRe.isValid());
+
+ QRegularExpressionMatch alphaColor = alphaColorRe.match(str);
+ QRegularExpressionMatch opaqueColor = opaqueColorRe.match(str);
+ if (alphaColor.hasMatch()) {
+ return QColor(alphaColor.captured(2).toInt(0, 16),
+ alphaColor.captured(3).toInt(0, 16),
+ alphaColor.captured(4).toInt(0, 16),
+ alphaColor.captured(1).toInt(0, 16));
+ } else if (opaqueColor.hasMatch()) {
+ return QColor(opaqueColor.captured(1).toInt(0, 16),
+ opaqueColor.captured(2).toInt(0, 16),
+ opaqueColor.captured(3).toInt(0, 16));
+ }
+ return QColor(str);
+}
+
+/*********************************************************************************
+** command implementations
+**********************************************************************************/
+void PaintCommands::command_comment(QRegularExpressionMatch)
+{
+ if (m_verboseMode)
+ printf(" -(lance) comment: %s\n", qPrintable(m_currentCommand));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_import(QRegularExpressionMatch re)
+{
+ QString importFile(re.captured(1));
+ QFileInfo fi(m_filepath);
+ QDir dir = fi.absoluteDir();
+ QFile *file = new QFile(dir.absolutePath() + QDir::separator() + importFile);
+
+ if (importFile.isEmpty() || !file->exists()) {
+ dir.cdUp();
+ dir.cd("data");
+ dir.cd("qps");
+ delete file;
+ file = new QFile(dir.absolutePath() + QDir::separator() + importFile);
+ }
+
+ if (importFile.isEmpty() || !file->exists()) {
+ dir.cdUp();
+ dir.cd("images");
+ delete file;
+ file = new QFile(dir.absolutePath() + QDir::separator() + importFile);
+ }
+
+ if (importFile.isEmpty() || !file->exists()) {
+ printf(" - importing non-existing file at line %d (%s)\n", m_currentCommandIndex,
+ qPrintable(file->fileName()));
+ delete file;
+ return;
+ }
+
+ if (!file->open(QIODevice::ReadOnly)) {
+ printf(" - failed to read file: '%s'\n", qPrintable(file->fileName()));
+ delete file;
+ return;
+ }
+ if (m_verboseMode)
+ printf(" -(lance) importing file at line %d (%s)\n", m_currentCommandIndex,
+ qPrintable(fi.fileName()));
+
+ QFileInfo fileinfo(*file);
+ m_commands[m_currentCommandIndex] = QLatin1String("# import file (") + fileinfo.fileName()
+ + QLatin1String(") start");
+ QString rawContent = QString::fromUtf8(file->readAll());
+ QStringList importedData = rawContent.split('\n', Qt::SkipEmptyParts);
+ importedData.append(QLatin1String("# import file (") + fileinfo.fileName() + QLatin1String(") end ---"));
+ insertAt(m_currentCommandIndex, importedData);
+
+ if (m_verboseMode) {
+ printf(" -(lance) Command buffer now looks like:\n");
+ for (int i = 0; i < m_commands.count(); ++i)
+ printf(" ---> {%s}\n", qPrintable(m_commands.at(i)));
+ }
+ delete file;
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_begin_block(QRegularExpressionMatch re)
+{
+ const QString &blockName = re.captured(1);
+ if (m_verboseMode)
+ printf(" -(lance) begin_block (%s)\n", qPrintable(blockName));
+ if (m_blockMap.contains(blockName))
+ qFatal("Two blocks named (%s)", qPrintable(blockName));
+
+ m_commands[m_currentCommandIndex] = QLatin1String("# begin block (") + blockName + QLatin1Char(')');
+ QStringList newBlock;
+ int i = m_currentCommandIndex + 1;
+ for (; i < m_commands.count(); ++i) {
+ const QString &nextCmd = m_commands.at(i);
+ if (nextCmd.startsWith("end_block")) {
+ m_commands[i] = QLatin1String("# end block (") + blockName + QLatin1Char(')');
+ break;
+ }
+ newBlock += nextCmd;
+ }
+
+ if (m_verboseMode)
+ for (int j = 0; j < newBlock.count(); ++j)
+ printf(" %d: %s\n", j, qPrintable(newBlock.at(j)));
+
+ if (i >= m_commands.count())
+ printf(" - Warning! Block doesn't have an 'end_block' marker!\n");
+
+ m_blockMap.insert(blockName, newBlock);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_end_block(QRegularExpressionMatch)
+{
+ printf(" - end_block should be consumed by begin_block command.\n");
+ printf(" You will never see this if your block markers are in sync\n");
+ printf(" (noop)\n");
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_repeat_block(QRegularExpressionMatch re)
+{
+ QString blockName = re.captured(1);
+ if (m_verboseMode)
+ printf(" -(lance) repeating block (%s)\n", qPrintable(blockName));
+
+ QStringList block = m_blockMap.value(blockName);
+ if (block.isEmpty()) {
+ printf(" - repeated block (%s) is empty!\n", qPrintable(blockName));
+ return;
+ }
+
+ m_commands[m_currentCommandIndex] = QLatin1String("# repeated block (") + blockName + QLatin1Char(')');
+ insertAt(m_currentCommandIndex, block);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawLine(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double x1 = convertToDouble(caps.at(1));
+ double y1 = convertToDouble(caps.at(2));
+ double x2 = convertToDouble(caps.at(3));
+ double y2 = convertToDouble(caps.at(4));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawLine((%.2f, %.2f), (%.2f, %.2f))\n", x1, y1, x2, y2);
+
+ m_painter->drawLine(QLineF(x1, y1, x2, y2));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawLines(QRegularExpressionMatch re)
+{
+ static QRegularExpression separators("\\s");
+ QStringList numbers = re.captured(1).split(separators, Qt::SkipEmptyParts);
+
+ QList<QLineF> array;
+ for (int i = 0; i + 3 < numbers.size(); i += 4) {
+ QPointF pt1(numbers.at(i).toFloat(), numbers.at(i + 1).toFloat());
+ QPointF pt2(numbers.at(i + 2).toFloat(), numbers.at(i + 3).toFloat());
+ array.append(QLineF(pt1, pt2));
+ }
+
+ if (m_verboseMode)
+ printf(" -(lance) drawLines(size=%zd)\n", size_t(array.size()));
+
+ m_painter->drawLines(array);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawPath(QRegularExpressionMatch re)
+{
+ if (m_verboseMode)
+ printf(" -(lance) drawPath(name=%s)\n", qPrintable(re.captured(1)));
+
+ QPainterPath &path = m_pathMap[re.captured(1)];
+ m_painter->drawPath(path);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawPixmap(QRegularExpressionMatch re)
+{
+ QPixmap pm;
+ pm = m_pixmapMap[re.captured(1)]; // try cache first
+ if (pm.isNull())
+ pm = image_load<QPixmap>(re.captured(1));
+ if (pm.isNull()) {
+ QFileInfo fi(m_filepath);
+ QDir dir = fi.absoluteDir();
+ dir.cdUp();
+ dir.cd("images");
+ QString fileName = dir.absolutePath() + QLatin1Char('/') + re.captured(1);
+ pm = QPixmap(fileName);
+ if (pm.isNull() && !fileName.endsWith(".png")) {
+ fileName.append(".png");
+ pm = QPixmap(fileName);
+ }
+ }
+ if (pm.isNull()) {
+ fprintf(stderr, "ERROR(drawPixmap): failed to load pixmap: '%s'\n",
+ qPrintable(re.captured(1)));
+ return;
+ }
+
+ qreal tx = convertToFloat(re.captured(2));
+ qreal ty = convertToFloat(re.captured(3));
+ qreal tw = convertToFloat(re.captured(4));
+ qreal th = convertToFloat(re.captured(5));
+
+ qreal sx = convertToFloat(re.captured(6));
+ qreal sy = convertToFloat(re.captured(7));
+ qreal sw = convertToFloat(re.captured(8));
+ qreal sh = convertToFloat(re.captured(9));
+
+ if (tw == 0) tw = -1;
+ if (th == 0) th = -1;
+ if (sw == 0) sw = -1;
+ if (sh == 0) sh = -1;
+
+ if (m_verboseMode)
+ printf(" -(lance) drawPixmap('%s' dim=(%d, %d), depth=%d, (%f, %f, %f, %f), (%f, %f, %f, %f)\n",
+ qPrintable(re.captured(1)), pm.width(), pm.height(), pm.depth(),
+ tx, ty, tw, th, sx, sy, sw, sh);
+
+ if (!re.capturedLength(4)) // at most two coordinates specified
+ m_painter->drawPixmap(QPointF(tx, ty), pm);
+ else
+ m_painter->drawPixmap(QRectF(tx, ty, tw, th), pm, QRectF(sx, sy, sw, sh));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawImage(QRegularExpressionMatch re)
+{
+ QImage im;
+ im = m_imageMap[re.captured(1)]; // try cache first
+ if (im.isNull())
+ im = image_load<QImage>(re.captured(1));
+
+ if (im.isNull()) {
+ QFileInfo fi(m_filepath);
+ QDir dir = fi.absoluteDir();
+ dir.cdUp();
+ dir.cd("images");
+ QString fileName = dir.absolutePath() + QLatin1Char('/') + re.captured(1);
+ im = QImage(fileName);
+ if (im.isNull() && !fileName.endsWith(".png")) {
+ fileName.append(".png");
+ im = QImage(fileName);
+ }
+ }
+ if (im.isNull()) {
+ fprintf(stderr, "ERROR(drawImage): failed to load image: '%s'\n", qPrintable(re.captured(1)));
+ return;
+ }
+
+ qreal tx = convertToFloat(re.captured(2));
+ qreal ty = convertToFloat(re.captured(3));
+ qreal tw = convertToFloat(re.captured(4));
+ qreal th = convertToFloat(re.captured(5));
+
+ qreal sx = convertToFloat(re.captured(6));
+ qreal sy = convertToFloat(re.captured(7));
+ qreal sw = convertToFloat(re.captured(8));
+ qreal sh = convertToFloat(re.captured(9));
+
+ if (tw == 0) tw = -1;
+ if (th == 0) th = -1;
+ if (sw == 0) sw = -1;
+ if (sh == 0) sh = -1;
+
+ if (m_verboseMode)
+ printf(" -(lance) drawImage('%s' dim=(%d, %d), (%f, %f, %f, %f), (%f, %f, %f, %f)\n",
+ qPrintable(re.captured(1)), im.width(), im.height(), tx, ty, tw, th, sx, sy, sw, sh);
+
+ if (!re.capturedLength(4)) // at most two coordinates specified
+ m_painter->drawImage(QPointF(tx, ty), im);
+ else
+ m_painter->drawImage(QRectF(tx, ty, tw, th), im, QRectF(sx, sy, sw, sh));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawTiledPixmap(QRegularExpressionMatch re)
+{
+ QPixmap pm;
+ pm = m_pixmapMap[re.captured(1)]; // try cache first
+ if (pm.isNull())
+ pm = image_load<QPixmap>(re.captured(1));
+ if (pm.isNull()) {
+ QFileInfo fi(m_filepath);
+ QDir dir = fi.absoluteDir();
+ dir.cdUp();
+ dir.cd("images");
+ QString fileName = dir.absolutePath() + QLatin1Char('/') + re.captured(1);
+ pm = QPixmap(fileName);
+ if (pm.isNull() && !fileName.endsWith(".png")) {
+ fileName.append(".png");
+ pm = QPixmap(fileName);
+ }
+ }
+ if (pm.isNull()) {
+ fprintf(stderr, "ERROR(drawTiledPixmap): failed to load pixmap: '%s'\n",
+ qPrintable(re.captured(1)));
+ return;
+ }
+
+ int tx = convertToInt(re.captured(2));
+ int ty = convertToInt(re.captured(3));
+ int tw = convertToInt(re.captured(4));
+ int th = convertToInt(re.captured(5));
+
+ int sx = convertToInt(re.captured(6));
+ int sy = convertToInt(re.captured(7));
+
+ if (tw == 0) tw = -1;
+ if (th == 0) th = -1;
+
+ if (m_verboseMode)
+ printf(" -(lance) drawTiledPixmap('%s' dim=(%d, %d), (%d, %d, %d, %d), (%d, %d)\n",
+ qPrintable(re.captured(1)), pm.width(), pm.height(), tx, ty, tw, th, sx, sy);
+
+ m_painter->drawTiledPixmap(tx, ty, tw, th, pm, sx, sy);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawPoint(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ float x = convertToFloat(caps.at(1));
+ float y = convertToFloat(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawPoint(%.2f, %.2f)\n", x, y);
+
+ m_painter->drawPoint(QPointF(x, y));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawPolygon(QRegularExpressionMatch re)
+{
+ static QRegularExpression separators("\\s");
+ QStringList caps = re.capturedTexts();
+ QString cap = caps.at(1);
+ QStringList numbers = cap.split(separators, Qt::SkipEmptyParts);
+
+ QPolygonF array;
+ for (int i=0; i + 1<numbers.size(); i+=2)
+ array.append(QPointF(convertToDouble(numbers.at(i)), convertToDouble(numbers.at(i+1))));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawPolygon(size=%zd)\n", size_t(array.size()));
+
+ m_painter->drawPolygon(array, caps.at(2).toLower() == "winding" ? Qt::WindingFill : Qt::OddEvenFill);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawPolyline(QRegularExpressionMatch re)
+{
+ static QRegularExpression separators("\\s");
+ QStringList numbers = re.captured(1).split(separators, Qt::SkipEmptyParts);
+
+ QPolygonF array;
+ for (int i=0; i + 1<numbers.size(); i+=2)
+ array.append(QPointF(numbers.at(i).toFloat(),numbers.at(i+1).toFloat()));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawPolyline(size=%zd)\n", size_t(array.size()));
+
+ m_painter->drawPolyline(array.toPolygon());
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawRect(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ float x = convertToFloat(caps.at(1));
+ float y = convertToFloat(caps.at(2));
+ float w = convertToFloat(caps.at(3));
+ float h = convertToFloat(caps.at(4));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawRect(%.2f, %.2f, %.2f, %.2f)\n", x, y, w, h);
+
+ m_painter->drawRect(QRectF(x, y, w, h));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawRoundedRect(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ float x = convertToFloat(caps.at(1));
+ float y = convertToFloat(caps.at(2));
+ float w = convertToFloat(caps.at(3));
+ float h = convertToFloat(caps.at(4));
+ float xr = convertToFloat(caps.at(5));
+ float yr = convertToFloat(caps.at(6));
+
+ int mode = translateEnum(sizeModeTable, caps.at(7), sizeof(sizeModeTable)/sizeof(char *));
+ if (mode < 0)
+ mode = Qt::AbsoluteSize;
+
+ if (m_verboseMode)
+ printf(" -(lance) drawRoundRect(%f, %f, %f, %f, %f, %f, %s)\n", x, y, w, h, xr, yr, mode ? "RelativeSize" : "AbsoluteSize");
+
+ m_painter->drawRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::SizeMode(mode));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawRoundRect(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ int w = convertToInt(caps.at(3));
+ int h = convertToInt(caps.at(4));
+ int xs = caps.at(5).isEmpty() ? 50 : convertToInt(caps.at(5));
+ int ys = caps.at(6).isEmpty() ? 50 : convertToInt(caps.at(6));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawRoundRect(%d, %d, %d, %d, [%d, %d])\n", x, y, w, h, xs, ys);
+
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+ m_painter->drawRoundedRect(x, y, w, h, xs, ys, Qt::RelativeSize);
+ QT_WARNING_POP
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawEllipse(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ float x = convertToFloat(caps.at(1));
+ float y = convertToFloat(caps.at(2));
+ float w = convertToFloat(caps.at(3));
+ float h = convertToFloat(caps.at(4));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawEllipse(%.2f, %.2f, %.2f, %.2f)\n", x, y, w, h);
+
+ m_painter->drawEllipse(QRectF(x, y, w, h));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawPie(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ int w = convertToInt(caps.at(3));
+ int h = convertToInt(caps.at(4));
+ int angle = convertToInt(caps.at(5));
+ int sweep = convertToInt(caps.at(6));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawPie(%d, %d, %d, %d, %d, %d)\n", x, y, w, h, angle, sweep);
+
+ m_painter->drawPie(x, y, w, h, angle, sweep);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawChord(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ int w = convertToInt(caps.at(3));
+ int h = convertToInt(caps.at(4));
+ int angle = convertToInt(caps.at(5));
+ int sweep = convertToInt(caps.at(6));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawChord(%d, %d, %d, %d, %d, %d)\n", x, y, w, h, angle, sweep);
+
+ m_painter->drawChord(x, y, w, h, angle, sweep);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawArc(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ int w = convertToInt(caps.at(3));
+ int h = convertToInt(caps.at(4));
+ int angle = convertToInt(caps.at(5));
+ int sweep = convertToInt(caps.at(6));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawArc(%d, %d, %d, %d, %d, %d)\n", x, y, w, h, angle, sweep);
+
+ m_painter->drawArc(x, y, w, h, angle, sweep);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawText(QRegularExpressionMatch re)
+{
+ if (!m_shouldDrawText)
+ return;
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ QString txt = caps.at(3);
+
+ if (m_verboseMode)
+ printf(" -(lance) drawText(%d, %d, %s)\n", x, y, qPrintable(txt));
+
+ m_painter->drawText(x, y, txt);
+}
+
+void PaintCommands::command_drawStaticText(QRegularExpressionMatch re)
+{
+ if (!m_shouldDrawText)
+ return;
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ QString txt = caps.at(3);
+
+ if (m_verboseMode)
+ printf(" -(lance) drawStaticText(%d, %d, %s)\n", x, y, qPrintable(txt));
+
+ m_painter->drawStaticText(x, y, QStaticText(txt));
+}
+
+void PaintCommands::command_drawGlyphRun(QRegularExpressionMatch re)
+{
+ if (!m_shouldDrawText)
+ return;
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ QString txt = caps.at(3);
+
+ if (m_verboseMode)
+ printf(" -(lance) drawGlyphRun(%d, %d, %s)\n", x, y, qPrintable(txt));
+
+ QTextLayout layout;
+ layout.setFont(m_painter->font());
+ layout.setText(txt);
+ layout.beginLayout();
+ qreal lineY = 0.0;
+ forever {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+ line.setPosition(QPointF(0.0, lineY));
+ lineY += line.height();
+ }
+ layout.endLayout();
+
+ QList<QGlyphRun> glyphRuns = layout.glyphRuns();
+
+ for (const QGlyphRun &glyphRun : glyphRuns)
+ m_painter->drawGlyphRun(QPointF(x, y), glyphRun);
+}
+
+void PaintCommands::command_drawTextDocument(QRegularExpressionMatch re)
+{
+ if (!m_shouldDrawText)
+ return;
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ QString txt = caps.at(3);
+
+ if (m_verboseMode)
+ printf(" -(lance) drawTextDocument(%d, %d, %s)\n", x, y, qPrintable(txt));
+
+ QTextDocument doc;
+ doc.setBaseUrl(QUrl::fromLocalFile(QDir::currentPath() + QLatin1String("/")));
+ doc.setHtml(txt);
+
+ m_painter->save();
+ m_painter->translate(x, y);
+ doc.drawContents(m_painter);
+ m_painter->restore();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_fillRect(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ int w = convertToInt(caps.at(3));
+ int h = convertToInt(caps.at(4));
+
+ if (!caps.at(5).isEmpty()) {
+ QColor color = convertToColor(caps.at(5));
+ if (m_verboseMode)
+ printf(" -(lance) fillRect(%d, %d, %d, %d, %s)\n", x, y, w, h, qPrintable(color.name()));
+ m_painter->fillRect(x, y, w, h, color);
+ } else {
+ if (m_verboseMode)
+ printf(" -(lance) fillRect(%d, %d, %d, %d)\n", x, y, w, h);
+ m_painter->fillRect(x, y, w, h, m_painter->brush());
+ }
+}
+
+void PaintCommands::command_fillRectF(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double x = convertToDouble(caps.at(1));
+ double y = convertToDouble(caps.at(2));
+ double w = convertToDouble(caps.at(3));
+ double h = convertToDouble(caps.at(4));
+
+ if (!caps.at(5).isEmpty()) {
+ QColor color = convertToColor(caps.at(5));
+ if (m_verboseMode)
+ printf(" -(lance) fillRectF(%.2f, %.2f, %.2f, %.2f, %s)\n", x, y, w, h, qPrintable(color.name()));
+ m_painter->fillRect(QRectF(x, y, w, h), color);
+ } else {
+ if (m_verboseMode)
+ printf(" -(lance) fillRectF(%.2f, %.2f, %.2f, %.2f)\n", x, y, w, h);
+ m_painter->fillRect(QRectF(x, y, w, h), m_painter->brush());
+ }
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_noop(QRegularExpressionMatch)
+{
+ if (m_verboseMode)
+ printf(" -(lance) noop: %s\n", qPrintable(m_currentCommand));
+
+ if (!m_currentCommand.trimmed().isEmpty()) {
+ fprintf(stderr, "unknown command: '%s'\n", qPrintable(m_currentCommand.trimmed()));
+ }
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_addText(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ double x = convertToDouble(caps.at(2));
+ double y = convertToDouble(caps.at(3));
+ QString text = caps.at(4);
+
+ if (m_verboseMode)
+ printf(" -(lance) path_addText(%s, %.2f, %.2f, text=%s\n", qPrintable(name), x, y, qPrintable(text));
+
+ m_pathMap[name].addText(x, y, m_painter->font(), text);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_addEllipse(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ double x = convertToDouble(caps.at(2));
+ double y = convertToDouble(caps.at(3));
+ double w = convertToDouble(caps.at(4));
+ double h = convertToDouble(caps.at(5));
+
+ if (m_verboseMode)
+ printf(" -(lance) path_addEllipse(%s, %.2f, %.2f, %.2f, %.2f)\n", qPrintable(name), x, y, w, h);
+
+ m_pathMap[name].addEllipse(x, y, w, h);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_addRect(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ double x = convertToDouble(caps.at(2));
+ double y = convertToDouble(caps.at(3));
+ double w = convertToDouble(caps.at(4));
+ double h = convertToDouble(caps.at(5));
+
+ if (m_verboseMode)
+ printf(" -(lance) path_addRect(%s, %.2f, %.2f, %.2f, %.2f)\n", qPrintable(name), x, y, w, h);
+
+ m_pathMap[name].addRect(x, y, w, h);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_addPolygon(QRegularExpressionMatch re)
+{
+ static QRegularExpression separators("\\s");
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ QString cap = caps.at(2);
+ QStringList numbers = cap.split(separators, Qt::SkipEmptyParts);
+
+ QPolygonF array;
+ for (int i=0; i + 1<numbers.size(); i+=2)
+ array.append(QPointF(numbers.at(i).toFloat(),numbers.at(i+1).toFloat()));
+
+ if (m_verboseMode)
+ printf(" -(lance) path_addPolygon(name=%s, size=%zd)\n", qPrintable(name), size_t(array.size()));
+
+ m_pathMap[name].addPolygon(array);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_arcTo(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ double x = convertToDouble(caps.at(2));
+ double y = convertToDouble(caps.at(3));
+ double w = convertToDouble(caps.at(4));
+ double h = convertToDouble(caps.at(5));
+ double angle = convertToDouble(caps.at(6));
+ double length = convertToDouble(caps.at(7));
+
+ if (m_verboseMode)
+ printf(" -(lance) path_arcTo(%s, %.2f, %.2f, %.2f, %.2f, angle=%.2f, len=%.2f)\n", qPrintable(name), x, y, w, h, angle, length);
+
+ m_pathMap[name].arcTo(x, y, w, h, angle, length);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_createOutline(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ QString newName = caps.at(2);
+ QPen pen = m_painter->pen();
+
+ if (m_verboseMode)
+ printf(" -(lance) path_createOutline(%s, name=%s, width=%d)\n",
+ qPrintable(name), qPrintable(newName), pen.width());
+
+ if (!m_pathMap.contains(name)) {
+ fprintf(stderr, "createOutline(), unknown path: %s\n", qPrintable(name));
+ return;
+ }
+ QPainterPathStroker stroker;
+ stroker.setWidth(pen.widthF());
+ stroker.setDashPattern(pen.style());
+ stroker.setCapStyle(pen.capStyle());
+ stroker.setJoinStyle(pen.joinStyle());
+ m_pathMap[newName] = stroker.createStroke(m_pathMap[name]);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_cubicTo(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ double x1 = convertToDouble(caps.at(2));
+ double y1 = convertToDouble(caps.at(3));
+ double x2 = convertToDouble(caps.at(4));
+ double y2 = convertToDouble(caps.at(5));
+ double x3 = convertToDouble(caps.at(6));
+ double y3 = convertToDouble(caps.at(7));
+
+ if (m_verboseMode)
+ printf(" -(lance) path_cubicTo(%s, (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f))\n", qPrintable(name), x1, y1, x2, y2, x3, y3);
+
+ m_pathMap[name].cubicTo(x1, y1, x2, y2, x3, y3);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_moveTo(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ double x1 = convertToDouble(caps.at(2));
+ double y1 = convertToDouble(caps.at(3));
+
+ if (m_verboseMode)
+ printf(" -(lance) path_moveTo(%s, (%.2f, %.2f))\n", qPrintable(name), x1, y1);
+
+ m_pathMap[name].moveTo(x1, y1);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_lineTo(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ double x1 = convertToDouble(caps.at(2));
+ double y1 = convertToDouble(caps.at(3));
+
+ if (m_verboseMode)
+ printf(" -(lance) path_lineTo(%s, (%.2f, %.2f))\n", qPrintable(name), x1, y1);
+
+ m_pathMap[name].lineTo(x1, y1);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_setFillRule(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ bool winding = caps.at(2).toLower() == "winding";
+
+ if (m_verboseMode)
+ printf(" -(lance) path_setFillRule(name=%s, winding=%d)\n", qPrintable(name), winding);
+
+ m_pathMap[name].setFillRule(winding ? Qt::WindingFill : Qt::OddEvenFill);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_closeSubpath(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+
+ if (m_verboseMode)
+ printf(" -(lance) path_closeSubpath(name=%s)\n", qPrintable(name));
+
+ m_pathMap[name].closeSubpath();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_getClipPath(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+
+ if (m_verboseMode)
+ printf(" -(lance) path_closeSubpath(name=%s)\n", qPrintable(name));
+
+ m_pathMap[name] = m_painter->clipPath();
+}
+
+/***************************************************************************************************/
+static void qt_debug_path(const QPainterPath &path, const QString &name)
+{
+ const char *names[] = {
+ "MoveTo ",
+ "LineTo ",
+ "CurveTo ",
+ "CurveToData"
+ };
+
+ printf("\nQPainterPath (%s): elementCount=%d\n", qPrintable(name), path.elementCount());
+ for (int i=0; i<path.elementCount(); ++i) {
+ const QPainterPath::Element &e = path.elementAt(i);
+ Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
+ printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
+ }
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_debugPrint(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ qt_debug_path(m_pathMap[name], name);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_region_addRect(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ int x = convertToInt(caps.at(2));
+ int y = convertToInt(caps.at(3));
+ int w = convertToInt(caps.at(4));
+ int h = convertToInt(caps.at(5));
+
+ if (m_verboseMode)
+ printf(" -(lance) region_addRect(%s, %d, %d, %d, %d)\n", qPrintable(name), x, y, w, h);
+
+ m_regionMap[name] += QRect(x, y, w, h);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_region_addEllipse(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ int x = convertToInt(caps.at(2));
+ int y = convertToInt(caps.at(3));
+ int w = convertToInt(caps.at(4));
+ int h = convertToInt(caps.at(5));
+
+ if (m_verboseMode)
+ printf(" -(lance) region_addEllipse(%s, %d, %d, %d, %d)\n", qPrintable(name), x, y, w, h);
+
+ m_regionMap[name] += QRegion(x, y, w, h, QRegion::Ellipse);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_region_getClipRegion(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString name = caps.at(1);
+ QRegion region = m_painter->clipRegion();
+
+ if (m_verboseMode)
+ printf(" -(lance) region_getClipRegion(name=%s), bounds=[%d, %d, %d, %d]\n", qPrintable(name),
+ region.boundingRect().x(),
+ region.boundingRect().y(),
+ region.boundingRect().width(),
+ region.boundingRect().height());
+
+ m_regionMap[name] = region;
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_resetMatrix(QRegularExpressionMatch)
+{
+ if (m_verboseMode)
+ printf(" -(lance) resetMatrix()\n");
+
+ m_painter->resetTransform();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_restore(QRegularExpressionMatch)
+{
+ if (m_verboseMode)
+ printf(" -(lance) restore()\n");
+
+ m_painter->restore();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_rotate(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double angle = convertToDouble(caps.at(1));
+
+ if (m_verboseMode)
+ printf(" -(lance) rotate(%.2f)\n", angle);
+
+ m_painter->rotate(angle);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_rotate_x(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double angle = convertToDouble(caps.at(1));
+
+ if (m_verboseMode)
+ printf(" -(lance) rotate_x(%.2f)\n", angle);
+
+ QTransform transform;
+ transform.rotate(angle, Qt::XAxis);
+ m_painter->setTransform(transform, true);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_rotate_y(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double angle = convertToDouble(caps.at(1));
+
+ if (m_verboseMode)
+ printf(" -(lance) rotate_y(%.2f)\n", angle);
+
+ QTransform transform;
+ transform.rotate(angle, Qt::YAxis);
+ m_painter->setTransform(transform, true);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_save(QRegularExpressionMatch)
+{
+ if (m_verboseMode)
+ printf(" -(lance) save()\n");
+
+ m_painter->save();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_mapQuadToQuad(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double x1 = convertToDouble(caps.at(1));
+ double y1 = convertToDouble(caps.at(2));
+ double x2 = convertToDouble(caps.at(3));
+ double y2 = convertToDouble(caps.at(4));
+ double x3 = convertToDouble(caps.at(5));
+ double y3 = convertToDouble(caps.at(6));
+ double x4 = convertToDouble(caps.at(7));
+ double y4 = convertToDouble(caps.at(8));
+ QPolygonF poly1(4);
+ poly1[0] = QPointF(x1, y1);
+ poly1[1] = QPointF(x2, y2);
+ poly1[2] = QPointF(x3, y3);
+ poly1[3] = QPointF(x4, y4);
+
+ double x5 = convertToDouble(caps.at(9));
+ double y5 = convertToDouble(caps.at(10));
+ double x6 = convertToDouble(caps.at(11));
+ double y6 = convertToDouble(caps.at(12));
+ double x7 = convertToDouble(caps.at(13));
+ double y7 = convertToDouble(caps.at(14));
+ double x8 = convertToDouble(caps.at(15));
+ double y8 = convertToDouble(caps.at(16));
+ QPolygonF poly2(4);
+ poly2[0] = QPointF(x5, y5);
+ poly2[1] = QPointF(x6, y6);
+ poly2[2] = QPointF(x7, y7);
+ poly2[3] = QPointF(x8, y8);
+
+ if (m_verboseMode)
+ printf(" -(lance) mapQuadToQuad(%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f ->\n\t"
+ ",%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
+ x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, x6, y6, x7, y7, x8, y8);
+
+ QTransform trans;
+
+ if (!QTransform::quadToQuad(poly1, poly2, trans)) {
+ qWarning("Couldn't perform quad to quad transformation!");
+ }
+
+ m_painter->setTransform(trans, true);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setMatrix(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double m11 = convertToDouble(caps.at(1));
+ double m12 = convertToDouble(caps.at(2));
+ double m13 = convertToDouble(caps.at(3));
+ double m21 = convertToDouble(caps.at(4));
+ double m22 = convertToDouble(caps.at(5));
+ double m23 = convertToDouble(caps.at(6));
+ double m31 = convertToDouble(caps.at(7));
+ double m32 = convertToDouble(caps.at(8));
+ double m33 = convertToDouble(caps.at(9));
+
+ if (m_verboseMode)
+ printf(" -(lance) setMatrix(%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f)\n",
+ m11, m12, m13, m21, m22, m23, m31, m32, m33);
+
+ QTransform trans;
+ trans.setMatrix(m11, m12, m13,
+ m21, m22, m23,
+ m31, m32, m33);
+
+ m_painter->setTransform(trans, true);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_scale(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double sx = convertToDouble(caps.at(1));
+ double sy = convertToDouble(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) scale(%.2f, %.2f)\n", sx, sy);
+
+
+ m_painter->scale(sx, sy);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setBackground(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QColor color = convertToColor(caps.at(1));
+ QString pattern = caps.at(2);
+
+ int style = translateEnum(brushStyleTable, pattern, Qt::LinearGradientPattern);
+ if (style < 0)
+ style = Qt::SolidPattern;
+
+ if (m_verboseMode)
+ printf(" -(lance) setBackground(%s, %s)\n", qPrintable(color.name()), qPrintable(pattern));
+
+ m_painter->setBackground(QBrush(color, Qt::BrushStyle(style)));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setOpacity(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double opacity = convertToDouble(caps.at(1));
+
+ if (m_verboseMode)
+ printf(" -(lance) setOpacity(%lf)\n", opacity);
+
+ m_painter->setOpacity(opacity);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setBgMode(QRegularExpressionMatch re)
+{
+ QString cap = re.captured(2);
+ Qt::BGMode mode = Qt::TransparentMode;
+ if (cap.toLower() == QLatin1String("opaquemode") || cap.toLower() == QLatin1String("opaque"))
+ mode = Qt::OpaqueMode;
+
+ if (m_verboseMode)
+ printf(" -(lance) setBackgroundMode(%s)\n", mode == Qt::OpaqueMode ? "OpaqueMode" : "TransparentMode");
+
+ m_painter->setBackgroundMode(mode);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setBrush(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QImage img = m_imageMap[caps.at(1)]; // try cache first
+ if (img.isNull())
+ img = image_load<QImage>(caps.at(1));
+ if (!img.isNull()) { // Assume image brush
+ if (m_verboseMode)
+ printf(" -(lance) setBrush(image=%s, width=%d, height=%d)\n",
+ qPrintable(caps.at(1)), img.width(), img.height());
+
+ m_painter->setBrush(QBrush(img));
+ } else if (caps.at(1).toLower() == "nobrush") {
+ m_painter->setBrush(Qt::NoBrush);
+ if (m_verboseMode)
+ printf(" -(lance) setBrush(Qt::NoBrush)\n");
+ } else {
+ QColor color = convertToColor(caps.at(1));
+ QString pattern = caps.at(2);
+
+ int style = translateEnum(brushStyleTable, pattern, Qt::LinearGradientPattern);
+ if (style < 0)
+ style = Qt::SolidPattern;
+
+ if (m_verboseMode)
+ printf(" -(lance) setBrush(%s, %s (%d))\n", qPrintable(color.name()), qPrintable(pattern), style);
+
+ m_painter->setBrush(QBrush(color, Qt::BrushStyle(style)));
+ }
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setBrushOrigin(QRegularExpressionMatch re)
+{
+ int x = convertToInt(re.captured(1));
+ int y = convertToInt(re.captured(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) setBrushOrigin(%d, %d)\n", x, y);
+
+ m_painter->setBrushOrigin(x, y);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_brushTranslate(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double dx = convertToDouble(caps.at(1));
+ double dy = convertToDouble(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) brushTranslate(%f, %f)\n", dx, dy);
+
+ QBrush new_brush = m_painter->brush();
+ QTransform brush_matrix = new_brush.transform();
+ brush_matrix.translate(dx, dy);
+ new_brush.setTransform(brush_matrix);
+ m_painter->setBrush(new_brush);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_brushScale(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double sx = convertToDouble(caps.at(1));
+ double sy = convertToDouble(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) brushScale(%f, %f)\n", sx, sy);
+
+ QBrush new_brush = m_painter->brush();
+ QTransform brush_matrix = new_brush.transform();
+ brush_matrix.scale(sx, sy);
+ new_brush.setTransform(brush_matrix);
+ m_painter->setBrush(new_brush);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_brushRotate(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double rot = convertToDouble(caps.at(1));
+
+ if (m_verboseMode)
+ printf(" -(lance) brushScale(%f)\n", rot);
+
+ QBrush new_brush = m_painter->brush();
+ QTransform brush_matrix = new_brush.transform();
+ brush_matrix.rotate(rot);
+ new_brush.setTransform(brush_matrix);
+ m_painter->setBrush(new_brush);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_brushShear(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double sx = convertToDouble(caps.at(1));
+ double sy = convertToDouble(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) brushShear(%f, %f)\n", sx, sy);
+
+ QBrush new_brush = m_painter->brush();
+ QTransform brush_matrix = new_brush.transform();
+ brush_matrix.shear(sx, sy);
+ new_brush.setTransform(brush_matrix);
+ m_painter->setBrush(new_brush);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setClipping(QRegularExpressionMatch re)
+{
+ bool clipping = re.captured(1).toLower() == "true";
+
+ if (m_verboseMode)
+ printf(" -(lance) setClipping(%d)\n", clipping);
+
+ m_painter->setClipping(clipping);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setClipRect(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ int w = convertToInt(caps.at(3));
+ int h = convertToInt(caps.at(4));
+
+ int combine = translateEnum(clipOperationTable, caps.at(5), Qt::IntersectClip + 1);
+ if (combine == -1)
+ combine = Qt::ReplaceClip;
+
+ if (m_verboseMode)
+ printf(" -(lance) setClipRect(%d, %d, %d, %d), %s\n", x, y, w, h, clipOperationTable[combine]);
+
+ m_painter->setClipRect(x, y, w, h, Qt::ClipOperation(combine));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setClipPath(QRegularExpressionMatch re)
+{
+ int combine = translateEnum(clipOperationTable, re.captured(2), Qt::IntersectClip + 1);
+ if (combine == -1)
+ combine = Qt::ReplaceClip;
+
+ if (m_verboseMode)
+ printf(" -(lance) setClipPath(name=%s), %s\n", qPrintable(re.captured(1)), clipOperationTable[combine]);
+
+ if (!m_pathMap.contains(re.captured(1)))
+ fprintf(stderr, " - setClipPath, no such path");
+ m_painter->setClipPath(m_pathMap[re.captured(1)], Qt::ClipOperation(combine));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setClipRegion(QRegularExpressionMatch re)
+{
+ int combine = translateEnum(clipOperationTable, re.captured(2), Qt::IntersectClip + 1);
+ if (combine == -1)
+ combine = Qt::ReplaceClip;
+ QRegion r = m_regionMap[re.captured(1)];
+
+ if (m_verboseMode)
+ printf(" -(lance) setClipRegion(name=%s), bounds=[%d, %d, %d, %d], %s\n",
+ qPrintable(re.captured(1)),
+ r.boundingRect().x(),
+ r.boundingRect().y(),
+ r.boundingRect().width(),
+ r.boundingRect().height(),
+ clipOperationTable[combine]);
+
+ m_painter->setClipRegion(m_regionMap[re.captured(1)], Qt::ClipOperation(combine));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setFont(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QString family = caps.at(1);
+ int size = convertToInt(caps.at(2));
+
+ int weight = translateEnum(fontWeightTable, re.captured(3).toLower(), 5);
+ if (weight != -1) {
+ switch (weight) {
+ case 0: weight = QFont::Light; break;
+ case 1: weight = QFont::Normal; break;
+ case 2: weight = QFont::DemiBold; break;
+ case 3: weight = QFont::Bold; break;
+ case 4: weight = QFont::Black; break;
+ }
+ } else {
+ weight = convertToInt(re.captured(3));
+ }
+
+ bool italic = caps.at(4).toLower() == "true" || caps.at(4).toLower() == "italic";
+
+ QFont font(family, size, weight, italic);
+
+ int hinting = translateEnum(fontHintingTable, caps.at(5), 4);
+ if (hinting == -1)
+ hinting = 0;
+ else
+ font.setHintingPreference(QFont::HintingPreference(hinting));
+
+ bool underline = caps.at(6).toLower() == "true" || caps.at(6).toLower() == "underline";
+ bool strikeOut = caps.at(7).toLower() == "true" || caps.at(7).toLower() == "strikeout";
+ bool overline = caps.at(8).toLower() == "true" || caps.at(8).toLower() == "overline";
+ font.setUnderline(underline);
+ font.setStrikeOut(strikeOut);
+ font.setOverline(overline);
+
+ int capitalization = translateEnum(fontCapitalizationTable, caps.at(9), 5);
+ if (capitalization == -1)
+ capitalization = 0;
+ else
+ font.setCapitalization(QFont::Capitalization(capitalization));
+
+ if (m_verboseMode)
+ printf(" -(lance) setFont(family=%s, size=%d, weight=%d, italic=%d hinting=%s\n",
+ qPrintable(family), size, weight, italic, fontHintingTable[hinting]);
+
+ m_painter->setFont(font);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setPen(QRegularExpressionMatch re)
+{
+ QString cap = re.captured(1);
+ int style = translateEnum(penStyleTable, cap, Qt::DashDotDotLine + 1);
+ if (style >= 0) {
+ if (m_verboseMode)
+ printf(" -(lance) setPen(%s)\n", qPrintable(cap));
+
+ m_painter->setPen(Qt::PenStyle(style));
+ } else if (cap.toLower() == "brush") {
+ QPen pen(m_painter->brush(), 0);
+ if (m_verboseMode) {
+ printf(" -(lance) setPen(brush), style=%d, color=%08x\n",
+ pen.brush().style(), pen.color().rgba());
+ }
+ m_painter->setPen(pen);
+ } else {
+ QColor color = convertToColor(cap);
+ if (m_verboseMode)
+ printf(" -(lance) setPen(%s)\n", qPrintable(color.name()));
+
+ m_painter->setPen(color);
+ }
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setPen2(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QBrush brush;
+
+ if (caps.at(1).toLower() == "brush")
+ brush = m_painter->brush();
+ else
+ brush = convertToColor(caps.at(1));
+
+ double width = convertToDouble(caps.at(2));
+ int penStyle = translateEnum(penStyleTable, caps.at(3), Qt::DashDotDotLine + 1);
+ if (penStyle < 0)
+ penStyle = Qt::SolidLine;
+
+ Qt::PenCapStyle capStyle = Qt::SquareCap;
+ if (caps.at(4).toLower() == "flatcap") capStyle = Qt::FlatCap;
+ else if (caps.at(4).toLower() == "squarecap") capStyle = Qt::SquareCap;
+ else if (caps.at(4).toLower() == "roundcap") capStyle = Qt::RoundCap;
+ else if (!caps.at(4).isEmpty())
+ fprintf(stderr, "ERROR: setPen, unknown capStyle: %s\n", qPrintable(caps.at(4)));
+
+ Qt::PenJoinStyle joinStyle = Qt::BevelJoin;
+ if (caps.at(5).toLower() == "miterjoin") joinStyle = Qt::MiterJoin;
+ else if (caps.at(5).toLower() == "beveljoin") joinStyle = Qt::BevelJoin;
+ else if (caps.at(5).toLower() == "roundjoin") joinStyle = Qt::RoundJoin;
+ else if (!caps.at(5).isEmpty())
+ fprintf(stderr, "ERROR: setPen, unknown joinStyle: %s\n", qPrintable(caps.at(5)));
+
+ if (m_verboseMode)
+ printf(" -(lance) setPen(%s, width=%f, style=%d, cap=%d, join=%d)\n",
+ qPrintable(brush.color().name()), width, penStyle, capStyle, joinStyle);
+
+ m_painter->setPen(QPen(brush, width, Qt::PenStyle(penStyle), capStyle, joinStyle));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setRenderHint(QRegularExpressionMatch re)
+{
+ QString hintString = re.captured(1).toLower();
+ bool on = re.captured(2).isEmpty() || re.captured(2).toLower() == "true";
+ if (hintString.contains("antialiasing")) {
+ if (m_verboseMode)
+ printf(" -(lance) setRenderHint Antialiasing\n");
+
+ m_painter->setRenderHint(QPainter::Antialiasing, on);
+ } else if (hintString.contains("smoothpixmaptransform")) {
+ if (m_verboseMode)
+ printf(" -(lance) setRenderHint SmoothPixmapTransform\n");
+ m_painter->setRenderHint(QPainter::SmoothPixmapTransform, on);
+ } else {
+ fprintf(stderr, "ERROR(setRenderHint): unknown hint '%s'\n", qPrintable(hintString));
+ }
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_clearRenderHint(QRegularExpressionMatch /*re*/)
+{
+ m_painter->setRenderHint(QPainter::Antialiasing, false);
+ m_painter->setRenderHint(QPainter::SmoothPixmapTransform, false);
+ if (m_verboseMode)
+ printf(" -(lance) clearRenderHint\n");
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setCompositionMode(QRegularExpressionMatch re)
+{
+ QString modeString = re.captured(1).toLower();
+ int mode = translateEnum(compositionModeTable, modeString, 33);
+
+ if (mode < 0 || mode > QPainter::RasterOp_SourceAndNotDestination) {
+ fprintf(stderr, "ERROR: invalid mode: %s\n", qPrintable(modeString));
+ return;
+ }
+
+ if (m_verboseMode)
+ printf(" -(lance) setCompositionMode: %d: %s\n", mode, qPrintable(modeString));
+
+ m_painter->setCompositionMode(QPainter::CompositionMode(mode));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_translate(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double dx = convertToDouble(caps.at(1));
+ double dy = convertToDouble(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) translate(%f, %f)\n", dx, dy);
+
+ m_painter->translate(dx, dy);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_pixmap_load(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString fileName = caps.at(1);
+ QString name = caps.at(2);
+
+ if (name.isEmpty())
+ name = fileName;
+
+ QImage im = image_load<QImage>(fileName);
+ QPixmap px = QPixmap::fromImage(im, Qt::OrderedDither | Qt::OrderedAlphaDither);
+
+ if (m_verboseMode)
+ printf(" -(lance) pixmap_load(%s as %s), size=[%d, %d], depth=%d\n",
+ qPrintable(fileName), qPrintable(name),
+ px.width(), px.height(), px.depth());
+
+ m_pixmapMap[name] = px;
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_bitmap_load(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString fileName = caps.at(1);
+ QString name = caps.at(2);
+
+ if (name.isEmpty())
+ name = fileName;
+
+ QBitmap bm = image_load<QBitmap>(fileName);
+
+ if (m_verboseMode)
+ printf(" -(lance) bitmap_load(%s as %s), size=[%d, %d], depth=%d\n",
+ qPrintable(fileName), qPrintable(name),
+ bm.width(), bm.height(), bm.depth());
+
+ m_pixmapMap[name] = bm;
+}
+
+void PaintCommands::command_pixmap_setDevicePixelRatio(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString name = caps.at(1);
+ double dpr = convertToDouble(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) pixmap_setDevicePixelRatio(%s), %.1f -> %.1f\n",
+ qPrintable(name), m_pixmapMap[name].devicePixelRatio(), dpr);
+
+ m_pixmapMap[name].setDevicePixelRatio(dpr);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_pixmap_setMask(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ QBitmap mask = image_load<QBitmap>(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) pixmap_setMask(%s, %s)\n", qPrintable(caps.at(1)), qPrintable(caps.at(2)));
+
+ if (!m_pixmapMap[caps.at(1)].isNull())
+ m_pixmapMap[caps.at(1)].setMask(mask);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_image_load(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString fileName = caps.at(1);
+ QString name = caps.at(2);
+
+ if (name.isEmpty())
+ name = fileName;
+
+ QImage image = image_load<QImage>(fileName);
+
+ if (m_verboseMode)
+ printf(" -(lance) image_load(%s as %s), size=[%d, %d], format=%d\n",
+ qPrintable(fileName), qPrintable(name),
+ image.width(), image.height(), image.format());
+
+ m_imageMap[name] = image;
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_image_setColorCount(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString name = caps.at(1);
+ int count = convertToInt(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) image_setColorCount(%s), %d -> %d\n",
+ qPrintable(name), m_imageMap[name].colorCount(), count);
+
+ m_imageMap[name].setColorCount(count);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_image_setColor(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString name = caps.at(1);
+ int index = convertToInt(caps.at(2));
+ QColor color = convertToColor(caps.at(3));
+
+ if (m_verboseMode)
+ printf(" -(lance) image_setColor(%s), %d = %08x\n", qPrintable(name), index, color.rgba());
+
+ m_imageMap[name].setColor(index, color.rgba());
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_image_setDevicePixelRatio(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString name = caps.at(1);
+ double dpr = convertToDouble(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) image_setDevicePixelRatio(%s), %.1f -> %.1f\n",
+ qPrintable(name), m_imageMap[name].devicePixelRatio(), dpr);
+
+ m_imageMap[name].setDevicePixelRatio(dpr);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_abort(QRegularExpressionMatch)
+{
+ m_abort = true;
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_clearStops(QRegularExpressionMatch)
+{
+ if (m_verboseMode)
+ printf(" -(lance) gradient_clearStops\n");
+ m_gradientStops.clear();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_appendStop(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double pos = convertToDouble(caps.at(1));
+ QColor color = convertToColor(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) gradient_appendStop(%.2f, %x)\n", pos, color.rgba());
+
+ m_gradientStops << QGradientStop(pos, color);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_setLinear(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double x1 = convertToDouble(caps.at(1));
+ double y1 = convertToDouble(caps.at(2));
+ double x2 = convertToDouble(caps.at(3));
+ double y2 = convertToDouble(caps.at(4));
+
+ if (m_verboseMode)
+ printf(" -(lance) gradient_setLinear (%.2f, %.2f), (%.2f, %.2f), spread=%d\n",
+ x1, y1, x2, y2, m_gradientSpread);
+
+ QLinearGradient lg(QPointF(x1, y1), QPointF(x2, y2));
+ lg.setStops(m_gradientStops);
+ lg.setSpread(m_gradientSpread);
+ lg.setCoordinateMode(m_gradientCoordinate);
+ QBrush brush(lg);
+ QTransform brush_matrix = m_painter->brush().transform();
+ brush.setTransform(brush_matrix);
+ m_painter->setBrush(brush);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_setLinearPen(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double x1 = convertToDouble(caps.at(1));
+ double y1 = convertToDouble(caps.at(2));
+ double x2 = convertToDouble(caps.at(3));
+ double y2 = convertToDouble(caps.at(4));
+
+ if (m_verboseMode)
+ printf(" -(lance) gradient_setLinear (%.2f, %.2f), (%.2f, %.2f), spread=%d\n",
+ x1, y1, x2, y2, m_gradientSpread);
+
+ QLinearGradient lg(QPointF(x1, y1), QPointF(x2, y2));
+ lg.setStops(m_gradientStops);
+ lg.setSpread(m_gradientSpread);
+ lg.setCoordinateMode(m_gradientCoordinate);
+ QPen pen = m_painter->pen();
+ pen.setBrush(lg);
+ m_painter->setPen(pen);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_setRadial(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double cx = convertToDouble(caps.at(1));
+ double cy = convertToDouble(caps.at(2));
+ double rad = convertToDouble(caps.at(3));
+ double fx = convertToDouble(caps.at(4));
+ double fy = convertToDouble(caps.at(5));
+
+ if (m_verboseMode)
+ printf(" -(lance) gradient_setRadial center=(%.2f, %.2f), radius=%.2f, focal=(%.2f, %.2f), "
+ "spread=%d\n",
+ cx, cy, rad, fx, fy, m_gradientSpread);
+
+ QRadialGradient rg(QPointF(cx, cy), rad, QPointF(fx, fy));
+ rg.setStops(m_gradientStops);
+ rg.setSpread(m_gradientSpread);
+ rg.setCoordinateMode(m_gradientCoordinate);
+ QBrush brush(rg);
+ QTransform brush_matrix = m_painter->brush().transform();
+ brush.setTransform(brush_matrix);
+ m_painter->setBrush(brush);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_setRadialExtended(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double cx = convertToDouble(caps.at(1));
+ double cy = convertToDouble(caps.at(2));
+ double rad = convertToDouble(caps.at(3));
+ double fx = convertToDouble(caps.at(4));
+ double fy = convertToDouble(caps.at(5));
+ double frad = convertToDouble(caps.at(6));
+
+ if (m_verboseMode)
+ printf(" -(lance) gradient_setRadialExtended center=(%.2f, %.2f), radius=%.2f, focal=(%.2f, %.2f), "
+ "focal radius=%.2f, spread=%d\n",
+ cx, cy, rad, fx, fy, frad, m_gradientSpread);
+
+ QRadialGradient rg(QPointF(cx, cy), rad, QPointF(fx, fy), frad);
+ rg.setStops(m_gradientStops);
+ rg.setSpread(m_gradientSpread);
+ rg.setCoordinateMode(m_gradientCoordinate);
+ QBrush brush(rg);
+ QTransform brush_matrix = m_painter->brush().transform();
+ brush.setTransform(brush_matrix);
+ m_painter->setBrush(brush);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_setConical(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double cx = convertToDouble(caps.at(1));
+ double cy = convertToDouble(caps.at(2));
+ double angle = convertToDouble(caps.at(3));
+
+ if (m_verboseMode) {
+ printf(" -(lance) gradient_setConical center=(%.2f, %.2f), angle=%.2f\n, spread=%d",
+ cx, cy, angle, m_gradientSpread);
+ }
+
+ QConicalGradient cg(QPointF(cx, cy), angle);
+ cg.setStops(m_gradientStops);
+ cg.setSpread(m_gradientSpread);
+ cg.setCoordinateMode(m_gradientCoordinate);
+ QBrush brush(cg);
+ QTransform brush_matrix = m_painter->brush().transform();
+ brush.setTransform(brush_matrix);
+ m_painter->setBrush(brush);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_setSpread(QRegularExpressionMatch re)
+{
+ int spreadMethod = translateEnum(spreadMethodTable, re.captured(1), 3);
+
+ if (m_verboseMode)
+ printf(" -(lance) gradient_setSpread %d=[%s]\n", spreadMethod, spreadMethodTable[spreadMethod]);
+
+ m_gradientSpread = QGradient::Spread(spreadMethod);
+}
+
+void PaintCommands::command_gradient_setCoordinateMode(QRegularExpressionMatch re)
+{
+ int coord = translateEnum(coordinateMethodTable, re.captured(1), 4);
+
+ if (m_verboseMode)
+ printf(" -(lance) gradient_setCoordinateMode %d=[%s]\n", coord,
+ coordinateMethodTable[coord]);
+
+ m_gradientCoordinate = QGradient::CoordinateMode(coord);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_surface_begin(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double x = convertToDouble(caps.at(1));
+ double y = convertToDouble(caps.at(2));
+ double w = convertToDouble(caps.at(3));
+ double h = convertToDouble(caps.at(4));
+
+ if (m_surface_painter) {
+ fprintf(stderr, "ERROR: surface already active");
+ return;
+ }
+
+ if (m_verboseMode)
+ printf(" -(lance) surface_begin, pos=[%.2f, %.2f], size=[%.2f, %.2f]\n", x, y, w, h);
+
+ m_surface_painter = m_painter;
+
+ if (m_type == OpenGLType || m_type == OpenGLBufferType) {
+#ifndef QT_NO_OPENGL
+ m_default_glcontext = QOpenGLContext::currentContext();
+ m_surface_glcontext = new QOpenGLContext();
+ // Pick up the format from the current context; this is especially
+ // important in order to pick the right version/profile to test.
+ m_surface_glcontext->setFormat(m_default_glcontext->format());
+ m_surface_glcontext->create();
+ m_surface_glcontext->makeCurrent(m_default_glcontext->surface());
+ QOpenGLFramebufferObjectFormat fmt; // ###TBD: get format from caller
+ fmt.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ fmt.setSamples(4);
+ m_surface_glbuffer = new QOpenGLFramebufferObject(qRound(w), qRound(h), fmt);
+ m_surface_glbuffer->bind();
+ m_surface_glpaintdevice = new QOpenGLPaintDevice(qRound(w), qRound(h));
+ m_painter = new QPainter(m_surface_glpaintdevice);
+ m_painter->save();
+ m_painter->setCompositionMode(QPainter::CompositionMode_Clear);
+ m_painter->fillRect(QRect(0, 0, qRound(w), qRound(h)), Qt::transparent);
+ m_painter->restore();
+#endif
+ } else {
+ QImage::Format surface_format;
+ if (QImage::toPixelFormat(m_format).alphaUsage() != QPixelFormat::UsesAlpha)
+ surface_format = qt_alphaVersion(m_format);
+ else
+ surface_format = m_format;
+
+ m_surface_image = QImage(qRound(w), qRound(h), surface_format);
+ m_surface_image.fill(0);
+ m_painter = new QPainter(&m_surface_image);
+ }
+ m_surface_rect = QRectF(x, y, w, h);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_surface_end(QRegularExpressionMatch)
+{
+ if (!m_surface_painter) {
+ fprintf(stderr, "ERROR: surface not active");
+ return;
+ }
+
+ if (m_verboseMode)
+ printf(" -(lance) surface_end, pos=[%.2f, %.2f], size=[%.2f, %.2f]\n",
+ m_surface_rect.x(),
+ m_surface_rect.y(),
+ m_surface_rect.width(),
+ m_surface_rect.height());
+ m_painter->end();
+
+ delete m_painter;
+ m_painter = m_surface_painter;
+ m_surface_painter = 0;
+
+ if (m_type == OpenGLType || m_type == OpenGLBufferType) {
+#ifndef QT_NO_OPENGL
+ QImage new_image = m_surface_glbuffer->toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
+
+ delete m_surface_glpaintdevice;
+ m_surface_glpaintdevice = 0;
+ delete m_surface_glbuffer;
+ m_surface_glbuffer = 0;
+ delete m_surface_glcontext;
+ m_surface_glcontext = 0;
+
+ m_default_glcontext->makeCurrent(m_default_glcontext->surface());
+ m_painter->drawImage(m_surface_rect, new_image);
+ // Flush the pipeline:
+ m_painter->beginNativePainting();
+ m_painter->endNativePainting();
+#endif
+ } else {
+ m_painter->drawImage(m_surface_rect, m_surface_image);
+ m_surface_image = QImage();
+ }
+ m_surface_rect = QRectF();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_image_convertToFormat(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString srcName = caps.at(1);
+ QString destName = caps.at(2);
+
+ if (!m_imageMap.contains(srcName)) {
+ fprintf(stderr, "ERROR(convertToFormat): no such image '%s'\n", qPrintable(srcName));
+ return;
+ }
+
+ int format = translateEnum(imageFormatTable, caps.at(3), QImage::NImageFormats);
+ if (format < 0 || format >= QImage::NImageFormats) {
+ fprintf(stderr, "ERROR(convertToFormat): invalid format %d = '%s'\n",
+ format, qPrintable(caps.at(3)));
+ return;
+ }
+
+ QImage src = m_imageMap[srcName];
+ QImage dest = src.convertToFormat(QImage::Format(format),
+ Qt::OrderedAlphaDither | Qt::OrderedDither);
+
+ if (m_verboseMode) {
+ printf(" -(lance) convertToFormat %s:%d -> %s:%d\n",
+ qPrintable(srcName), src.format(),
+ qPrintable(destName), dest.format());
+ }
+
+ m_imageMap[destName] = dest;
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_textlayout_draw(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString text = caps.at(1);
+ double width = convertToDouble(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) textlayout_draw text='%s', width=%f\n",
+ qPrintable(text), width);
+
+ QFont copy = m_painter->font();
+ copy.setPointSize(10);
+
+ QTextLayout layout(text, copy, m_painter->device());
+ layout.beginLayout();
+
+ double y_offset = 0;
+
+ while (true) {
+ QTextLine line = layout.createLine();
+ if (!line.isValid())
+ break;
+ line.setLineWidth(width);
+ line.setPosition(QPointF(0, y_offset));
+
+ y_offset += line.height();
+ }
+
+ layout.draw(m_painter, QPointF(0, 0));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_pen_setDashOffset(QRegularExpressionMatch re)
+{
+ QStringList caps = re.capturedTexts();
+ double offset = convertToDouble(caps.at(1));
+
+ if (m_verboseMode)
+ printf(" -(lance) setDashOffset(%lf)\n", offset);
+
+ QPen p = m_painter->pen();
+ p.setDashOffset(offset);
+ m_painter->setPen(p);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_pen_setDashPattern(QRegularExpressionMatch re)
+{
+ static QRegularExpression separators("\\s");
+ QStringList caps = re.capturedTexts();
+ QString cap = caps.at(1);
+ QStringList numbers = cap.split(separators, Qt::SkipEmptyParts);
+
+ QList<qreal> pattern;
+ for (int i=0; i<numbers.size(); ++i)
+ pattern.append(convertToDouble(numbers.at(i)));
+
+ if (m_verboseMode)
+ printf(" -(lance) pen_setDashPattern(size=%zd)\n", size_t(pattern.size()));
+
+ QPen p = m_painter->pen();
+ p.setDashPattern(pattern);
+ m_painter->setPen(p);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_pen_setCosmetic(QRegularExpressionMatch re)
+{
+ QString hm = re.capturedTexts().at(1);
+ bool on = hm == "true" || hm == "yes" || hm == "on";
+
+ if (m_verboseMode) {
+ printf(" -(lance) pen_setCosmetic(%s)\n", on ? "true" : "false");
+ }
+
+ QPen p = m_painter->pen();
+ p.setCosmetic(on);
+
+ m_painter->setPen(p);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawConvexPolygon(QRegularExpressionMatch re)
+{
+ static QRegularExpression separators("\\s");
+ QStringList caps = re.capturedTexts();
+ QString cap = caps.at(1);
+ QStringList numbers = cap.split(separators, Qt::SkipEmptyParts);
+
+ QPolygonF array;
+ for (int i=0; i + 1<numbers.size(); i+=2)
+ array.append(QPointF(convertToDouble(numbers.at(i)), convertToDouble(numbers.at(i+1))));
+
+ if (m_verboseMode)
+ printf(" -(lance) drawConvexPolygon(size=%zd)\n", size_t(array.size()));
+
+
+ m_painter->drawConvexPolygon(array);
+}
diff --git a/tests/baseline/painting/paintcommands.h b/tests/baseline/painting/paintcommands.h
new file mode 100644
index 0000000000..15c6d3fa58
--- /dev/null
+++ b/tests/baseline/painting/paintcommands.h
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef PAINTCOMMANDS_H
+#define PAINTCOMMANDS_H
+
+#include <qcolor.h>
+#include <qmap.h>
+#include <qpainterpath.h>
+#include <qregion.h>
+#include <qregularexpression.h>
+#include <qstringlist.h>
+#include <qpixmap.h>
+#include <qbrush.h>
+#include <qhash.h>
+
+QT_FORWARD_DECLARE_CLASS(QPainter)
+#ifndef QT_NO_OPENGL
+QT_FORWARD_DECLARE_CLASS(QOpenGLFramebufferObject)
+QT_FORWARD_DECLARE_CLASS(QOpenGLPaintDevice)
+QT_FORWARD_DECLARE_CLASS(QOpenGLContext)
+#endif
+
+enum DeviceType {
+ WidgetType,
+ BitmapType,
+ PixmapType,
+ ImageType,
+ ImageMonoType,
+ OpenGLType,
+ OpenGLBufferType,
+ PictureType,
+ PrinterType,
+ PdfType,
+ PsType,
+ GrabType,
+ CustomDeviceType,
+ CustomWidgetType,
+ ImageWidgetType
+};
+
+/************************************************************************/
+class PaintCommands
+{
+public:
+ // construction / initialization
+ PaintCommands(const QStringList &cmds, int w, int h, QImage::Format format)
+ : m_painter(0)
+ , m_surface_painter(0)
+ , m_format(format)
+ , m_commands(cmds)
+ , m_gradientSpread(QGradient::PadSpread)
+ , m_gradientCoordinate(QGradient::LogicalMode)
+ , m_width(w)
+ , m_height(h)
+ , m_verboseMode(false)
+ , m_type(WidgetType)
+ , m_checkers_background(true)
+ , m_shouldDrawText(true)
+#ifndef QT_NO_OPENGL
+ , m_default_glcontext(0)
+ , m_surface_glcontext(0)
+ , m_surface_glbuffer(0)
+ , m_surface_glpaintdevice(0)
+#endif
+ { staticInit(); }
+
+public:
+ void setCheckersBackground(bool b) { staticInit(); m_checkers_background = b; }
+ void setContents(const QStringList &cmds) {
+ staticInit();
+ m_blockMap.clear();
+ m_pathMap.clear();
+ m_pixmapMap.clear();
+ m_imageMap.clear();
+ m_regionMap.clear();
+ m_gradientStops.clear();
+ m_controlPoints.clear();
+ m_gradientSpread = QGradient::PadSpread;
+ m_gradientCoordinate = QGradient::LogicalMode;
+ m_commands = cmds;
+
+
+ }
+ void setPainter(QPainter *pt) { staticInit(); m_painter = pt; }
+ void setType(DeviceType t) { staticInit(); m_type = t; }
+ void setFilePath(const QString &path) { staticInit(); m_filepath = path; }
+ void setControlPoints(const QList<QPointF> &points)
+ {
+ staticInit();
+ m_controlPoints = points;
+ }
+ void setVerboseMode(bool v) { staticInit(); m_verboseMode = v; }
+ void insertAt(int commandIndex, const QStringList &newCommands);
+ void setShouldDrawText(bool drawText) { m_shouldDrawText = drawText; }
+
+ // run
+ void runCommands();
+
+private:
+ // run
+ void runCommand(const QString &scriptLine);
+
+ // conversion methods
+ int convertToInt(const QString &str);
+ double convertToDouble(const QString &str);
+ float convertToFloat(const QString &str);
+ QColor convertToColor(const QString &str);
+
+ // commands: comments
+ void command_comment(QRegularExpressionMatch re);
+
+ // commands: importer
+ void command_import(QRegularExpressionMatch re);
+
+ // commands: blocks
+ void command_begin_block(QRegularExpressionMatch re);
+ void command_end_block(QRegularExpressionMatch re);
+ void command_repeat_block(QRegularExpressionMatch re);
+
+ // commands: misc
+ void command_textlayout_draw(QRegularExpressionMatch re);
+ void command_abort(QRegularExpressionMatch re);
+
+ // commands: noops
+ void command_noop(QRegularExpressionMatch re);
+
+ // commands: setters
+ void command_setBgMode(QRegularExpressionMatch re);
+ void command_setBackground(QRegularExpressionMatch re);
+ void command_setOpacity(QRegularExpressionMatch re);
+ void command_path_setFillRule(QRegularExpressionMatch re);
+ void command_setBrush(QRegularExpressionMatch re);
+ void command_setBrushOrigin(QRegularExpressionMatch re);
+ void command_brushTranslate(QRegularExpressionMatch re);
+ void command_brushRotate(QRegularExpressionMatch re);
+ void command_brushScale(QRegularExpressionMatch re);
+ void command_brushShear(QRegularExpressionMatch re);
+ void command_setClipPath(QRegularExpressionMatch re);
+ void command_setClipRect(QRegularExpressionMatch re);
+ void command_setClipRectangle(QRegularExpressionMatch re);
+ void command_setClipRegion(QRegularExpressionMatch re);
+ void command_setClipping(QRegularExpressionMatch re);
+ void command_setCompositionMode(QRegularExpressionMatch re);
+ void command_setFont(QRegularExpressionMatch re);
+ void command_setPen(QRegularExpressionMatch re);
+ void command_setPen2(QRegularExpressionMatch re);
+ void command_pen_setDashOffset(QRegularExpressionMatch re);
+ void command_pen_setDashPattern(QRegularExpressionMatch re);
+ void command_pen_setCosmetic(QRegularExpressionMatch re);
+ void command_setRenderHint(QRegularExpressionMatch re);
+ void command_clearRenderHint(QRegularExpressionMatch re);
+ void command_gradient_appendStop(QRegularExpressionMatch re);
+ void command_gradient_clearStops(QRegularExpressionMatch re);
+ void command_gradient_setConical(QRegularExpressionMatch re);
+ void command_gradient_setLinear(QRegularExpressionMatch re);
+ void command_gradient_setRadial(QRegularExpressionMatch re);
+ void command_gradient_setRadialExtended(QRegularExpressionMatch re);
+ void command_gradient_setLinearPen(QRegularExpressionMatch re);
+ void command_gradient_setSpread(QRegularExpressionMatch re);
+ void command_gradient_setCoordinateMode(QRegularExpressionMatch re);
+
+ // commands: drawing ops
+ void command_drawArc(QRegularExpressionMatch re);
+ void command_drawChord(QRegularExpressionMatch re);
+ void command_drawConvexPolygon(QRegularExpressionMatch re);
+ void command_drawEllipse(QRegularExpressionMatch re);
+ void command_drawImage(QRegularExpressionMatch re);
+ void command_drawLine(QRegularExpressionMatch re);
+ void command_drawLines(QRegularExpressionMatch re);
+ void command_drawPath(QRegularExpressionMatch re);
+ void command_drawPie(QRegularExpressionMatch re);
+ void command_drawPixmap(QRegularExpressionMatch re);
+ void command_drawPoint(QRegularExpressionMatch re);
+ void command_drawPolygon(QRegularExpressionMatch re);
+ void command_drawPolyline(QRegularExpressionMatch re);
+ void command_drawRect(QRegularExpressionMatch re);
+ void command_drawRoundedRect(QRegularExpressionMatch re);
+ void command_drawRoundRect(QRegularExpressionMatch re);
+ void command_drawText(QRegularExpressionMatch re);
+ void command_drawStaticText(QRegularExpressionMatch re);
+ void command_drawGlyphRun(QRegularExpressionMatch re);
+ void command_drawTextDocument(QRegularExpressionMatch re);
+ void command_drawTiledPixmap(QRegularExpressionMatch re);
+ void command_fillRect(QRegularExpressionMatch re);
+ void command_fillRectF(QRegularExpressionMatch re);
+
+ // paths
+ void command_path_addEllipse(QRegularExpressionMatch re);
+ void command_path_addPolygon(QRegularExpressionMatch re);
+ void command_path_addRect(QRegularExpressionMatch re);
+ void command_path_addText(QRegularExpressionMatch re);
+ void command_path_arcTo(QRegularExpressionMatch re);
+ void command_path_closeSubpath(QRegularExpressionMatch re);
+ void command_path_createOutline(QRegularExpressionMatch re);
+ void command_path_cubicTo(QRegularExpressionMatch re);
+ void command_path_debugPrint(QRegularExpressionMatch re);
+ void command_path_lineTo(QRegularExpressionMatch re);
+ void command_path_moveTo(QRegularExpressionMatch re);
+ void command_region_addEllipse(QRegularExpressionMatch re);
+ void command_region_addRect(QRegularExpressionMatch re);
+
+ // getters
+ void command_region_getClipRegion(QRegularExpressionMatch re);
+ void command_path_getClipPath(QRegularExpressionMatch re);
+
+ // commands: surface begin/end
+ void command_surface_begin(QRegularExpressionMatch re);
+ void command_surface_end(QRegularExpressionMatch re);
+
+ // commands: save/restore painter state
+ void command_restore(QRegularExpressionMatch re);
+ void command_save(QRegularExpressionMatch re);
+
+ // commands: pixmap/image
+ void command_pixmap_load(QRegularExpressionMatch re);
+ void command_pixmap_setMask(QRegularExpressionMatch re);
+ void command_bitmap_load(QRegularExpressionMatch re);
+ void command_pixmap_setDevicePixelRatio(QRegularExpressionMatch re);
+ void command_image_convertToFormat(QRegularExpressionMatch re);
+ void command_image_load(QRegularExpressionMatch re);
+ void command_image_setColor(QRegularExpressionMatch re);
+ void command_image_setColorCount(QRegularExpressionMatch re);
+ void command_image_setDevicePixelRatio(QRegularExpressionMatch re);
+
+ // commands: transformation
+ void command_resetMatrix(QRegularExpressionMatch re);
+ void command_translate(QRegularExpressionMatch re);
+ void command_rotate(QRegularExpressionMatch re);
+ void command_rotate_x(QRegularExpressionMatch re);
+ void command_rotate_y(QRegularExpressionMatch re);
+ void command_scale(QRegularExpressionMatch re);
+ void command_mapQuadToQuad(QRegularExpressionMatch re);
+ void command_setMatrix(QRegularExpressionMatch re);
+
+ // attributes
+ QPainter *m_painter;
+ QPainter *m_surface_painter;
+ QImage::Format m_format;
+ QImage m_surface_image;
+ QRectF m_surface_rect;
+ QStringList m_commands;
+ QString m_currentCommand;
+ int m_currentCommandIndex;
+ QString m_filepath;
+ QMap<QString, QStringList> m_blockMap;
+ QMap<QString, QPainterPath> m_pathMap;
+ QMap<QString, QPixmap> m_pixmapMap;
+ QMap<QString, QImage> m_imageMap;
+ QMap<QString, QRegion> m_regionMap;
+ QGradientStops m_gradientStops;
+ QGradient::Spread m_gradientSpread;
+ QGradient::CoordinateMode m_gradientCoordinate;
+ bool m_abort;
+ int m_width;
+ int m_height;
+
+ bool m_verboseMode;
+ DeviceType m_type;
+ bool m_checkers_background;
+ bool m_shouldDrawText;
+
+ QList<QPointF> m_controlPoints;
+
+#ifndef QT_NO_OPENGL
+ QOpenGLContext *m_default_glcontext;
+ QOpenGLContext *m_surface_glcontext;
+ QOpenGLFramebufferObject *m_surface_glbuffer;
+ QOpenGLPaintDevice *m_surface_glpaintdevice;
+#endif
+
+ // painter functionalities string tables
+ static const char *brushStyleTable[];
+ static const char *penStyleTable[];
+ static const char *fontWeightTable[];
+ static const char *fontHintingTable[];
+ static const char *fontCapitalizationTable[];
+ static const char *clipOperationTable[];
+ static const char *spreadMethodTable[];
+ static const char *coordinateMethodTable[];
+ static const char *compositionModeTable[];
+ static const char *imageFormatTable[];
+ static const char *sizeModeTable[];
+ static int translateEnum(const char *table[], const QString &pattern, int limit);
+
+ // utility
+ template <typename T> T image_load(const QString &filepath);
+
+ // commands dictionary management
+ static void staticInit();
+
+public:
+ struct PaintCommandInfos
+ {
+ PaintCommandInfos(QString id, void (PaintCommands::*p)(QRegularExpressionMatch), QRegularExpression r, QString sy, QString sa)
+ : identifier(id)
+ , regExp(r)
+ , syntax(sy)
+ , sample(sa)
+ , paintMethod(p)
+ {}
+ PaintCommandInfos(QString title)
+ : identifier(title), paintMethod(0) {}
+ bool isSectionHeader() const { return paintMethod == 0; }
+ QString identifier;
+ QRegularExpression regExp;
+ QString syntax;
+ QString sample;
+ void (PaintCommands::*paintMethod)(QRegularExpressionMatch);
+ };
+
+ static PaintCommandInfos *findCommandById(const QString &identifier) {
+ for (int i=0; i<s_commandInfoTable.size(); i++)
+ if (s_commandInfoTable[i].identifier == identifier)
+ return &s_commandInfoTable[i];
+ return 0;
+ }
+
+ static QList<PaintCommandInfos> s_commandInfoTable;
+ static QList<QPair<QString,QStringList> > s_enumsTable;
+ static QMultiHash<QString, int> s_commandHash;
+};
+
+#endif // PAINTCOMMANDS_H
diff --git a/tests/baseline/painting/scripts/aliasing.qps b/tests/baseline/painting/scripts/aliasing.qps
new file mode 100644
index 0000000000..59878f9c4d
--- /dev/null
+++ b/tests/baseline/painting/scripts/aliasing.qps
@@ -0,0 +1,156 @@
+
+path_moveTo convexPath 25 0
+path_lineTo convexPath 50 50
+path_lineTo convexPath 25 25
+path_lineTo convexPath 0 50
+path_closeSubpath convexPath
+
+pixmap_load border.png pixmap
+
+setRenderHint LineAntialiasing false
+translate 10 10
+
+begin_block drawing
+ setPen black 1
+ setBrush 7f7fff
+ drawPath convexPath
+
+ setFont "monospace" 8
+ setPen black
+ drawText 0 68 "QwErTy@"
+
+
+ setPen black 1
+ setBrush 7f7fff
+ drawRect 0 80 10 5
+
+ setPen black 1
+ setBrush noBrush
+ drawRect 20 80 10 5
+
+ setPen noPen
+ setBrush 7f7fff
+ drawRect 40 80 10 5
+
+
+ setPen black 2
+ setBrush 7f7fff
+ drawRect 0 90 10 5
+
+ setPen black 2
+ setBrush noBrush
+ drawRect 20 90 10 5
+
+ setPen noPen
+ setBrush 7f7fff
+ drawRect 40 90 10 5
+
+
+ setPen black 3
+ setBrush 7f7fff
+ drawRect 0 100 10 5
+
+ setPen black 3
+ setBrush noBrush
+ drawRect 20 100 10 5
+
+ setPen noPen
+ setBrush 7f7fff
+ drawRect 40 100 10 5
+
+
+ setPen black 1
+ setBrush noBrush
+ drawLine 10 110 20 120
+ drawLine 30 120 40 110
+
+ setPen black 2
+ setBrush noBrush
+ drawLine 10 120 20 130
+ drawLine 30 130 40 120
+
+ setPen black 3
+ setBrush noBrush
+ drawLine 10 130 20 140
+ drawLine 30 140 40 130
+
+ drawPixmap pixmap 0 150
+
+ setRenderHint SmoothPixmapTransform false
+ drawPixmap pixmap 20 150 15 15 0 0 10 10
+
+end_block
+
+translate 0 180
+setRenderHint LineAntialiasing true
+repeat_block drawing
+drawText 15 185 "0.0"
+
+resetMatrix
+translate 70.2 10.2
+setRenderHint LineAntialiasing false
+repeat_block drawing
+translate 0 180
+setRenderHint LineAntialiasing true
+repeat_block drawing
+translate -0.2 -0.2
+drawText 15 185 "0.2"
+
+
+resetMatrix
+translate 130.4 10.4
+setRenderHint LineAntialiasing false
+repeat_block drawing
+translate 0 180
+setRenderHint LineAntialiasing true
+repeat_block drawing
+translate -0.4 -0.4
+drawText 15 185 "0.4"
+
+
+resetMatrix
+translate 190.5 10.5
+setRenderHint LineAntialiasing false
+repeat_block drawing
+translate 0 180
+setRenderHint LineAntialiasing true
+repeat_block drawing
+translate -0.5 -0.5
+drawText 15 185 "0.5"
+
+
+resetMatrix
+translate 250.6 10.6
+setRenderHint LineAntialiasing false
+repeat_block drawing
+translate 0 180
+setRenderHint LineAntialiasing true
+repeat_block drawing
+translate -0.6 -0.6
+drawText 15 185 "0.6"
+
+
+resetMatrix
+translate 310.8 10.8
+setRenderHint LineAntialiasing false
+repeat_block drawing
+translate 0 180
+setRenderHint LineAntialiasing true
+repeat_block drawing
+translate -0.8 -0.8
+drawText 15 185 "0.8"
+
+
+resetMatrix
+translate 371 11
+setRenderHint LineAntialiasing false
+repeat_block drawing
+translate 0 180
+setRenderHint LineAntialiasing true
+repeat_block drawing
+drawText 15 185 "1.0"
+
+
+resetMatrix
+drawText 430 95 "Aliased"
+drawText 430 275 "Anti-Aliased" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/arcs.qps b/tests/baseline/painting/scripts/arcs.qps
new file mode 100644
index 0000000000..8afaf73ff1
--- /dev/null
+++ b/tests/baseline/painting/scripts/arcs.qps
@@ -0,0 +1,68 @@
+# Version: 1
+# CheckVsReference: 5
+
+setRenderHint LineAntialiasing
+
+setPen red 0
+
+drawEllipse 0 0 600 400
+
+path_moveTo arcs 300 200
+path_arcTo arcs 0 0 600 400 0 10
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 0 0 600 400 20 30
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 0 0 600 400 60 45
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 0 0 600 400 115 60
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 0 0 600 400 180 90
+path_closeSubpath arcs
+
+path_moveTo arcs 590 200
+path_arcTo arcs 10 10 580 380 0 360
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 20 20 560 360 0 -10
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 20 20 560 360 -20 -30
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 20 20 560 360 -60 -45
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 20 20 560 360 -115 -60
+path_closeSubpath arcs
+
+path_moveTo arcs 300 200
+path_arcTo arcs 20 20 560 360 -180 -90
+path_closeSubpath arcs
+
+setPen black 1 solidline
+setBrush #3f00ff00
+drawPath arcs
+
+# Then again with a matrix set...
+translate 200 400
+rotate 10
+scale 0.5 0.5
+setPen red 0
+setBrush nobrush
+drawEllipse 0 0 600 400
+
+setPen black 1 solidline
+setBrush #3f0000ff
+drawPath arcs \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/arcs2.qps b/tests/baseline/painting/scripts/arcs2.qps
new file mode 100644
index 0000000000..a2739a8c97
--- /dev/null
+++ b/tests/baseline/painting/scripts/arcs2.qps
@@ -0,0 +1,54 @@
+# Version: 1
+# CheckVsReference: 5
+
+drawArc 100 100 100 100 0 1440
+drawArc 100 100 100 100 1440 1440
+drawArc 100 100 100 100 2880 1440
+drawArc 100 100 100 100 4320 1440
+
+drawArc 100 200 100 100 0 -1440
+drawArc 100 200 100 100 -1440 -1440
+drawArc 100 200 100 100 -2880 -1440
+drawArc 100 200 100 100 -4320 -1440
+
+drawArc 200 100 100 100 720 1440
+drawArc 200 100 100 100 2160 1440
+drawArc 200 100 100 100 3600 1440
+drawArc 200 100 100 100 5040 1440
+
+drawArc 200 200 100 100 -720 -1440
+drawArc 200 200 100 100 -2160 -1440
+drawArc 200 200 100 100 -3600 -1440
+drawArc 200 200 100 100 -5040 -1440
+
+
+drawArc 300 100 100 100 3840 480
+drawArc 300 200 100 100 -3840 -480
+
+drawArc 300 100 100 100 1600 1340
+
+setPen black
+drawArc 400 100 200 200 0 5760
+setPen white
+drawArc 400 100 200 200 960 960
+drawArc 400 100 200 200 2880 960
+drawArc 400 100 200 200 4800 960
+
+setPen black
+drawArc 100 350 300 300 160 5760
+drawArc 100 350 300 300 320 5760
+drawArc 100 350 300 300 1920 5760
+drawArc 100 350 300 300 2080 5760
+drawArc 100 350 300 300 3680 5760
+drawArc 100 350 300 300 3840 5760
+drawArc 100 350 300 300 5440 5760
+drawArc 100 350 300 300 5600 5760
+setPen white
+drawArc 100 350 300 300 0 5760
+
+translate 400 300
+setRenderHint Antialiasing true
+setPen blue 40
+drawArc 100 100 200 200 0 4320
+setPen red 40
+drawArc 60 60 280 280 0 4320
diff --git a/tests/baseline/painting/scripts/background.qps b/tests/baseline/painting/scripts/background.qps
new file mode 100644
index 0000000000..d1efe5c178
--- /dev/null
+++ b/tests/baseline/painting/scripts/background.qps
@@ -0,0 +1,136 @@
+# Version: 1
+# CheckVsReference: 5%
+
+translate 10 30
+setBackground 7f7fff
+setBackgroundMode Transparent
+setPen ff7f7f
+
+path_moveTo path 0 0
+path_lineTo path 25 0
+path_cubicTo path 50 0 25 25 25 50
+path_lineTo path 0 50
+
+bitmap_load bitmap.png bitmap
+
+begin_block drawing
+ save
+ drawRect 0 0 50 50
+
+ translate 60 0
+ drawEllipse 0 0 50 50
+
+ translate 60 0
+ drawPolygon [0 0 50 0 25 50 25 25]
+
+ translate 60 0
+ drawPath path
+
+ translate 60 0
+ drawPie 0 0 50 50 1440 2000
+
+ translate 60 0
+ drawChord 0 0 50 50 1440 2000
+
+ translate 60 0
+ drawLine 0 0 50 0
+ drawLine 0 0 50 50
+ drawLine 0 0 0 50
+
+ translate 60 0
+ drawPolyline [0 0 50 0 25 50 25 25]
+
+ translate 60 0
+ drawArc 0 0 50 50 1440 2000
+
+ translate 60 0
+ drawText 0 10 "Jambi-Bambi"
+
+ translate 80 0
+ drawPixmap bitmap 0 0
+ restore
+
+ save
+ setRenderHint Antialiasing
+ translate 5 55
+ drawRect 0 0 50 50
+
+ translate 60 0
+ drawEllipse 0 0 50 50
+
+ translate 60 0
+ drawPolygon [0 0 50 0 25 50 25 25]
+
+ translate 60 0
+ drawPath path
+
+ translate 60 0
+ drawPie 0 0 50 50 1440 2000
+
+ translate 60 0
+ drawChord 0 0 50 50 1440 2000
+
+ translate 60 0
+ drawLine 0 0 50 0
+ drawLine 0 0 50 50
+ drawLine 0 0 0 50
+
+ translate 60 0
+ drawPolyline [0 0 50 0 25 50 25 25]
+
+ translate 60 0
+ drawArc 0 0 50 50 1440 2000
+
+ translate 60 0
+ drawText 0 10 "Jambi-Bambi"
+
+ translate 80 0
+ drawPixmap bitmap 0 0
+ restore
+end_block
+
+translate 0 160
+setBackgroundMode Transparent
+setPen ff7f7f 0 dotline flatcap beveljoin
+repeat_block drawing
+
+translate 0 160
+setBackgroundMode Opaque
+setPen ff7f7f 0 dotline flatcap beveljoin
+repeat_block drawing
+
+translate 0 160
+setBackgroundMode Transparent
+setPen ff7f7f 4 dashline flatcap beveljoin
+repeat_block drawing
+
+translate 0 160
+setBackgroundMode OpaqueMode
+setPen ff7f7f 4 dashline flatcap beveljoin
+repeat_block drawing
+
+resetMatrix
+
+translate 5 5
+
+setBrush nobrush
+setPen black
+setBackgroundMode transparent
+drawText 10 15 "TransparentMode with solid 0-width pen"
+drawRect 0 0 685 135
+
+translate 0 160
+drawText 10 15 "TransparentMode with dotted 0-width pen"
+drawRect 0 0 685 135
+
+translate 0 160
+drawText 10 15 "OpaqueMode with dotted 0-width pen"
+drawRect 0 0 685 135
+
+translate 0 160
+drawText 10 15 "TransparentMode with dotted 4-width pen"
+drawRect 0 0 685 135
+
+translate 0 160
+drawText 10 15 "OpaqueMode with solid 4-width pen"
+drawRect 0 0 685 135
diff --git a/tests/baseline/painting/scripts/background_brush.qps b/tests/baseline/painting/scripts/background_brush.qps
new file mode 100644
index 0000000000..ca1f944964
--- /dev/null
+++ b/tests/baseline/painting/scripts/background_brush.qps
@@ -0,0 +1,5 @@
+# Version: 1
+# CheckVsReference: 5%
+
+setBrush #00ff00 crosspattern
+import "background.qps" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/beziers.qps b/tests/baseline/painting/scripts/beziers.qps
new file mode 100644
index 0000000000..62d9d031a6
--- /dev/null
+++ b/tests/baseline/painting/scripts/beziers.qps
@@ -0,0 +1,148 @@
+# Version: 1
+# CheckVsReference: 5%
+
+setRenderHint LineAntialiasing
+
+setPen green 0
+
+translate 20 20
+path_moveTo fullSize 0 0
+path_cubicTo fullSize 200 100 -100 100 100 0
+
+path_moveTo fullSize 0 200
+path_cubicTo fullSize 0 100 100 100 100 200
+
+path_moveTo fullSize 0 250
+path_cubicTo fullSize 50 200 50 200 100 250
+drawPath fullSize
+
+translate 110 0
+scale 10 10
+path_moveTo medSize 0 0
+path_cubicTo medSize 20 10 -10 10 10 0
+
+path_moveTo medSize 0 20
+path_cubicTo medSize 0 10 10 10 10 20
+
+path_moveTo medSize 0 25
+path_cubicTo medSize 5 20 5 20 10 25
+drawPath medSize
+
+resetMatrix
+translate 240 20
+scale 100 100
+path_moveTo smallSize 0 0
+path_cubicTo smallSize 2 1 -1 1 1 0
+
+path_moveTo smallSize 0 2
+path_cubicTo smallSize 0 1 1 1 1 2
+
+path_moveTo smallSize 0 2.5
+path_cubicTo smallSize 0.5 2 0.5 2 1 2.5
+drawPath smallSize
+
+resetMatrix
+translate 20 300
+drawPath medSize
+
+resetMatrix
+translate 250 -100
+path_moveTo maxSize 0 500
+path_cubicTo maxSize 1000 0 -500 0 500 500
+drawPath maxSize
+
+setRenderHint Antialiasing off
+resetMatrix
+
+path_moveTo path1 0 0
+path_cubicTo path1 10 10 0 10 10 0
+
+path_moveTo path2 0 0
+path_cubicTo path2 15 15 -5 15 10 0
+
+path_moveTo path3 0 0
+path_cubicTo path3 20 20 -10 20 10 0
+
+path_moveTo path4 0 0
+path_cubicTo path4 0 5 10 10 0 15
+
+path_moveTo path5 0 10
+path_cubicTo path5 10 10 -10 20 0 0
+
+path_moveTo path6 0 0
+path_cubicTo path6 10 5 -10 10 0 15
+
+setPen black 2
+setBrush nobrush
+
+translate 10 500
+scale 3 3
+begin_block paths
+save
+drawPath path1
+translate 20 0
+drawPath path2
+translate 20 0
+drawPath path3
+translate 20 0
+drawPath path4
+translate 20 0
+drawPath path5
+translate 20 0
+drawPath path6
+restore
+end_block
+
+setPen nopen
+setBrush black
+
+translate 0 20
+repeat_block paths
+
+setRenderHint Antialiasing
+
+setPen black 2
+setBrush nobrush
+
+translate 120 -20
+repeat_block paths
+
+setPen nopen
+setBrush black
+
+translate 0 20
+repeat_block paths
+
+resetMatrix
+path_moveTo miterPath 20 0
+path_cubicTo miterPath 20 20 0 0 1 0
+path_lineTo miterPath -1 -0.2
+
+setBrush nobrush
+
+translate 50 660
+scale 5 5
+
+setPen black 4 solidline flatcap miterjoin
+drawPath miterPath
+setPen red 0
+drawPath miterPath
+
+path_moveTo miterPath2 21 0.2
+path_lineTo miterPath2 19 0
+path_cubicTo miterPath2 20 0 0 20 0 0
+
+translate 30 0
+setPen black 4 solidline flatcap miterjoin
+drawPath miterPath2
+setPen red 0
+drawPath miterPath2
+
+path_moveTo wonkyPath 0 0
+path_cubicTo wonkyPath 5 15 20 0 17 0
+
+translate 30 0
+setPen black 4 solidline flatcap miterjoin
+drawPath wonkyPath
+setPen red 0
+drawPath wonkyPath
diff --git a/tests/baseline/painting/scripts/bitmaps.qps b/tests/baseline/painting/scripts/bitmaps.qps
new file mode 100644
index 0000000000..4966490337
--- /dev/null
+++ b/tests/baseline/painting/scripts/bitmaps.qps
@@ -0,0 +1,166 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+#setRenderHint SmoothPixmapTransform
+
+translate 10 50
+setBackground ff7f7f
+setPen 3f3f9f
+
+bitmap_load dome_mono.png the_pixmap
+
+save
+ # Draw with opaque pen/bg in transparent/opaque mode
+ setBackgroundMode Transparent
+ drawPixmap the_pixmap 0 0
+ setBackgroundMode Opaque
+ drawPixmap the_pixmap 110 0
+
+ translate 220 0
+
+ # Draw with alpha pen/bg in transparent/opaque mode
+ save
+ setBackground 7fff7f7f
+ setPen 7f3f3f9f
+ setBackgroundMode Transparent
+ drawPixmap the_pixmap 0 0
+ setBackgroundMode Opaque
+ drawPixmap the_pixmap 110 0
+ restore
+
+ translate 220 0
+
+ # Draw with rotated opaque pen/bg in transparent/opaque mode
+ setBackgroundMode Transparent
+ save
+ translate 50 50
+ rotate 10
+ translate -50 -50
+ drawPixmap the_pixmap 0 0
+ restore
+ setBackgroundMode Opaque
+ translate 110 0
+ save
+ translate 50 50
+ rotate 10
+ translate -50 -50
+ drawPixmap the_pixmap 0 0
+ restore
+restore
+
+translate 0 150
+
+save
+ setBackgroundMode Transparent
+ drawTiledPixmap the_pixmap 0 0 200 100
+ setBackgroundMode Opaque
+ drawTiledPixmap the_pixmap 210 0 200 100
+
+ translate 440 -10
+ save
+ rotate 10
+ drawTiledPixmap the_pixmap 0 0 200 100
+ restore
+restore
+
+translate 0 150
+save
+ setBackgroundMode Transparent
+ drawTiledPixmap the_pixmap 0 0 200 100 10 20
+ setBackgroundMode Opaque
+ drawTiledPixmap the_pixmap 210 0 200 100 10 20
+
+ translate 440 -10
+ save
+ rotate 10
+ drawTiledPixmap the_pixmap 0 0 200 100 10 20
+ restore
+restore
+
+
+pixmap_setMask the_pixmap mask_100.png
+drawPixmap the_pixmap 0 150
+setBackgroundMode Opaque
+drawPixmap the_pixmap 110 150
+
+translate 220 150
+save
+ translate 50 50
+ rotate 10
+ translate -50 -50
+ setBackgroundMode Transparent
+ drawPixmap the_pixmap 0 0
+restore
+
+translate 110 0
+save
+ translate 50 50
+ rotate 10
+ translate -50 -50
+ setBackgroundMode Opaque
+ drawPixmap the_pixmap 0 0
+restore
+
+resetMatrix
+translate 10 650
+bitmap_load dome_mono.png the_bitmap
+setBackgroundMode Transparent
+
+begin_block draw_subrected
+ drawPixmap the_bitmap 0 0 50 50 0 0 50 50
+ drawPixmap the_bitmap 50 0 50 50 50 0 50 50
+ drawPixmap the_bitmap 0 50 50 50 0 50 50 50
+ drawPixmap the_bitmap 50 50 50 50 50 50 50 50
+end_block
+
+translate 110 0
+setBackgroundMode Opaque
+repeat_block draw_subrected
+
+translate 110 0
+save
+ translate 20 -10
+ rotate 10
+ setBackgroundMode Transparent
+ repeat_block draw_subrected
+restore
+
+translate 110 0
+save
+ translate 20 -10
+ rotate 10
+ setBackgroundMode Opaque
+ repeat_block draw_subrected
+restore
+
+# Some helpful texts
+
+resetMatrix
+setPen black
+drawText 10 40 "Transparent"
+drawText 120 40 "Opaque"
+drawText 230 40 "Trans w/alpha"
+drawText 340 40 "Opaque w/alpha"
+drawText 450 40 "Trans w/xform"
+drawText 560 40 "Opaque w/xform"
+
+drawText 10 190 "Transparent tiled"
+drawText 220 190 "Opaque tiled"
+drawText 440 190 "Opaque w/xform"
+
+drawText 10 340 "Transparent tiled w/offset"
+drawText 220 340 "Opaque tiled w/offset"
+drawText 440 340 "Opaque w/xform w/offset"
+
+drawText 10 490 "Trans masked"
+drawText 120 490 "Opaque masked"
+drawText 230 490 "masked w/xform"
+drawText 340 490 "masked w/xform"
+
+drawText 10 640 "Subrected"
+drawText 110 640 "Subrected opaque"
+drawText 220 640 "subrect w/xform"
+drawText 330 640 "subrect w/xform opaque"
+
+
diff --git a/tests/baseline/painting/scripts/borderimage.qps b/tests/baseline/painting/scripts/borderimage.qps
new file mode 100644
index 0000000000..ebd4f4d249
--- /dev/null
+++ b/tests/baseline/painting/scripts/borderimage.qps
@@ -0,0 +1,120 @@
+# Version: 1
+# CheckVsReference: 10%
+
+image_load borderimage.png borderimage
+translate -128 -128
+begin_block draw_border
+# top
+drawImage borderimage 0 0 16 16 0 0 16 16
+drawImage borderimage 16 0 36 16 16 0 32 16
+drawImage borderimage 52 0 16 16 48 0 16 16
+# sides
+drawImage borderimage 0 16 16 16 0 16 16 32
+drawImage borderimage 52 16 16 16 48 16 16 32
+#bottom
+drawImage borderimage 0 32 16 16 0 48 16 16
+drawImage borderimage 16 32 36 16 16 48 32 16
+drawImage borderimage 52 32 16 16 48 48 16 16
+end_block draw_border
+resetMatrix
+begin_block draw_column
+translate 1 1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+translate 0.1 64.1
+repeat_block draw_border
+end_block draw_column
+setRenderHint Antialiasing
+resetMatrix
+translate 72 0
+repeat_block draw_column
+resetMatrix
+scale 1.25 1.25
+translate 144 0
+repeat_block draw_border
+resetMatrix
+scale 1.25 1.25
+translate 246 0
+rotate 30
+repeat_block draw_border
+setRenderHint SmoothPixmapTransform
+resetMatrix
+scale 1.25 1.25
+translate 144 120
+repeat_block draw_border
+resetMatrix
+scale 1.25 1.25
+translate 246 120
+rotate 30
+repeat_block draw_border
+resetMatrix
+translate 215 260
+scale 3.55 3.55
+rotate 30
+repeat_block draw_border
+resetMatrix
+setRenderHint SmoothPixmapTransform off
+setRenderHint Antialiasing off
+translate 480 627
+rotate 180
+repeat_block draw_column
+resetMatrix
+setRenderHint Antialiasing
+translate 552 627
+rotate 180
+repeat_block draw_column
+resetMatrix
+setRenderHint Antialiasing off
+translate 200.1 520.1
+begin_block one_pixel_border
+drawImage borderimage 0 0 16 16 0 0 16 16
+drawImage borderimage 16 0 64 16 16 0 1 1
+drawImage borderimage 80 0 16 16 48 0 16 16
+drawImage borderimage 0 16 16 64 16 0 1 1
+drawImage borderimage 80 16 16 64 16 0 1 1
+drawImage borderimage 0 80 16 16 0 48 16 16
+drawImage borderimage 16 80 64 16 16 0 1 1
+drawImage borderimage 80 80 16 16 48 48 16 16
+end_block one_pixel_border
+resetMatrix
+translate 205.1 626.1
+scale 0.4 0.4
+repeat_block one_pixel_border
+resetMatrix
+translate 255.1 624.1
+scale 0.4 0.4
+rotate 10
+repeat_block one_pixel_border
+resetMatrix
+setPen red
+drawRect 0 0 70 680
+drawText 10 670 "aa off"
+drawRect 72 0 70 680
+drawText 80 670 "aa on"
+drawRect 409 0 70 680
+drawText 419 650 "rot 180"
+drawText 419 670 "aa off"
+drawRect 481 0 70 680
+drawText 491 650 "rot 180"
+drawText 491 670 "aa on"
+drawRect 164 0 224 124
+drawText 174 114 "smoothpixmaptransform off"
+drawRect 164 128 224 134
+drawText 174 252 "smoothpixmaptransform on"
+drawRect 200 520 97 188
+drawText 210 698 "1x1 edges" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/brush_pens.qps b/tests/baseline/painting/scripts/brush_pens.qps
new file mode 100644
index 0000000000..b9a2bc0ada
--- /dev/null
+++ b/tests/baseline/painting/scripts/brush_pens.qps
@@ -0,0 +1,104 @@
+# Version: 1
+# CheckVsReference: 5%
+
+path_addRect p 0 0 75 75
+path_addEllipse p 25 25 75 75
+
+translate 10 10
+
+begin_block setup_gradient
+ gradient_clearStops
+ gradient_appendStop 0 red
+ gradient_appendStop 0.1 blue
+ gradient_appendStop 0.2 yellow
+ gradient_appendStop 0.3 cyan
+ gradient_appendStop 0.4 magenta
+ gradient_appendStop 0.5 green
+ gradient_appendStop 0.6 black
+ gradient_appendStop 0.7 indianred
+ gradient_appendStop 0.8 white
+ gradient_appendStop 0.9 orange
+ gradient_appendStop 1 blue
+ gradient_setLinear 0 0 100 100
+end_block
+
+setPen brush 0
+setBrush nobrush
+
+begin_block drawing
+ save
+ drawLine 0 0 100 100
+
+ translate 0 100
+ drawPath p
+
+ translate 0 110
+ drawRect 0 0 100 100
+
+ translate 0 110
+ drawPolyline [0 0 100 0 50 50]
+
+ drawPoint 40 40
+ drawPoint 41 40
+ drawPoint 42 40
+ drawPoint 43 40
+ drawPoint 44 40
+ drawPoint 45 40
+ drawPoint 46 40
+ drawPoint 47 40
+ drawPoint 48 40
+ drawPoint 49 40
+ drawPoint 50 40
+
+ restore
+end_block
+
+save
+ translate 110 0
+ save
+ setRenderHint Antialiasing
+ repeat_block drawing
+ restore
+
+ setBrush dome_rgb32.png
+ setPen brush 0
+ setBrush nobrush
+
+ translate 110 0
+ repeat_block drawing
+
+ translate 110 0
+ save
+ setRenderHint Antialiasing
+ repeat_block drawing
+ restore
+restore
+
+translate 0 0
+
+save
+ repeat_block setup_gradient
+ setPen brush 5
+ setBrush nobrush
+ translate 0 350
+ repeat_block drawing
+
+ translate 110 0
+ save
+ setRenderHint Antialiasing
+ repeat_block drawing
+ restore
+
+ setBrush dome_rgb32.png
+ setPen brush 5
+ setBrush nobrush
+
+ translate 110 0
+ repeat_block drawing
+
+ translate 110 0
+ save
+ setRenderHint Antialiasing
+ repeat_block drawing
+ restore
+restore \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/brushes.qps b/tests/baseline/painting/scripts/brushes.qps
new file mode 100644
index 0000000000..43a7843601
--- /dev/null
+++ b/tests/baseline/painting/scripts/brushes.qps
@@ -0,0 +1,88 @@
+# Version: 1
+# CheckVsReference: 5%
+
+# Fill the background
+drawRect 0 0 width height
+
+setRenderHint Antialiasing
+setRenderHint SmoothPixmapTransform
+
+translate 10 10
+# Draw all the pattern types as 40x40 rects using green, transparent background
+begin_block drawrects
+setBrush green Dense1Pattern
+drawRect 0 0 40 40
+setBrush green Dense2Pattern
+drawRect 40 0 40 40
+setBrush green Dense3Pattern
+drawRect 80 0 40 40
+setBrush green Dense4Pattern
+drawRect 120 0 40 40
+setBrush green Dense5Pattern
+drawRect 160 0 40 40
+setBrush green Dense6Pattern
+drawRect 200 0 40 40
+setBrush green Dense7Pattern
+drawRect 240 0 40 40
+setBrush green HorPattern
+drawRect 280 0 40 40
+setBrush green VerPattern
+drawRect 320 0 40 40
+setBrush green CrossPattern
+drawRect 360 0 40 40
+setBrush green BDiagPattern
+drawRect 400 0 40 40
+setBrush green FDiagPattern
+drawRect 440 0 40 40
+setBrush green DiagCrossPattern
+drawRect 480 0 40 40
+setBrush green SolidPattern
+drawRect 520 0 40 40
+setBrush green NoBrush
+drawRect 560 0 40 40
+gradient_setLinear 0 0 0 40
+drawRect 600 0 40 40
+setBrush face.png
+drawRect 640 0 80 40
+end_block
+
+# Switch to opaque mode
+setBackground #7fff7f
+setBackgroundMode OpaqueMode
+translate 0 50
+
+# Draw all the pattern types as 40x40 rects using green, opaque background
+repeat_block drawrects
+
+translate 50 50
+rotate 10
+
+
+setBackgroundMode TransparentMode
+repeat_block drawrects
+setBackgroundMode OpaqueMode
+translate 0 40
+repeat_block drawrects
+
+
+setBrush dot.png
+setPen nopen
+resetMatrix
+drawRect 0 200 50 50
+drawRect 50 200 50 50
+
+setPen red
+setBrushOrigin 0 250
+drawRect 0 250 50 50
+setBrushOrigin 50 250
+drawRect 50 250 50 50
+
+
+setBrush dome_indexed.png
+setPen nopen
+brushScale 0.7 0.7
+drawRect 20 320 600 200
+
+setBrush dome_argb32.png
+brushScale 1.5 1.5
+drawRect 20 540 600 200
diff --git a/tests/baseline/painting/scripts/clippath_antialiasing.qps b/tests/baseline/painting/scripts/clippath_antialiasing.qps
new file mode 100644
index 0000000000..193ce8b7ed
--- /dev/null
+++ b/tests/baseline/painting/scripts/clippath_antialiasing.qps
@@ -0,0 +1,76 @@
+# There was no serration in either case
+save
+setBrush black SolidPattern
+drawRect 0.0 0.0 500.0 300.0
+restore
+
+save
+setRenderHint Antialiasing true
+path_addEllipse mypath1 10.0 10.0 200.0 200.0
+path_addRect mypath1 10.0 210.0 200.0 40.0
+path_addPolygon mypath1 [ 10 250 50 280 90 300 130 300 170 280 210 250]
+
+setClipPath mypath1 ReplaceClip
+setPen NoPen
+setBrush cyan SolidPattern
+drawRect 10.0 10.0 400.0 400.0
+restore
+save
+setRenderHint Antialiasing false
+path_addEllipse mypath2 220.0 10.0 200.0 200.0
+path_addRect mypath2 220.0 210.0 200.0 40.0
+path_addPolygon mypath2 [ 220 250 270 280 300 300 340 300 380 280 420 250]
+setClipPath mypath2 ReplaceClip
+setRenderHint Antialiasing true
+setPen NoPen
+setBrush cyan SolidPattern
+drawRect 220.0 10.0 300.0 300.0
+restore
+
+setPen red
+setBrush NoBrush
+drawText 20 250 "Antialiasing before setClipPath"
+drawText 240 250 "Antialiasing after setClipPath"
+
+# Test that the clipping region is not abnormal after some transformations
+translate 100 300
+
+save
+path_addEllipse mypath3 10.0 10.0 200.0 200.0
+path_addRect mypath3 10.0 210.0 200.0 40.0
+setPen black SolidLine
+setBrush NoBrush
+setRenderHint Antialiasing true
+drawPath mypath3
+setClipPath mypath3 ReplaceClip
+rotate 60
+setFont "times" 10 Bold
+drawText 10 70 "Antialiasing before setClipPath - Transformation"
+drawText 10 40 "Antialiasing before setClipPath - Transformation"
+drawText 10 10 "Antialiasing before setClipPath - Transformation"
+drawText 10 -20 "Antialiasing before setClipPath - Transformation"
+drawText 10 -50 "Antialiasing before setClipPath - Transformation"
+drawText 10 -80 "Antialiasing before setClipPath - Transformation"
+restore
+
+translate 0 250
+
+save
+path_addEllipse mypath4 10.0 10.0 200.0 200.0
+path_addRect mypath4 10.0 210.0 200.0 40.0
+setPen black SolidLine
+setBrush NoBrush
+drawPath mypath4
+setClipPath mypath4 ReplaceClip
+setRenderHint Antialiasing true
+rotate 60
+setFont "times" 10 Bold
+drawText 10 70 "Antialiasing after setClipPath - Transformation"
+drawText 10 40 "Antialiasing after setClipPath - Transformation"
+drawText 10 10 "Antialiasing after setClipPath - Transformation"
+drawText 10 -20 "Antialiasing after setClipPath - Transformation"
+drawText 10 -50 "Antialiasing after setClipPath - Transformation"
+drawText 10 -80 "Antialiasing after setClipPath - Transformation"
+restore
+
+
diff --git a/tests/baseline/painting/scripts/clippaths.qps b/tests/baseline/painting/scripts/clippaths.qps
new file mode 100644
index 0000000000..fe8e198a17
--- /dev/null
+++ b/tests/baseline/painting/scripts/clippaths.qps
@@ -0,0 +1,60 @@
+# Version: 1
+# CheckVsReference: 5%
+
+path_addRect hor 0 0 50 10
+path_addRect ver 0 0 10 50
+
+translate 10 10
+setPen NoPen
+
+begin_block clipping
+save
+
+ setBrush 0x7f7fff
+ save
+ setClipPath hor
+ drawRect 0 0 100 100
+
+ setClipPath ver IntersectClip
+ setBrush black CrossPattern
+ drawRect 0 0 100 100
+ restore
+
+ translate 100 0
+ save
+ setClipPath hor
+ drawRect 0 0 100 100
+
+ setClipPath ver ReplaceClip
+ setBrush black CrossPattern
+ drawRect 0 0 100 100
+ restore
+
+ translate 100 0
+ save
+ setClipPath hor
+ drawRect 0 0 100 100
+
+ setClipPath ver UniteClip
+ setBrush black CrossPattern
+ drawRect 0 0 100 100
+ restore
+
+restore
+end_block
+
+translate 300 0
+setRenderHint Antialiasing
+repeat_block clipping
+
+translate -300 100
+setRenderHint Antialiasing false
+scale 1.2 1.2
+repeat_block clipping
+
+translate 300 0
+setRenderHint Antialiasing
+setRenderHint SmoothPixmapTransform
+repeat_block clipping
+
+
diff --git a/tests/baseline/painting/scripts/clipping.qps b/tests/baseline/painting/scripts/clipping.qps
new file mode 100644
index 0000000000..3694ff2ba7
--- /dev/null
+++ b/tests/baseline/painting/scripts/clipping.qps
@@ -0,0 +1,182 @@
+# Version: 1
+# CheckVsReference: 5%
+
+region_addRect clip 50 0 90 190
+region_addRect clip 0 50 180 90
+
+region_addRect clip2 30 30 60 60
+
+region_addRect clip3 10 10 60 60
+
+path_cubicTo path 90 0 50 50 90 90
+path_cubicTo path 0 90 50 50 0 0
+
+path_addRect path2 0 0 90 90
+path_moveTo path2 90 45
+path_arcTo path2 0 0 90 90 0 -360
+
+path_addRect emptypath 0 0 0 0
+region_addRect emptyregion 0 0 0 0
+
+# Normal clip rect
+setClipRect 0 0 50 150
+begin_block repaint
+save
+setBrush red
+setPen nopen
+resetMatrix
+region_getClipRegion tmpclip
+path_getClipPath tmpclippath
+drawRect 0 0 width height
+setBrush #3f0000ff
+setClipRegion tmpclip
+drawRect 0 0 width height
+setClipPath tmpclippath
+setBrush #3f00ff00
+drawRect 0 0 width height
+restore
+end_block
+
+# Rotated clip rect
+translate 100 0
+rotate 10
+setClipRect 0 0 50 150
+repeat_block repaint
+
+# simple clip region
+resetMatrix
+translate 0 200
+setClipRegion clip
+repeat_block repaint
+
+# simle rotated clip region
+translate 250 -10
+rotate 10
+setClipRegion clip
+repeat_block repaint
+
+# verify that clip is not xformed with painter
+resetMatrix
+translate 200 0
+setClipRegion clip
+rotate 30
+setBrush red
+setPen nopen
+drawRect 0 0 width height
+
+resetMatrix
+translate 0 400
+save
+setClipRegion clip
+setClipRegion clip2 IntersectClip
+repeat_block repaint
+translate 0 100
+rotate 10
+setClipRegion clip
+setClipRegion clip2 IntersectClip
+restore
+
+translate 100 0
+save
+setClipRegion clip3
+setClipRegion clip2 UniteClip
+repeat_block repaint
+translate 0 100
+rotate 10
+setClipRegion clip3
+setClipRegion clip2 UniteClip
+repeat_block repaint
+restore
+
+translate 100 0
+save
+setClipPath path
+repeat_block repaint
+translate 50 100
+rotate 45
+setClipPath path
+repeat_block repaint
+restore
+
+translate 100 0
+save
+setClipPath path
+setClipPath path2 IntersectClip
+repeat_block repaint
+translate 0 100
+rotate 10
+setClipPath path
+setClipPath path2 IntersectClip
+repeat_block repaint
+restore
+
+translate 100 0
+save
+setClipPath path
+setClipPath path2 UniteClip
+repeat_block repaint
+translate 0 100
+rotate 10
+setClipPath path
+setClipPath path2 UniteClip
+repeat_block repaint
+restore
+
+translate 100 0
+save
+setClipPath path
+setClipRegion clip3 IntersectClip
+repeat_block repaint
+translate 0 100
+rotate 10
+setClipRegion clip3
+setClipPath path IntersectClip
+repeat_block repaint
+restore
+
+translate 100 0
+save
+setClipPath path
+setClipRegion clip3 UniteClip
+repeat_block repaint
+translate 0 100
+rotate 10
+setClipRegion clip3
+setClipPath path UniteClip
+repeat_block repaint
+restore
+
+# test that an empty region is not drawn.
+resetMatrix
+setClipRegion emptyregion
+setBrush #3f00ff00
+drawRect 0 0 300 300
+drawText 50 50 "Text should be clipped away by region"
+setClipping false
+
+setClipPath emptypath
+setBrush #3fffff00
+drawRect 50 50 300 300
+drawText 70 80 "Text should be clipped away by path"
+
+# Test that we can extract a clipregion when a matrix is set too
+resetMatrix
+translate 500 10
+scale 2 1
+setBrush blue
+setClipping false
+rotate 5
+drawRect 0 0 100 100
+setClipRect 0 0 100 100
+resetMatrix
+rotate 10
+region_getClipRegion xclip
+setClipRegion xclip
+resetMatrix
+setBrush #7f00ff00
+drawRect 0 0 width height
+
+# the below used to assert in debug mode
+setClipRect 10 10 20 20
+setClipping false
+setClipping true \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/clipping_state.qps b/tests/baseline/painting/scripts/clipping_state.qps
new file mode 100644
index 0000000000..a29d3738c8
--- /dev/null
+++ b/tests/baseline/painting/scripts/clipping_state.qps
@@ -0,0 +1,47 @@
+# Version: 1
+# CheckVsReference: 5%
+
+path_addRect path1 10 10 50 50
+path_addRect path2 30 30 50 50
+# enable/disable a clip path
+setPen nopen
+setBrush red
+setClipPath path1
+setClipPath path2 UniteClip
+drawRect 0 0 100 100
+setClipping false
+setBrush #630000ff
+drawRect 0 0 100 100
+setClipping true
+setBrush #6300ff00
+drawRect 0 0 100 100
+# enable/disable noclip
+translate 150 0
+setClipPath path1 NoClip
+setClipping false
+setBrush #630000ff
+drawRect 0 0 100 100
+setClipping true
+setBrush #6300ff00
+drawRect 25 25 50 50
+# enable/disable full clipping
+translate 150 0
+path_addRect path3 0 0 10 10
+path_addRect path4 20 20 10 10
+setClipPath path3
+setClipPath path4 IntersectClip
+setClipping false
+setBrush #630000ff
+drawRect 0 0 100 100
+setClipping true
+setBrush #6300ff00
+drawRect 25 25 50 50
+# disable clipping followed by setClipRect
+translate 150 0
+setClipRect 0 0 50 50 ReplaceClip
+setClipping false
+setBrush #630000ff
+drawRect 0 0 100 100
+setClipRect 25 25 75 75 IntersectClip
+setBrush #6300ff00
+drawRect 25 25 50 50 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/cliprects.qps b/tests/baseline/painting/scripts/cliprects.qps
new file mode 100644
index 0000000000..aa0367eccf
--- /dev/null
+++ b/tests/baseline/painting/scripts/cliprects.qps
@@ -0,0 +1,59 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+
+translate 10 10
+setPen NoPen
+
+begin_block clipping
+save
+
+ setBrush 0x7f7fff
+ save
+ setClipRect 0 0 50 10
+ drawRect 0 0 100 100
+
+ setClipRect 0 0 10 50 IntersectClip
+ setBrush black CrossPattern
+ drawRect 0 0 100 100
+ restore
+
+ translate 100 0
+ save
+ setClipRect 0 0 50 10
+ drawRect 0 0 100 100
+
+ setClipRect 0 0 10 50 ReplaceClip
+ setBrush black CrossPattern
+ drawRect 0 0 100 100
+ restore
+
+ translate 100 0
+ save
+ setClipRect 0 0 50 10
+ drawRect 0 0 100 100
+
+ setClipRect 0 0 10 50 UniteClip
+ setBrush black CrossPattern
+ drawRect 0 0 100 100
+ restore
+
+restore
+end_block
+
+translate 300 0
+setRenderHint Antialiasing
+repeat_block clipping
+
+translate -300 100
+setRenderHint Antialiasing false
+scale 1.2 1.2
+repeat_block clipping
+
+translate 300 0
+setRenderHint Antialiasing
+setRenderHint SmoothPixmapTransform
+repeat_block clipping
+
+
diff --git a/tests/baseline/painting/scripts/conical_gradients.qps b/tests/baseline/painting/scripts/conical_gradients.qps
new file mode 100644
index 0000000000..d6eb860f3f
--- /dev/null
+++ b/tests/baseline/painting/scripts/conical_gradients.qps
@@ -0,0 +1,85 @@
+# Version: 1
+# CheckVsReference: 5%
+
+path_addRect path 300 0 80 80
+path_addEllipse path 340 40 60 60
+
+setRenderHint Antialiasing
+
+setPen black
+
+begin_block gradients
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setConical 40 40 50
+drawRect 0 0 100 100
+
+gradient_setConical 140 40 230
+drawEllipse 100 0 100 100
+
+gradient_clearStops
+gradient_appendStop 0 3f7f7fff
+gradient_appendStop 0.5 dfdfffff
+gradient_appendStop 1 7f00007f
+
+gradient_setConical 240 40 50
+drawPolygon [200 0 290 0 250 99]
+
+gradient_setConical 340 40 230
+drawPath path
+
+end_block
+
+translate 0 100
+scale 1 2
+repeat_block gradients
+
+resetMatrix
+translate 0 300
+brushTranslate 30 0
+brushScale 0.9 0.9
+brushRotate 20
+repeat_block gradients
+
+# Some helpful info perhaps?
+resetMatrix
+setPen black
+
+drawText 410 50 "No XForm"
+drawText 410 200 "scale 1x2"
+drawText 410 300 "brush transform"
+drawText 10 450 "50 deg"
+drawText 110 450 "230 deg"
+drawText 210 450 "50 deg w/alpha "
+drawText 310 450 "230 deg w/alpha"
+
+setPen 3f000000
+setBrush nobrush
+
+begin_block ellipse_draw
+ setClipRect 0 0 100 100
+ drawEllipse 35 35 11 11
+ save
+ translate 40 40
+ rotate -50
+ drawLine -100 0 100 0
+ restore
+ translate 100 0
+end_block
+
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+
+resetMatrix
+translate 0 100
+scale 1 2
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/conical_gradients_perspectives.qps b/tests/baseline/painting/scripts/conical_gradients_perspectives.qps
new file mode 100644
index 0000000000..a9c14f1ce7
--- /dev/null
+++ b/tests/baseline/painting/scripts/conical_gradients_perspectives.qps
@@ -0,0 +1,64 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+setRenderHint Antialiasing
+
+setPen #00ff00
+
+translate 10 10
+# standard draw
+begin_block gradient
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 0.9 cyan
+gradient_appendStop 1 red
+
+gradient_setSpread PadSpread
+gradient_setConical 140 140 100
+drawRect 0 0 300 300
+end_block gradient
+
+# Rotation w/o smooth xform
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 50 0 200 300 300 300 0
+ repeat_block gradient
+restore
+restore
+
+translate 0 320
+
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 100 300 200 300 300 0
+ repeat_block gradient
+restore
+
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 0 300 300 250 300 50
+ repeat_block gradient
+restore
+restore
+
+
+resetMatrix
+setPen black
+translate 125 20
+drawText 0 0 "No transform"
+translate 350 0
+drawText 0 0 "Left Tilted"
+resetMatrix
+translate 125 350
+drawText 0 0 "Bottom Tilted"
+translate 350 0
+drawText 0 0 "Right Tilted"
+translate 120 0 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/cosmetic.qps b/tests/baseline/painting/scripts/cosmetic.qps
new file mode 100644
index 0000000000..3c730cf26f
--- /dev/null
+++ b/tests/baseline/painting/scripts/cosmetic.qps
@@ -0,0 +1,55 @@
+drawRect 0 0 800 800
+
+setRenderHint Antialiasing true
+image_load dome_argb32.png img
+
+save
+setBrush springgreen SolidPattern
+
+begin_block primitives
+
+setPen black 2 DashLine
+pen_setCosmetic true
+drawLine 10 60 60 10
+drawRect 80 10.0 30 50
+drawText 130 50 "Foo"
+drawImage img 160 10 50 50
+
+pen_setCosmetic false
+drawLine 10 160 60 110
+drawRect 80 110.0 30 50
+drawText 130 150 "Foo"
+drawImage img 160 110 50 50
+
+setPen NoPen
+drawLine 10 260 60 210
+drawRect 80 210.0 30 50
+drawText 130 250 "Foo"
+drawImage img 160 210 50 50
+
+end_block primitives
+
+
+translate 250 0
+rotate 10
+scale 2.5 1
+repeat_block primitives
+
+resetMatrix
+# Force non-simple pen in Pdf
+setOpacity 0.5
+translate 0 400
+repeat_block primitives
+
+translate 250 0
+rotate 10
+scale 2.5 1
+repeat_block primitives
+
+restore
+setPen blue 4 DotLine
+setBrush olive SolidPattern
+pen_setCosmetic true
+translate 50 720
+scale 2 2
+drawRect 0 0 30 30
diff --git a/tests/baseline/painting/scripts/dashes.qps b/tests/baseline/painting/scripts/dashes.qps
new file mode 100644
index 0000000000..185443a292
--- /dev/null
+++ b/tests/baseline/painting/scripts/dashes.qps
@@ -0,0 +1,268 @@
+# Version: 1
+# CheckVsReference: 5%
+
+translate 20 20
+
+begin_block draw
+save
+ save
+ setPen black 1 SolidLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 SolidLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 SolidLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 2 SolidLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 SolidLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 SolidLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 6 SolidLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 6 SolidLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 6 SolidLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ restore
+
+
+ translate 100 0
+ save
+ setPen black 1 DotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 DotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 DotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 2 DotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 DotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 DotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 6 DotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 6 DotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 6 DotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ restore
+
+ translate 100 0
+ save
+ setPen black 1 DashLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 DashLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 DashLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 2 DashLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 DashLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 DashLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 6 DashLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 6 DashLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 6 DashLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ restore
+
+ translate 100 0
+
+ save
+ setPen black 1 DashDotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 DashDotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 DashDotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 2 DashDotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 DashDotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 DashDotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 6 DashDotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 6 DashDotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 6 DashDotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ restore
+
+ translate 100 0
+
+ save
+ setPen black 1 DashDotDotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 DashDotDotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 DashDotDotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 2 DashDotDotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 DashDotDotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 DashDotDotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 4 DashDotDotLine FlatCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 4 DashDotDotLine SquareCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 4 DashDotDotLine RoundCap BevelJoin
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ restore
+
+ translate 100 0
+
+ save
+ setPen black 1 SolidLine FlatCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 SolidLine SquareCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 1 SolidLine RoundCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 2 SolidLine FlatCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 SolidLine SquareCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 2 SolidLine RoundCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+
+ setPen black 4 SolidLine FlatCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 4 SolidLine SquareCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ setPen black 4 SolidLine RoundCap BevelJoin
+ pen_setDashPattern [1 4 9 4 27 4]
+ drawPolyline [0 0 80 0 80 30 40 20 0 30]
+ translate 0 40
+ restore
+
+restore
+end_block
+
+translate 0 400
+setRenderHint Antialiasing
+repeat_block draw
+
+translate 0 -20
+drawText 30 0 "Solid"
+
+translate 100 0
+drawText 20 0 "DotLine"
+
+translate 100 0
+drawText 10 0 "DashLine"
+
+translate 100 0
+drawText 0 0 "DashDotLine"
+
+translate 100 0
+drawText 0 0 "DashDotDotLine"
+
+translate 100 0
+drawText 0 0 "CustomDashLine"
+
+resetMatrix
+
+translate 620 40
+
+begin_block width_and_caps_texts
+ drawText 0 0 "Width=1, FlatCap"
+ translate 0 40
+ drawText 0 0 "Width=1, SquareCap"
+ translate 0 40
+ drawText 0 0 "Width=1, RoundCap"
+ translate 0 40
+ drawText 0 0 "Width=2, FlatCap"
+ translate 0 40
+ drawText 0 0 "Width=2, SquareCap"
+ translate 0 40
+ drawText 0 0 "Width=2, RoundCap"
+ translate 0 40
+ drawText 0 0 "Width=6, FlatCap"
+ translate 0 40
+ drawText 0 0 "Width=6, SqareCap"
+ translate 0 40
+ drawText 0 0 "Width=6, RoundCap"
+end_block
+
+translate 0 80
+repeat_block width_and_caps_texts \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/degeneratebeziers.qps b/tests/baseline/painting/scripts/degeneratebeziers.qps
new file mode 100644
index 0000000000..948968b0cd
--- /dev/null
+++ b/tests/baseline/painting/scripts/degeneratebeziers.qps
@@ -0,0 +1,47 @@
+# Version: 1
+# CheckVsReference: 5%
+
+path_moveTo degenerate 3427.0918499999997948 3872.1318999999998596
+path_cubicTo degenerate 3427.0918499999997948 3872.1318999999994048 4729.4590867905308187 5176.8613451144155988 5389.9325499999995372 5837.8072499999998399
+
+scale 0.05 0.05
+translate -2500 -3000
+setPen black 800
+drawPath degenerate
+
+resetMatrix
+path_moveTo revbez 0 20
+path_cubicTo revbez 0 0 120 0 120 -20
+
+path_moveTo revbez 0 80
+path_cubicTo revbez 0 100 120 100 120 120
+
+translate 50 250
+
+setPen blue 40 solidline flatcap
+drawPath revbez
+setPen red 0
+drawPath revbez
+
+translate 200 0
+setPen blue 40 solidline squarecap
+drawPath revbez
+setPen red 0
+drawPath revbez
+
+translate 200 0
+setPen blue 40 solidline roundcap
+drawPath revbez
+setPen red 0
+drawPath revbez
+
+resetMatrix
+path_lineTo tightJoin 60 10
+path_cubicTo tightJoin 50 0 100 0 100 50
+
+translate 50 500
+
+setPen green 40 solidline roundcap roundjoin
+drawPath tightJoin
+setPen red 0
+drawPath tightJoin
diff --git a/tests/baseline/painting/scripts/deviceclipping.qps b/tests/baseline/painting/scripts/deviceclipping.qps
new file mode 100644
index 0000000000..8608a50994
--- /dev/null
+++ b/tests/baseline/painting/scripts/deviceclipping.qps
@@ -0,0 +1,48 @@
+# Version: 1
+# CheckVsReference: 5%
+
+setBrush 0xff7f7f
+setPen 0x7f0000
+
+path_moveTo path -1000000 10000
+path_cubicTo path 100 100 100 150 150 400
+path_closeSubpath path
+
+begin_block drawing
+
+ drawPath ellipse
+
+ drawLine -1000000 200 200 200
+ drawLine 200 -1000000 200 200
+ drawLine 200 200 1000000 200
+ drawLine 200 200 200 1000000
+ drawLine -1000000 -1000000 200 200
+
+ drawPolygon [-1000000 100 100 -1000000 100 100]
+ drawRect 300 -500000 1000000 1000000
+
+ drawPath path
+
+end_block
+
+save
+translate 20 20
+setBrush #0x7f7f7fff
+setPen #0x7f00007f
+repeat_block drawing
+
+translate 20 20
+setRenderHint Antialiasing
+setBrush #0x7f7fff7f
+setPen #0x7f007f00
+repeat_block drawing
+restore
+
+setPen 0x00007f 2
+setRenderHint Antialiasing
+
+drawLine 0 -200 200 200
+
+setPen 0x007f00 10
+
+drawLine 0 -200 200 0 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/drawpoints.qps b/tests/baseline/painting/scripts/drawpoints.qps
new file mode 100644
index 0000000000..c02cd85737
--- /dev/null
+++ b/tests/baseline/painting/scripts/drawpoints.qps
@@ -0,0 +1,101 @@
+# Version: 1
+# CheckVsReference: 5%
+
+#setRenderHint Antialiasing
+
+setPen red 0 solidline
+begin_block points
+drawPoint 00 00
+drawPoint 10 00
+drawPoint 20 00
+drawPoint 30 00
+drawPoint 40 00
+drawPoint 50 00
+drawPoint 00 10
+drawPoint 10 10
+drawPoint 20 10
+drawPoint 30 10
+drawPoint 40 10
+drawPoint 50 10
+drawPoint 00 20
+drawPoint 10 20
+drawPoint 20 20
+drawPoint 30 20
+drawPoint 40 20
+drawPoint 50 20
+drawPoint 00 30
+drawPoint 10 30
+drawPoint 20 30
+drawPoint 30 30
+drawPoint 40 30
+drawPoint 50 30
+drawPoint 00 40
+drawPoint 10 40
+drawPoint 20 40
+drawPoint 30 40
+drawPoint 40 40
+drawPoint 50 40
+drawPoint 00 50
+drawPoint 10 50
+drawPoint 20 50
+drawPoint 30 50
+drawPoint 40 50
+drawPoint 50 50
+end_block points
+
+translate 100 0
+setPen blue 1 solidline
+repeat_block points
+
+translate 100 0
+setPen green 5 solidline roundcap
+repeat_block points
+
+resetMatrix
+
+translate 0 100
+scale 3 3
+setPen red 0 solidline roundcap
+repeat_block points
+
+translate 60 0
+setPen blue 1 solidline roundcap
+repeat_block points
+
+translate 60 0
+setPen green 5 solidline roundcap
+repeat_block points
+
+resetMatrix
+
+translate 0 300
+scale 3 3
+setPen red 0 solidline flatcap
+repeat_block points
+
+translate 60 0
+setPen blue 1 solidline flatcap
+repeat_block points
+
+translate 60 0
+setPen green 5 solidline flatcap
+repeat_block points
+
+resetMatrix
+translate 10 500
+setPen black 1 solidline flatcap
+drawPoint 0 0
+setPen black 2 solidline flatcap
+drawPoint 3 0
+setPen black 3 solidline flatcap
+drawPoint 8 0
+setPen black 4 solidline flatcap
+drawPoint 15 0
+setPen black 5 solidline flatcap
+drawPoint 24 0
+setPen black 6 solidline flatcap
+drawPoint 35 0
+setPen black 7 solidline flatcap
+drawPoint 48 0
+setPen black 8 solidline flatcap
+drawPoint 63 0 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/ellipses.qps b/tests/baseline/painting/scripts/ellipses.qps
new file mode 100644
index 0000000000..e2cffd7f27
--- /dev/null
+++ b/tests/baseline/painting/scripts/ellipses.qps
@@ -0,0 +1,86 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+surface_begin 0 0 600 600
+translate 0 50
+
+setPen nopen
+setBrush 0x7f000000
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setRadial 20 20 220 200
+
+drawEllipse 10 10 80 80
+drawEllipse 50 50 120 90
+
+translate 100 0
+brushTranslate 40 20
+brushScale 0.25 0.25
+
+setPen black
+
+drawEllipse 10 10 80 80
+setOpacity 0.5
+setCompositionMode SourceIn
+drawEllipse 50 50 120 90
+setOpacity 1.0
+setRenderHint Antialiasing
+setCompositionMode Xor
+brushTranslate 70 0
+translate 100 0
+drawEllipse 10 10 80 80
+
+setPen nopen
+drawEllipse 50 50 120 90
+
+setOpacity 0.7
+setBrush red
+translate 100 0
+setCompositionMode SourceOver
+
+drawEllipse 10 10 80 80
+
+setOpacity 0.6
+setPen black 5.0
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setLinear 20 20 120 100
+drawEllipse 50 50 120 90
+
+
+translate 100 0
+
+setOpacity 1.0
+drawEllipse 10 10 80 80
+
+setCompositionMode SourceIn
+setOpacity 0.7
+setPen black 3.0
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setLinear 50 50 80 90
+drawEllipse 50 50 120 90
+
+surface_end
+
+drawText 200 220 "Testing Ellipse drawing with varios combinations"
+drawText 200 240 "of features such as brushes, pens and composition modes" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/fillrect.qps b/tests/baseline/painting/scripts/fillrect.qps
new file mode 100644
index 0000000000..103ef2646a
--- /dev/null
+++ b/tests/baseline/painting/scripts/fillrect.qps
@@ -0,0 +1,121 @@
+setRenderHint Antialiasing false
+
+# offscreen
+translate 0 -200
+
+begin_block rects
+# int API
+fillRect 10 10 20 20 green
+fillRect 40 10 20 20
+drawRect 70 10 20 20
+
+# float API, int values
+fillRectF 10.0 40.0 20.0 20.0 green
+fillRectF 40.0 40.0 20.0 20.0
+drawRect 70.0 40.0 20.0 20.0
+
+# float API, float values
+fillRectF 10.0 70.0 20.5 20.5 green
+fillRectF 40.0 70.0 20.5 20.5
+drawRect 70.0 70.0 20.5 20.5
+
+# alignment, int api, color
+fillRect 10 100 10 10 green
+fillRect 20 100 10 10 green
+fillRect 10 110 10 10 green
+fillRect 20 110 10 10 green
+
+# alignment, int api, brush
+fillRect 40 100 10 10
+fillRect 50 100 10 10
+fillRect 40 110 10 10
+fillRect 50 110 10 10
+
+# alignment comparison
+drawRect 70 100 10 10
+drawRect 80 100 10 10
+drawRect 70 110 10 10
+drawRect 80 110 10 10
+
+# alignment, float api, color
+fillRectF 10.0 130.0 10.0 10.0 green
+fillRectF 20.0 130.0 10.0 10.0 green
+fillRectF 10.0 140.0 10.0 10.0 green
+fillRectF 20.0 140.0 10.0 10.0 green
+
+# alignment, float api, brush
+fillRectF 40.0 130.0 10.0 10.0
+fillRectF 50.0 130.0 10.0 10.0
+fillRectF 40.0 140.0 10.0 10.0
+fillRectF 50.0 140.0 10.0 10.0
+
+# alignment comparison
+drawRect 70.0 130.0 10.0 10.0
+drawRect 80.0 130.0 10.0 10.0
+drawRect 70.0 140.0 10.0 10.0
+drawRect 80.0 140.0 10.0 10.0
+
+end_block
+
+begin_block row
+
+repeat_block rects
+
+save
+translate 100.2 0.2
+repeat_block rects
+restore
+
+save
+translate 200.5 0.5
+repeat_block rects
+restore
+
+save
+translate 300.7 0.7
+repeat_block rects
+restore
+
+end_block
+
+# end of block defs
+
+resetMatrix
+
+setPen NoPen
+setBrush green
+repeat_block row
+
+save
+translate 500 50
+scale 0.42 0.42
+repeat_block row
+restore
+
+save
+translate 0 160
+scale 1.8 0.8
+repeat_block row
+restore
+
+save
+translate 650 320
+rotate 80
+repeat_block row
+restore
+
+save
+setBrush green Dense2Pattern
+translate 0 400
+repeat_block row
+restore
+
+save
+gradient_clearStops
+gradient_appendStop 0 green
+gradient_appendStop 1 blue
+gradient_setCoordinateMode ObjectBoundingMode
+gradient_setLinear 0.0 0.0 1.0 1.0
+translate 0 600
+repeat_block row
+restore
diff --git a/tests/baseline/painting/scripts/fillrect_aa.qps b/tests/baseline/painting/scripts/fillrect_aa.qps
new file mode 100644
index 0000000000..3232899661
--- /dev/null
+++ b/tests/baseline/painting/scripts/fillrect_aa.qps
@@ -0,0 +1,121 @@
+setRenderHint Antialiasing true
+
+# offscreen
+translate 0 -200
+
+begin_block rects
+# int API
+fillRect 10 10 20 20 green
+fillRect 40 10 20 20
+drawRect 70 10 20 20
+
+# float API, int values
+fillRectF 10.0 40.0 20.0 20.0 green
+fillRectF 40.0 40.0 20.0 20.0
+drawRect 70.0 40.0 20.0 20.0
+
+# float API, float values
+fillRectF 10.0 70.0 20.5 20.5 green
+fillRectF 40.0 70.0 20.5 20.5
+drawRect 70.0 70.0 20.5 20.5
+
+# alignment, int api, color
+fillRect 10 100 10 10 green
+fillRect 20 100 10 10 green
+fillRect 10 110 10 10 green
+fillRect 20 110 10 10 green
+
+# alignment, int api, brush
+fillRect 40 100 10 10
+fillRect 50 100 10 10
+fillRect 40 110 10 10
+fillRect 50 110 10 10
+
+# alignment comparison
+drawRect 70 100 10 10
+drawRect 80 100 10 10
+drawRect 70 110 10 10
+drawRect 80 110 10 10
+
+# alignment, float api, color
+fillRectF 10.0 130.0 10.0 10.0 green
+fillRectF 20.0 130.0 10.0 10.0 green
+fillRectF 10.0 140.0 10.0 10.0 green
+fillRectF 20.0 140.0 10.0 10.0 green
+
+# alignment, float api, brush
+fillRectF 40.0 130.0 10.0 10.0
+fillRectF 50.0 130.0 10.0 10.0
+fillRectF 40.0 140.0 10.0 10.0
+fillRectF 50.0 140.0 10.0 10.0
+
+# alignment comparison
+drawRect 70.0 130.0 10.0 10.0
+drawRect 80.0 130.0 10.0 10.0
+drawRect 70.0 140.0 10.0 10.0
+drawRect 80.0 140.0 10.0 10.0
+
+end_block
+
+begin_block row
+
+repeat_block rects
+
+save
+translate 100.2 0.2
+repeat_block rects
+restore
+
+save
+translate 200.5 0.5
+repeat_block rects
+restore
+
+save
+translate 300.7 0.7
+repeat_block rects
+restore
+
+end_block
+
+# end of block defs
+
+resetMatrix
+
+setPen NoPen
+setBrush green
+repeat_block row
+
+save
+translate 500 50
+scale 0.42 0.42
+repeat_block row
+restore
+
+save
+translate 0 160
+scale 1.8 0.8
+repeat_block row
+restore
+
+save
+translate 650 320
+rotate 80
+repeat_block row
+restore
+
+save
+setBrush green Dense2Pattern
+translate 0 400
+repeat_block row
+restore
+
+save
+gradient_clearStops
+gradient_appendStop 0 green
+gradient_appendStop 1 blue
+gradient_setCoordinateMode ObjectBoundingMode
+gradient_setLinear 0.0 0.0 1.0 1.0
+translate 0 600
+repeat_block row
+restore
diff --git a/tests/baseline/painting/scripts/filltest.qps b/tests/baseline/painting/scripts/filltest.qps
new file mode 100644
index 0000000000..112ffc85be
--- /dev/null
+++ b/tests/baseline/painting/scripts/filltest.qps
@@ -0,0 +1,413 @@
+# Version: 1
+# CheckVsReference: 5%
+
+setPen nopen
+setBrush red
+translate 0 4
+begin_block polys
+drawPolygon [0 0 2 -2 4 0]
+drawPolygon [0 2 2 4 4 2]
+end_block polys
+translate 6 .5
+repeat_block polys
+translate 6.5 0
+repeat_block polys
+translate 6 .5
+repeat_block polys
+
+resetMatrix
+
+translate 0 12
+setPen black
+drawPolygon [0 0 5 0 5 5 0 5]
+
+translate 10 0
+setPen nopen
+drawPolygon [0 0 5 0 5 5 0 5]
+
+translate 10 0
+drawPolygon [0 0 5 0 5 5 0 5]
+
+setBrush black
+path_addRect stroke -.5 -.5 6 6
+path_addRect stroke .5 .5 4 4
+drawPath stroke
+
+resetMatrix
+
+translate 0 65
+
+setPen red
+drawText 0 0 "path"
+drawText 40 0 "rect"
+drawText 80 0 "img"
+drawText 120 0 "pix"
+drawText 160 0 "brush"
+setPen nopen
+
+translate 0 5
+
+image_load border.png img
+pixmap_load border.png pix
+
+path_addRect rect 0 0 10 10
+begin_block rects
+drawPath rect
+drawRect 40 0 10 10
+drawImage img 80 0
+drawPixmap pix 120 0
+setBrush border.png
+drawRect 160 0 10 10
+setBrush black
+end_block rects
+
+setPen red
+drawText 180 10 "0.0"
+setPen nopen
+
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.1"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.2"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.3"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.4"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.5"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.6"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.7"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.8"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "0.9"
+setPen nopen
+translate 0.1 20
+repeat_block rects
+setPen red
+drawText 180 10 "1.0"
+setPen nopen
+
+resetMatrix
+
+translate 0 400
+
+setPen red
+drawText 0 10 "path"
+drawText 0 30 "rect"
+drawText 0 50 "img"
+drawText 0 70 "pix"
+drawText 0 90 "brush"
+drawText 0 110 "stroke"
+drawText 0 130 "scale"
+drawText 0 170 "rotate"
+setPen nopen
+
+translate 50 0
+
+begin_block rects2
+drawPath rect
+drawRect 0 20 10 10
+drawImage img 0 40
+drawPixmap pix 0 60
+save
+setBrush border.png
+drawRect 0 80 10 10
+translate 0 100
+setBrush red
+setPen black
+drawRect 0 0 10 10
+setBrush border.png
+setPen nopen
+translate 0 20
+scale 2 2
+drawRect 0 0 10 10
+translate 10 20
+rotate 90
+drawRect 0 0 10 10
+restore
+end_block rects2
+
+setPen red
+drawText -5 -10 "0.0"
+setPen nopen
+
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.1"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.2"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.3"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.4"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.5"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.6"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.7"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.8"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "0.9"
+setPen nopen
+translate 40 0.1
+repeat_block rects2
+setPen red
+drawText -5 -10 "1.0"
+setPen nopen
+
+resetMatrix
+
+translate 0 620
+
+setPen red
+drawText 0 10 "path"
+setPen nopen
+
+path_addRect rect2 -5 -5 10 10
+
+translate 55 5
+drawPath rect2
+
+translate 20 0
+rotate 10
+drawPath rect2
+rotate -10
+translate 20 0
+rotate 20
+drawPath rect2
+rotate -20
+translate 20 0
+rotate 30
+drawPath rect2
+rotate -30
+translate 20 0
+rotate 40
+drawPath rect2
+rotate -40
+translate 20 0
+rotate 50
+drawPath rect2
+rotate -50
+translate 20 0
+rotate 60
+drawPath rect2
+rotate -60
+translate 20 0
+rotate 70
+drawPath rect2
+rotate -70
+translate 20 0
+rotate 80
+drawPath rect2
+rotate -80
+translate 20 0
+rotate 90
+drawPath rect2
+rotate -90
+
+resetMatrix
+
+translate 0 600
+
+setPen red
+drawText 0 10 "rect"
+setPen nopen
+
+translate 55 5
+drawRect -5 -5 10 10
+
+translate 20 0
+rotate 10
+drawRect -5 -5 10 10
+rotate -10
+translate 20 0
+rotate 20
+drawRect -5 -5 10 10
+rotate -20
+translate 20 0
+rotate 30
+drawRect -5 -5 10 10
+rotate -30
+translate 20 0
+rotate 40
+drawRect -5 -5 10 10
+rotate -40
+translate 20 0
+rotate 50
+drawRect -5 -5 10 10
+rotate -50
+translate 20 0
+rotate 60
+drawRect -5 -5 10 10
+rotate -60
+translate 20 0
+rotate 70
+drawRect -5 -5 10 10
+rotate -70
+translate 20 0
+rotate 80
+drawRect -5 -5 10 10
+rotate -80
+translate 20 0
+rotate 90
+drawRect -5 -5 10 10
+rotate -90
+
+resetMatrix
+path_addRect vertical 0.1 0.1 0.2 10
+
+translate 0 320
+drawPath vertical
+translate 2.2 0
+drawPath vertical
+translate 2.2 0
+drawPath vertical
+translate 2.2 0
+drawPath vertical
+translate 2.2 0
+drawPath vertical
+
+resetMatrix
+path_addRect horizontal 0.1 0.1 10 0.2
+
+translate 0 340
+drawPath horizontal
+translate 0 2.2
+drawPath horizontal
+translate 0 2.2
+drawPath horizontal
+translate 0 2.2
+drawPath horizontal
+translate 0 2.2
+drawPath horizontal
+
+setOpacity 0.8
+resetMatrix
+
+translate 0.1 24.7
+translate 400 0
+#rotate 88.8
+rotate 89.9
+setBrush red
+drawPolygon [0 0 300 0 0 173]
+setBrush green
+drawPolygon [0 173 300 0 300 173]
+
+resetMatrix
+
+translate 410 24
+path_lineTo left 0 273
+path_lineTo left 300 273
+path_cubicTo left 50 273 250 0 0 0
+
+path_cubicTo right 250 0 50 273 300 273
+path_lineTo right 300 0
+
+translate 310 0
+rotate 90
+setBrush red
+drawPath left
+setBrush green
+drawPath right
+
+resetMatrix
+translate 0.1 680.1
+setPen red
+setOpacity 1
+drawText 115 -20 "0.1"
+drawText 0 0 "pixmap w/ opacity"
+setOpacity 0.6
+drawPixmap pix 120 -10
+translate 0 20
+setOpacity 1
+drawText 0 0 "image w/ opacity"
+setOpacity 0.6
+drawImage img 120 -10
+
+resetMatrix
+path_lineTo fillpath 0 50
+path_lineTo fillpath 50 50
+path_moveTo fillpath 70 50
+path_lineTo fillpath 70 100
+path_lineTo fillpath 40 100
+translate 500 400
+drawPath fillpath
+
+resetMatrix
+path_moveTo vectorarne 50 10
+path_lineTo vectorarne 50 50
+path_lineTo vectorarne 100 50
+path_addEllipse vectorarne 350 20 230 230
+path_moveTo vectorarne 500 500
+path_cubicTo vectorarne 20 20 250 30 50 150
+translate 500 550
+scale 0.4 0.4
+setRenderHint antialiasing
+drawPath vectorarne
+
+resetMatrix
+translate 200 730
+setRenderHint antialiasing off
+setOpacity 1
+setPen red
+drawText 0 0 "outline/fill consistency"
+setPen red
+setBrush green
+translate 80 -30
+drawPolygon [13.6965 -99.1837 -71.4767 13.823 32.4596 -33.1847]
diff --git a/tests/baseline/painting/scripts/glyphruns.qps b/tests/baseline/painting/scripts/glyphruns.qps
new file mode 100644
index 0000000000..2b70c72610
--- /dev/null
+++ b/tests/baseline/painting/scripts/glyphruns.qps
@@ -0,0 +1,175 @@
+drawGlyphRun -5 5 "Text that is drawn outside the bounds..."
+
+translate 20 20
+begin_block text_drawing
+save
+ setFont "sansserif" 10 normal
+ drawGlyphRun 0 20 "sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawGlyphRun 0 40 "sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawGlyphRun 0 60 "sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawGlyphRun 0 80 "sansserif 10pt, bold italic"
+
+
+ translate 0 100
+ setPen #7fff0000
+
+ setFont "sansserif" 10 normal
+ drawGlyphRun 0 20 "alpha sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawGlyphRun 0 40 "alpha sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawGlyphRun 0 60 "alpha sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawGlyphRun 0 80 "alpha sansserif 10pt, bold italic"
+
+
+ translate 0 100
+ setPen black
+ save
+ scale 0.9 0.9
+
+ setFont "sansserif" 10 normal
+ drawGlyphRun 0 20 "scaled sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawGlyphRun 0 40 "scaled sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawGlyphRun 0 60 "scaled sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawGlyphRun 0 80 "scaled sansserif 10pt, bold italic"
+ restore
+
+ translate 200 200
+ setPen black
+ save
+ scale -1 -1
+
+ setFont "sansserif" 10 normal
+ drawGlyphRun 0 20 "flipped sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawGlyphRun 0 40 "flipped sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawGlyphRun 0 60 "flipped sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawGlyphRun 0 80 "flipped sansserif 10pt, bold italic"
+ restore
+
+ translate -200 20
+ setPen black
+ save
+ translate 200 90
+ rotate 185
+
+ setFont "sansserif" 10 normal
+ drawGlyphRun 0 20 "rotated sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawGlyphRun 0 40 "rotated sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawGlyphRun 0 60 "rotated sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawGlyphRun 0 80 "rotated sansserif 10pt, bold italic"
+ restore
+
+ translate 0 100
+ gradient_appendStop 0 red
+ gradient_appendStop 0.5 #00ff00
+ gradient_appendStop 1 blue
+ gradient_setLinear 0 0 200 0
+ setPen brush
+
+ setFont "sansserif" 10 normal
+ drawGlyphRun 0 0 "gradient sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawGlyphRun 0 20 "gradient sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawGlyphRun 0 40 "gradient sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawGlyphRun 0 60 "gradient sansserif 10pt, bold italic"
+restore
+end_block
+
+translate 250 0
+drawGlyphRun 25 640 "clipped to rectangle"
+save
+ setPen #3f000000
+ setBrush nobrush
+ drawRect 20 0 100 620
+ setClipRect 20 0 100 620
+ setPen black
+ repeat_block text_drawing
+restore
+
+translate 150 0
+drawGlyphRun 25 640 "clipped to path"
+save
+ path_moveTo clip 20 0
+ path_cubicTo clip 0 200 40 400 20 400
+ path_lineTo clip 30 620
+ path_lineTo clip 30 0
+ path_lineTo clip 40 0
+ path_lineTo clip 40 620
+ path_lineTo clip 120 620
+ path_lineTo clip 120 0
+ path_lineTo clip 20 0
+ setPen #3f000000
+ setBrush nobrush
+ drawPath clip
+ setClipPath clip
+ setPen black
+ repeat_block text_drawing
+restore
+
+translate 150 0
+save
+ setPen black
+ setFont "sansserif" 16 normal
+ drawGlyphRun 0 40 "e😃m😇o😍j😜i😸!"
+restore
+
+translate 0 55
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default underline
+ drawGlyphRun 0 20 "Underlined text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default normal strikeout
+ drawGlyphRun 0 20 "Struck out text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default normal normal overline
+ drawGlyphRun 0 20 "Overlined text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default underline strikeout overline
+ drawGlyphRun 0 20 "All the effects text drawing"
+restore
diff --git a/tests/baseline/painting/scripts/gradients.qps b/tests/baseline/painting/scripts/gradients.qps
new file mode 100644
index 0000000000..eb3cda9cad
--- /dev/null
+++ b/tests/baseline/painting/scripts/gradients.qps
@@ -0,0 +1,44 @@
+# Version: 1
+# CheckVsReference: 5%
+
+drawText 75 20 "Linear"
+drawText 176 20 "Radial"
+drawText 277 20 "Conical"
+translate 0 30
+drawText 0 50 "AA off"
+drawText 0 151 "AA on"
+
+setPen nopen
+
+gradient_clearStops
+gradient_appendStop 0 0x00000000
+gradient_appendStop 0.001 red
+gradient_appendStop 0.2 blue
+gradient_appendStop 0.4 yellow
+gradient_appendStop 0.6 cyan
+gradient_appendStop 0.8 green
+gradient_appendStop 0.999 red
+gradient_appendStop 1 0x00000000
+
+gradient_setSpread PadSpread
+gradient_setCoordinateMode ObjectBoundingMode
+
+begin_block row
+save
+gradient_setLinear 0.1 0.0 0.9 0.0
+drawRect 50 0 100 100
+
+gradient_setRadial 0.5 0.5 0.5 0.5 0.5
+translate 101 0
+drawRect 50 0 100 100
+
+gradient_setConical 0.5 0.5 45
+translate 101 0
+drawRect 50 0 100 100
+restore
+end_block row
+
+setRenderHint Antialiasing
+
+translate 0 101
+repeat_block row \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/gradientxform_device.qps b/tests/baseline/painting/scripts/gradientxform_device.qps
new file mode 100644
index 0000000000..cd8b55d5b6
--- /dev/null
+++ b/tests/baseline/painting/scripts/gradientxform_device.qps
@@ -0,0 +1,67 @@
+# Version: 1
+# CheckVsReference: 5%
+
+gradient_clearStops
+gradient_appendStop 0 black
+gradient_appendStop 0.4 yellow
+gradient_appendStop 1 gray
+
+gradient_setSpread PadSpread
+
+gradient_setCoordinateMode StretchToDeviceMode
+
+# first run is dummy, make it offscreen
+save
+translate -500 -500
+
+begin_block row
+save
+
+setPen nopen
+drawRect 50 0 100 100
+
+setPen brush 30
+setBrush lightblue
+drawRect 175 15 70 70
+
+setFont "times" 110 1000
+drawText 270 100 "X"
+
+restore
+end_block row
+
+restore
+
+drawText 160 20 "PLAIN"
+drawText 560 20 "BRUSH XFORM"
+translate 0 20
+
+begin_block block
+save
+
+drawText 75 20 "Brush Fill"
+drawText 176 20 "Pen Stroke"
+drawText 277 20 "Text Stroke"
+translate 0 30
+drawText 0 50 "Linear"
+drawText 0 160 "Radial"
+drawText 0 270 "Conical"
+
+gradient_setLinear 0.0 0.0 0.4 0.0
+repeat_block row
+
+translate 0 110
+gradient_setRadial 0.04 0.08 0.3 0.3 0.05
+repeat_block row
+
+translate 0 110
+gradient_setConical 0.25 0.1 45
+repeat_block row
+restore
+end_block block
+
+translate 400 0
+brushRotate 30.0
+brushScale 1.5 .5
+brushTranslate 0 -80
+repeat_block block
diff --git a/tests/baseline/painting/scripts/gradientxform_logical.qps b/tests/baseline/painting/scripts/gradientxform_logical.qps
new file mode 100644
index 0000000000..1bba63a929
--- /dev/null
+++ b/tests/baseline/painting/scripts/gradientxform_logical.qps
@@ -0,0 +1,67 @@
+# Version: 1
+# CheckVsReference: 5%
+
+gradient_clearStops
+gradient_appendStop 0 black
+gradient_appendStop 0.4 yellow
+gradient_appendStop 1 gray
+
+gradient_setSpread PadSpread
+
+gradient_setCoordinateMode LogicalMode
+
+# first run is dummy, make it offscreen
+save
+translate -500 -500
+
+begin_block row
+save
+
+setPen nopen
+drawRect 50 0 100 100
+
+setPen brush 30
+setBrush lightblue
+drawRect 175 15 70 70
+
+setFont "times" 110 1000
+drawText 270 100 "X"
+
+restore
+end_block row
+
+restore
+
+drawText 160 20 "PLAIN"
+drawText 560 20 "BRUSH XFORM"
+translate 0 20
+
+begin_block block
+save
+
+drawText 75 20 "Brush Fill"
+drawText 176 20 "Pen Stroke"
+drawText 277 20 "Text Stroke"
+translate 0 30
+drawText 0 50 "Linear"
+drawText 0 160 "Radial"
+drawText 0 270 "Conical"
+
+gradient_setLinear 0 0 400 0
+repeat_block row
+
+translate 0 110
+gradient_setRadial 200 50 140 70 20
+repeat_block row
+
+translate 0 110
+gradient_setConical 220 60 45
+repeat_block row
+restore
+end_block block
+
+translate 400 0
+brushRotate 30.0
+brushScale 1.5 .5
+brushTranslate 0 -80
+repeat_block block
diff --git a/tests/baseline/painting/scripts/gradientxform_object.qps b/tests/baseline/painting/scripts/gradientxform_object.qps
new file mode 100644
index 0000000000..e34da24d46
--- /dev/null
+++ b/tests/baseline/painting/scripts/gradientxform_object.qps
@@ -0,0 +1,83 @@
+# Version: 1
+# CheckVsReference: 5%
+
+gradient_clearStops
+gradient_appendStop 0 black
+gradient_appendStop 0.4 yellow
+gradient_appendStop 1 gray
+
+gradient_setSpread PadSpread
+
+gradient_setCoordinateMode ObjectBoundingMode
+
+# first run is dummy, make it offscreen
+save
+translate -500 -500
+
+begin_block row
+save
+
+setPen nopen
+drawRect 50 0 100 100
+
+setPen brush 30
+setBrush lightblue
+translate 110 0
+drawRect 65 15 70 70
+
+translate 110 0
+setFont "times" 110 1000
+drawText 50 100 "X"
+
+restore
+end_block row
+
+restore
+
+drawText 160 20 "PLAIN"
+drawText 560 20 "BRUSH XFORM"
+translate 0 20
+
+begin_block block
+save
+
+drawText 75 20 "Brush Fill"
+drawText 176 20 "Pen Stroke"
+drawText 277 20 "Text Stroke"
+translate 0 30
+drawText 0 50 "Linear"
+drawText 0 160 "Radial"
+drawText 0 270 "Conical"
+
+gradient_setLinear 0.1 0.0 0.5 0.0
+repeat_block row
+
+translate 0 110
+gradient_setRadial 0.3 0.2 0.5 0.4 0.5
+repeat_block row
+
+translate 0 110
+gradient_setConical 0.5 0.7 45
+repeat_block row
+restore
+end_block block
+
+save
+translate 400 0
+brushRotate 30.0
+brushScale 1.5 .5
+repeat_block block
+restore
+
+drawText 80 400 "BRUSH XFORM, OBJECT BOUNDING MODE"
+drawText 500 400 "BRUSH XFORM, OBJECT MODE"
+
+translate 0 400
+brushTranslate 0.5 0.5
+brushRotate 180.0
+brushTranslate -0.5 -0.5
+repeat_block block
+
+translate 400 0
+gradient_setCoordinateMode ObjectMode
+repeat_block block
diff --git a/tests/baseline/painting/scripts/hinting.qps b/tests/baseline/painting/scripts/hinting.qps
new file mode 100644
index 0000000000..7ce21b287a
--- /dev/null
+++ b/tests/baseline/painting/scripts/hinting.qps
@@ -0,0 +1,26 @@
+translate 10 50
+setFont "sansserif" 10
+drawText 0 0 "Default hinting:"
+setFont "times" 12 normal normal default
+drawText 0 20 "The quick brown fox jumps over the lazy dog"
+
+translate 0 50
+setFont "sansserif" 10
+drawText 0 0 "No hinting:"
+setFont "times" 12 normal normal none
+drawText 0 20 "The quick brown fox jumps over the lazy dog"
+
+translate 0 50
+setFont "sansserif" 10
+drawText 0 0 "Vertical hinting:"
+setFont "times" 12 normal normal vertical
+drawText 0 20 "The quick brown fox jumps over the lazy dog"
+
+translate 0 50
+setFont "sansserif" 10
+drawText 0 0 "Full hinting:"
+setFont "times" 12 normal normal full
+drawText 0 20 "The quick brown fox jumps over the lazy dog"
+
+
+# Note: there is also the textlayout_draw command which might be interesting here.
diff --git a/tests/baseline/painting/scripts/image_dpr.qps b/tests/baseline/painting/scripts/image_dpr.qps
new file mode 100644
index 0000000000..7d3ca3099c
--- /dev/null
+++ b/tests/baseline/painting/scripts/image_dpr.qps
@@ -0,0 +1,43 @@
+
+setRenderHint Antialiasing true
+setRenderHint SmoothPixmapTransform true
+
+image_load sign.png img1
+pixmap_load sign.png pix1
+
+begin_block drawIt
+save
+
+drawImage img1 20 20 -1 -1
+drawRect 17.5 17.5 85 85
+
+setBrush img1
+setPen NoPen
+drawRect 20 120 120 120
+
+brushRotate 45
+drawRect 20 260 120 120
+
+setBrush NoBrush
+drawTiledPixmap pix1 20 400 120 120
+
+restore
+end_block
+
+save
+translate 150 0
+rotate -5
+repeat_block drawIt
+restore
+
+image_setDevicePixelRatio img1 2.0
+pixmap_setDevicePixelRatio pix1 2.0
+translate 400 0
+repeat_block drawIt
+
+save
+translate 150 0
+rotate -5
+repeat_block drawIt
+restore
+
diff --git a/tests/baseline/painting/scripts/image_formats.qps b/tests/baseline/painting/scripts/image_formats.qps
new file mode 100644
index 0000000000..d817d04bf8
--- /dev/null
+++ b/tests/baseline/painting/scripts/image_formats.qps
@@ -0,0 +1,81 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+image_load dome_argb32.png the_pixmap
+image_convertToFormat the_pixmap the_pixmap ARGB32_Premultiplied
+
+begin_block draw_stuff
+ save
+ image_convertToFormat the_pixmap converted ARGB32_Premultiplied
+ drawImage converted 0 0
+ translate 0 110
+
+ image_convertToFormat the_pixmap converted ARGB32
+ drawImage converted 0 0
+ translate 0 110
+
+ image_convertToFormat the_pixmap converted RGB32
+ drawImage converted 0 0
+ translate 0 110
+
+ image_convertToFormat the_pixmap converted Indexed8
+ drawImage converted 0 0
+ translate 0 110
+
+ image_convertToFormat the_pixmap converted MonoLSB
+ drawImage converted 0 0
+ translate 0 110
+
+ image_convertToFormat the_pixmap converted Mono
+ drawImage converted 0 0
+ translate 0 110
+ restore
+end_block
+
+
+image_load dome_argb32.png the_pixmap
+translate 110 0
+repeat_block draw_stuff
+
+
+image_load dome_rgb32.png the_pixmap
+translate 110 0
+repeat_block draw_stuff
+
+image_load dome_indexed.png the_pixmap
+translate 110 0
+repeat_block draw_stuff
+
+
+image_load dome_mono.png the_pixmap
+translate 110 0
+repeat_block draw_stuff
+
+image_load dome_mono_palette.png the_pixmap
+translate 110 0
+repeat_block draw_stuff
+
+image_load dome_indexed_mask.png the_pixmap
+translate 110 0
+repeat_block draw_stuff
+
+
+# helpful texts
+resetMatrix
+setPen black
+
+drawText 10 670 "ARGB32_PM"
+drawText 120 670 "ARGB32"
+drawText 230 670 "RGB32"
+drawText 340 670 "Indexed"
+drawText 450 670 "Mono"
+drawText 560 670 "Mono w/lut"
+drawText 670 670 "Indexed w/mask"
+
+drawText 770 50 "ARGB32_PM"
+drawText 770 160 "ARGB32"
+drawText 770 270 "RGB32"
+drawText 770 380 "Indexed"
+drawText 770 490 "MonoLSB"
+drawText 770 600 "Mono" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/images.qps b/tests/baseline/painting/scripts/images.qps
new file mode 100644
index 0000000000..3f892400e2
--- /dev/null
+++ b/tests/baseline/painting/scripts/images.qps
@@ -0,0 +1,106 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+setRenderHint Antialiasing
+
+setPen #00ff00
+
+image_load dome_argb32.png the_image
+begin_block draw_stuff
+
+save
+
+ # standard draw
+ drawImage the_image 0 0
+
+ # sub recting
+ translate 120 0
+ drawImage the_image 0 0 40 40 0 0 40 40
+ drawImage the_image 60 0 40 40 60 0 40 40
+ drawImage the_image 0 60 40 40 0 60 40 40
+ drawImage the_image 60 60 40 40 60 60 40 40
+ drawImage the_image 0 40 40 20 0 40 40 20
+ drawImage the_image 60 40 40 20 60 40 40 20
+ drawImage the_image 40 0 20 100 40 0 20 100
+
+ # subrecting w/scale
+ translate 120 0
+ drawImage the_image 0 0 50 50 0 0 25 25
+ drawImage the_image 50 0 50 50 25 0 25 25
+ drawImage the_image 0 50 50 50 0 25 25 25
+ drawImage the_image 50 50 50 50 25 25 25 25
+
+ # subrecting w/scale & smooth xform
+ translate 120 0
+ setRenderHint SmoothPixmapTransformation
+ drawImage the_image 0 0 50 50 0 0 25 25
+ drawImage the_image 50 0 50 50 25 0 25 25
+ drawImage the_image 0 50 50 50 0 25 25 25
+ drawImage the_image 50 50 50 50 25 25 25 25
+
+
+ # Rotation w/o smooth xform
+ translate 120 0
+ save
+ setRenderHint SmoothPixmapTransform off
+ rotate 10
+ drawImage the_image 0 0
+ restore
+
+ # Rotation w smooth xform
+ translate 120 0
+ save
+ setRenderHint SmoothPixmapTransform
+ rotate 10
+ drawImage the_image 0 0
+ restore
+
+restore
+
+end_block
+
+
+translate 0 120
+image_load dome_rgb32.png the_image
+repeat_block draw_stuff
+
+translate 0 120
+image_load dome_indexed.png the_image
+repeat_block draw_stuff
+
+translate 0 120
+image_load dome_indexed_mask.png the_image
+repeat_block draw_stuff
+
+translate 0 120
+image_load dome_mono.png the_image
+repeat_block draw_stuff
+
+
+resetMatrix
+translate 700 60
+setPen black
+drawText 0 0 "32 bit w/alpha"
+translate 0 120
+drawText 0 0 "32 bit w/o alpha"
+translate 0 120
+drawText 0 0 "8 bit indexed"
+translate 0 120
+drawText 0 0 "8 bit indexed w/mask"
+translate 0 120
+drawText 0 0 "1 bit"
+resetMatrix
+translate 0 600
+drawText 0 0 "normal"
+translate 120 0
+drawText 0 0 "subrect"
+translate 120 0
+drawText 0 0 "subrect scale"
+translate 120 0
+drawText 0 0 "subrect scale smooth"
+translate 120 0
+drawText 0 0 "xform"
+translate 120 0
+drawText 0 0 "smooth xform"
+translate 120 0 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/images2.qps b/tests/baseline/painting/scripts/images2.qps
new file mode 100644
index 0000000000..5159abc928
--- /dev/null
+++ b/tests/baseline/painting/scripts/images2.qps
@@ -0,0 +1,145 @@
+# Version: 1
+# CheckVsReference: 5%
+
+image_load dome_argb32.png the_image
+begin_block draw_stuff
+
+save
+ # standard draw
+ drawImage the_image 0 0
+
+ # flip x
+ translate 220 0
+ scale -1 1
+ drawImage the_image 0 0
+ scale -1 1
+
+ # flip y
+ translate 20 100
+ scale 1 -1
+ drawImage the_image 0 0
+ scale 1 -1
+
+ # flip x and y
+ translate 220 0
+ scale -1 -1
+ drawImage the_image 0 0
+ scale -1 -1
+
+ # flip y and scale
+ translate 20 10
+ save
+ scale 1 -1.1
+ drawImage the_image 0 0
+ restore
+
+ # flip y and scale
+ translate 220 -110
+ save
+ scale -1.1 0.9
+ drawImage the_image 0 0
+ restore
+restore
+end_block
+
+setRenderHint Antialiasing
+
+resetMatrix
+translate 0 120
+repeat_block draw_stuff
+
+resetMatrix
+translate 720 60
+setPen black
+drawText 0 0 "aliased"
+translate 0 120
+drawText 0 0 "antialiased"
+resetMatrix
+translate 0 260
+drawText 0 0 "normal"
+translate 120 0
+drawText 0 0 "flip x"
+translate 120 0
+drawText 0 0 "flip y"
+translate 120 0
+drawText 0 0 "flip x and y"
+translate 120 0
+drawText 0 0 "flip y and scale"
+translate 120 0
+drawText 0 0 "flip x and scale"
+translate 120 0
+
+setRenderHint SmoothPixmapTransform
+
+resetMatrix
+translate 20 300
+drawImage border.png 0 0 100 100 1 1 8 8
+drawText 0 -5 "subrect color bleeding"
+translate 0 120
+drawImage border.png 0 0 100 100 0 0 10 10
+
+image_load sign.png the_image
+resetMatrix
+drawText 240 300 "drawImage() with varying sx/sy offsets"
+translate 0 10
+drawRect 240 300 50 50
+drawImage the_image 240 300 50 50 20 0 80 80
+drawRect 300 300 50 50
+drawImage the_image 300 300 50 50 -20 0 80 80
+drawRect 240 370 50 50
+drawImage the_image 240 370 50 50 0 20 80 80
+drawRect 300 370 50 50
+drawImage the_image 300 370 50 50 0 -20 80 80
+
+pixmap_load sign.png the_pixmap
+translate 220 0
+translate 0 -10
+drawText 240 300 "drawPixmap() with varying sx/sy offsets"
+translate 0 10
+drawRect 240 300 50 50
+drawPixmap the_pixmap 240 300 50 50 20 0 80 80
+drawRect 300 300 50 50
+drawPixmap the_pixmap 300 300 50 50 -20 0 80 80
+drawRect 240 370 50 50
+drawPixmap the_pixmap 240 370 50 50 0 20 80 80
+drawRect 300 370 50 50
+drawPixmap the_pixmap 300 370 50 50 0 -20 80 80
+
+
+resetMatrix
+translate 0 170
+drawText 240 300 "drawImage() with varying sx/sy offsets"
+translate 0 10
+drawRect 240 300 50 50
+drawImage the_image 240 300 50 50 50 0 50 50
+drawRect 300 300 50 50
+drawImage the_image 300 300 50 50 -20 0 50 50
+drawRect 240 370 50 50
+drawImage the_image 240 370 50 50 0 50 50 50
+drawRect 300 370 50 50
+drawImage the_image 300 370 50 50 0 -20 50 50
+
+resetMatrix
+translate 220 170
+drawText 240 300 "drawPixmap() with varying sx/sy offsets"
+translate 0 10
+drawRect 240 300 50 50
+drawPixmap the_pixmap 240 300 50 50 50 0 50 50
+drawRect 300 300 50 50
+drawPixmap the_pixmap 300 300 50 50 -20 0 50 50
+drawRect 240 370 50 50
+drawPixmap the_pixmap 240 370 50 50 0 50 50 50
+drawRect 300 370 50 50
+drawPixmap the_pixmap 300 370 50 50 0 -20 50 50
+
+resetMatrix
+drawText 10 620 "drawImage/Pixmap() with negative x/y and sx/sy"
+setPen red
+
+translate 20 640
+drawImage the_image -10 -10 -1 -1 -10 -10 0 0
+drawRect 0 0 80 80
+
+translate 100 0
+drawPixmap the_pixmap -10 -10 -1 -1 -10 -10 0 0
+drawRect 0 0 80 80
diff --git a/tests/baseline/painting/scripts/join_cap_styles.qps b/tests/baseline/painting/scripts/join_cap_styles.qps
new file mode 100644
index 0000000000..ed823f53f5
--- /dev/null
+++ b/tests/baseline/painting/scripts/join_cap_styles.qps
@@ -0,0 +1,63 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+setRenderHint Antialiasing
+
+path_moveTo p 20 20
+path_cubicTo p 100 20 100 180 180 100
+path_lineTo p 20 180
+path_lineTo p 180 20
+
+setPen black 20 solidline roundcap roundjoin
+drawPath p
+setPen red
+drawPath p
+
+translate 200 0
+setPen black 20 solidline roundcap miterjoin
+drawPath p
+setPen red
+drawPath p
+
+translate 200 0
+setPen black 20 solidline roundcap beveljoin
+drawPath p
+setPen red
+drawPath p
+
+translate -400 200
+setPen black 20 solidline squarecap roundjoin
+drawPath p
+setPen red
+drawPath p
+
+translate 200 0
+setPen black 20 solidline squarecap miterjoin
+drawPath p
+setPen red
+drawPath p
+
+translate 200 0
+setPen black 20 solidline squarecap beveljoin
+drawPath p
+setPen red
+drawPath p
+
+translate -400 200
+setPen black 20 solidline flatcap roundjoin
+drawPath p
+setPen red
+drawPath p
+
+translate 200 0
+setPen black 20 solidline flatcap miterjoin
+drawPath p
+setPen red
+drawPath p
+
+translate 200 0
+setPen black 20 solidline flatcap beveljoin
+drawPath p
+setPen red
+drawPath p \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/join_cap_styles_duplicate_control_points.qps b/tests/baseline/painting/scripts/join_cap_styles_duplicate_control_points.qps
new file mode 100644
index 0000000000..96405ceae7
--- /dev/null
+++ b/tests/baseline/painting/scripts/join_cap_styles_duplicate_control_points.qps
@@ -0,0 +1,68 @@
+# Version: 1
+# CheckVsReference: 1% (0 0 600 650)
+
+
+setRenderHint Antialiasing
+
+path_moveTo p 40 70
+path_lineTo p 20 70
+path_cubicTo p 20 70 40 20 80 80
+
+path_moveTo p 20 120
+path_cubicTo p 50 60 80 110 80 110
+path_lineTo p 60 110
+
+scale 2 2
+
+setPen black 10 solidline roundcap roundjoin
+drawPath p
+setPen red 0
+drawPath p
+
+translate 100 0
+setPen black 10 solidline roundcap miterjoin
+drawPath p
+setPen red 0
+drawPath p
+
+translate 100 0
+setPen black 10 solidline roundcap beveljoin
+drawPath p
+setPen red 0
+drawPath p
+
+translate -200 100
+setPen black 10 solidline squarecap roundjoin
+drawPath p
+setPen red 0
+drawPath p
+
+translate 100 0
+setPen black 10 solidline squarecap miterjoin
+drawPath p
+setPen red 0
+drawPath p
+
+translate 100 0
+setPen black 10 solidline squarecap beveljoin
+drawPath p
+setPen red 0
+drawPath p
+
+translate -200 100
+setPen black 10 solidline flatcap roundjoin
+drawPath p
+setPen red 0
+drawPath p
+
+translate 100 0
+setPen black 10 solidline flatcap miterjoin
+drawPath p
+setPen red 0
+drawPath p
+
+translate 100 0
+setPen black 10 solidline flatcap beveljoin
+drawPath p
+setPen red 0
+drawPath p \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/linear_gradients.qps b/tests/baseline/painting/scripts/linear_gradients.qps
new file mode 100644
index 0000000000..b1b8dd69e7
--- /dev/null
+++ b/tests/baseline/painting/scripts/linear_gradients.qps
@@ -0,0 +1,144 @@
+# Version: 1
+# CheckVsReference: 2% (0 0 600 750)
+
+path_addRect path 400 0 80 80
+path_addEllipse path 440 40 60 60
+
+setRenderHint Antialiasing
+
+setPen black
+
+begin_block gradients
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setLinear 20 20 70 70
+drawRect 0 0 100 100
+
+gradient_setSpread ReflectSpread
+gradient_setLinear 120 20 170 70
+drawEllipse 100 0 100 100
+
+gradient_setSpread RepeatSpread
+gradient_setLinear 220 20 270 70
+drawRoundRect 200 0 100 100
+
+gradient_clearStops
+gradient_appendStop 0 3f7f7fff
+gradient_appendStop 0.5 dfdfffff
+gradient_appendStop 1 7f00007f
+
+gradient_setSpread PadSpread
+gradient_setLinear 320 20 340 40
+drawPolygon [300 0 390 0 350 99]
+
+gradient_setSpread ReflectSpread
+gradient_setLinear 420 20 440 40
+drawPath path
+
+gradient_setSpread RepeatSpread
+gradient_setLinear 520 20 540 40
+drawPie 500 0 100 100 720 4320
+end_block
+
+translate 0 100
+scale 1 2
+repeat_block gradients
+
+resetMatrix
+translate 0 300
+brushTranslate 30 0
+brushScale 0.9 0.9
+brushRotate 20
+repeat_block gradients
+
+# Vertical gradient tests
+resetMatrix
+setBrush noBrush
+translate 0 400
+
+begin_block vertical_gradients
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setLinear 20 20 20 70
+drawRect 0 0 100 100
+
+gradient_setSpread ReflectSpread
+gradient_setLinear 120 20 120 70
+drawEllipse 100 0 100 100
+
+gradient_setSpread RepeatSpread
+gradient_setLinear 220 20 220 70
+drawRoundRect 200 0 100 100
+
+gradient_clearStops
+gradient_appendStop 0 3f7f7fff
+gradient_appendStop 0.5 dfdfffff
+gradient_appendStop 1 7f00007f
+
+gradient_setSpread PadSpread
+gradient_setLinear 320 20 320 40
+drawPolygon [300 0 390 0 350 99]
+
+gradient_setSpread ReflectSpread
+gradient_setLinear 420 20 420 40
+drawPath path
+
+gradient_setSpread RepeatSpread
+gradient_setLinear 520 20 520 40
+drawPie 500 0 100 100 720 4320
+end_block
+
+translate 0 100
+scale 1 1.5
+repeat_block vertical_gradients
+
+resetMatrix
+translate 0 650
+brushTranslate 30 0
+brushScale 0.9 0.9
+brushRotate 20
+repeat_block vertical_gradients
+
+# Some helpful info perhaps?
+resetMatrix
+setPen black
+# gradient line indicators
+drawLine 20 20 70 70
+drawLine 120 20 170 70
+drawLine 220 20 270 70
+drawLine 320 20 340 40
+drawLine 420 20 440 40
+drawLine 520 20 540 40
+
+drawLine 20 140 70 240
+drawLine 120 140 170 240
+drawLine 220 140 270 240
+drawLine 320 140 340 180
+drawLine 420 140 440 180
+drawLine 520 140 540 180
+
+drawText 610 50 "No XForm"
+drawText 610 200 "scale 1x2"
+drawText 610 350 "brush transform"
+drawText 610 450 "vertical brush"
+drawText 610 570 "vertical brush scale 1x1.5"
+drawText 610 700 "vertical brush transform"
+
+drawText 10 780 "Pad"
+drawText 110 780 "Reflect"
+drawText 210 780 "Repeat"
+drawText 310 780 "Pad w/alpha"
+drawText 410 780 "Reflect w/alpha"
+drawText 510 780 "Repeat w/alpha" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/linear_gradients_perspectives.qps b/tests/baseline/painting/scripts/linear_gradients_perspectives.qps
new file mode 100644
index 0000000000..3ea39fbe46
--- /dev/null
+++ b/tests/baseline/painting/scripts/linear_gradients_perspectives.qps
@@ -0,0 +1,62 @@
+# Version: 1
+
+
+setRenderHint Antialiasing
+
+setPen #00ff00
+
+translate 10 10
+# standard draw
+begin_block gradient
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setLinear 10 10 290 290
+drawRect 0 0 300 300
+end_block gradient
+
+# Rotation w/o smooth xform
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 50 0 200 300 300 300 0
+ repeat_block gradient
+restore
+restore
+
+translate 0 320
+
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 100 300 200 300 300 0
+ repeat_block gradient
+restore
+
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 0 300 300 250 300 50
+ repeat_block gradient
+restore
+restore
+
+
+resetMatrix
+setPen black
+translate 125 20
+drawText 0 0 "No transform"
+translate 350 0
+drawText 0 0 "Left Tilted"
+resetMatrix
+translate 125 350
+drawText 0 0 "Bottom Tilted"
+translate 350 0
+drawText 0 0 "Right Tilted"
+translate 120 0 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/linear_resolving_gradients.qps b/tests/baseline/painting/scripts/linear_resolving_gradients.qps
new file mode 100644
index 0000000000..779760cb9a
--- /dev/null
+++ b/tests/baseline/painting/scripts/linear_resolving_gradients.qps
@@ -0,0 +1,66 @@
+# Version: 2
+# CheckVsReference: 2% (0 0 500 400)
+
+setRenderHint Antialiasing
+
+setPen black
+
+begin_block gradients
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setCoordinateMode ObjectBoundingMode
+gradient_setLinear 0.2 0.2 0.7 0.7
+drawRect 0 0 100 100
+
+gradient_setSpread ReflectSpread
+gradient_setLinear 0.2 0.2 0.7 0.7
+drawEllipse 100 0 100 100
+
+gradient_setSpread RepeatSpread
+gradient_setLinear 0.2 0.2 0.7 0.7
+drawRoundRect 200 0 100 100
+
+gradient_clearStops
+gradient_appendStop 0 3f7f7fff
+gradient_appendStop 0.5 dfdfffff
+gradient_appendStop 1 7f00007f
+
+gradient_setSpread PadSpread
+gradient_setLinear 0.2 0.2 0.8 0.4
+drawPolygon [300 0 400 0 350 100]
+
+gradient_setSpread RepeatSpread
+gradient_setLinear 0.2 0.2 0.4 0.4
+drawPie 400 0 100 100 0 4320
+end_block
+
+translate 0 100
+scale 1 2
+repeat_block gradients
+
+resetMatrix
+translate 0 300
+brushTranslate 30 0
+brushScale 0.9 0.9
+brushRotate 20
+repeat_block gradients
+
+# Some helpful info perhaps?
+resetMatrix
+setPen black
+
+drawText 510 50 "No XForm"
+drawText 510 200 "scale 1x2"
+drawText 510 350 "brush transform"
+
+drawText 10 450 "Pad"
+drawText 110 450 "Reflect"
+drawText 210 450 "Repeat"
+drawText 310 450 "Pad w/alpha"
+drawText 410 450 "Repeat w/alpha" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/lineconsistency.qps b/tests/baseline/painting/scripts/lineconsistency.qps
new file mode 100644
index 0000000000..0b40577659
--- /dev/null
+++ b/tests/baseline/painting/scripts/lineconsistency.qps
@@ -0,0 +1,72 @@
+# Version: 1
+
+begin_block draw
+setPen red
+drawPolygon [1.1 1 3.3 30.6 23.1 39.2 38.9 6.5]
+setPen black
+drawLine 1.1 1 3.3 30.6
+drawLine 3.3 30.6 23.1 39.2
+drawLine 23.1 39.2 38.9 6.5
+drawLine 38.9 6.5 1.1 1
+end_block draw
+drawText 0 60 "0.0 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.1 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.2 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.3 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.4 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.5 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.6 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.7 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.8 aligned"
+translate 0.1 80.1
+repeat_block draw
+drawText 0 60 "0.9 aligned"
+
+resetMatrix
+translate 100 0
+setPen black
+drawText 0 20 "Line and text, 0.0 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.1 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.2 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.3 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.4 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.5 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.6 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.7 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.8 aligned"
+drawLine 0 21 160 21
+translate 0 40.1
+drawText 0 20 "Line and text, 0.9 aligned"
+drawLine 0 21 160 21 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/linedashes.qps b/tests/baseline/painting/scripts/linedashes.qps
new file mode 100644
index 0000000000..78c791e68b
--- /dev/null
+++ b/tests/baseline/painting/scripts/linedashes.qps
@@ -0,0 +1,132 @@
+# Version: 1
+
+translate 10 10
+
+setPen 0xffff0000 0 solidline squarecap
+translate 50 50
+begin_block draw_lines
+ save
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ restore
+end_block
+
+setPen 0xffff0000 0 dotline squarecap
+translate 100 0
+repeat_block draw_lines
+setPen 0xffff0000 0 dashdotline squarecap
+translate 100 0
+repeat_block draw_lines
+setPen 0xffff0000 0 dashdotdotline squarecap
+translate 100 0
+repeat_block draw_lines
+setPen 0xffff0000 0 dashline squarecap
+translate 100 0
+repeat_block draw_lines
+
+path_moveTo mypath 10 10
+path_lineTo mypath 87 10
+path_moveTo mypath 10 30
+path_lineTo mypath 87 30
+path_moveTo mypath 10 50
+path_lineTo mypath 87 50
+
+resetMatrix
+translate 0 150
+
+begin_block distinctLines
+
+setPen black 0 SolidLine SquareCap
+pen_setDashPattern [ 3 3 ]
+drawPath mypath
+
+translate 100 0
+setPen black 5 SolidLine SquareCap
+pen_setDashPattern [ 3 3 ]
+drawPath mypath
+
+translate 100 0
+setPen black 0 SolidLine RoundCap
+pen_setDashPattern [ 3 3 ]
+drawPath mypath
+
+translate 100 0
+setPen black 5 SolidLine RoundCap
+pen_setDashPattern [ 3 3 ]
+drawPath mypath
+
+end_block distinctLines
+
+resetMatrix
+translate 0 220
+setRenderHint Antialiasing true
+repeat_block distinctLines
diff --git a/tests/baseline/painting/scripts/linedashes2.qps b/tests/baseline/painting/scripts/linedashes2.qps
new file mode 100644
index 0000000000..b9a4cb9566
--- /dev/null
+++ b/tests/baseline/painting/scripts/linedashes2.qps
@@ -0,0 +1,196 @@
+# Version: 1
+# CheckVsReference: 5% (0 0 800 800)
+
+translate -30 10
+
+setPen 0xffff0000 0 dashline squarecap
+pen_setDashPattern [10 5]
+
+save
+translate 100 100
+begin_block lines
+drawLine 100 100 200 100
+drawLine 100 100 200 200
+drawLine 100 100 100 200
+end_block
+
+setPen 0xffff0000 2 dashline squarecap
+translate 150 0
+repeat_block lines
+restore
+
+save
+save
+begin_block horizontal
+drawLine 0 0 50 0
+drawLine 3 10 53 10
+drawLine 6 20 56 20
+drawLine 9 30 59 30
+
+translate 0 50
+
+drawLine 0 0 50 5
+drawLine 3 10 53 15
+drawLine 6 20 56 25
+drawLine 9 30 59 35
+
+translate 0 50
+
+drawLine 0 0 50 -5
+drawLine 3 10 53 5
+drawLine 6 20 56 15
+drawLine 9 30 59 25
+end_block
+restore
+
+save
+translate 80 0
+repeat_block horizontal
+restore
+save
+translate 800 0
+repeat_block horizontal
+restore
+
+translate 180 -40
+save
+begin_block vertical
+drawLine 0 0 0 50
+drawLine 10 3 10 53
+drawLine 20 6 20 56
+drawLine 30 9 30 59
+
+translate 50 0
+
+drawLine 0 0 5 50
+drawLine 10 3 15 53
+drawLine 20 6 25 56
+drawLine 30 9 35 59
+
+translate 50 0
+
+drawLine 0 0 -5 50
+drawLine 10 3 5 53
+drawLine 20 6 15 56
+drawLine 30 9 25 59
+end_block
+restore
+
+save
+translate 0 80
+repeat_block vertical
+restore
+translate 0 800
+repeat_block vertical
+restore
+
+translate 0 200
+
+setPen 0xffff0000 2 dashline squarecap
+save
+repeat_block horizontal
+restore
+save
+translate 80 0
+repeat_block horizontal
+restore
+save
+translate 780 0
+repeat_block horizontal
+restore
+
+translate 360 -240
+save
+repeat_block vertical
+restore
+save
+translate 0 80
+repeat_block vertical
+restore
+translate 0 780
+repeat_block vertical
+
+resetMatrix
+translate 20 380
+setPen 0xffff00ff 5 dashdotline flatcap
+begin_block offset
+pen_setDashPattern [1 1 4 1 1 4]
+pen_setDashOffset -4
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset -2
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 0
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 2
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 4
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 6
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 8
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 10
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 12
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 14
+drawLine 0 0 300 0
+translate 0 8
+pen_setDashOffset 16
+drawLine 0 0 300 0
+end_block offset
+
+resetMatrix
+translate 420 380
+setPen 0xffff00ff 5 dashdotline roundcap
+repeat_block offset
+
+resetMatrix
+setPen black 3 dashdotline
+pen_setCosmetic true
+translate 0 -150
+drawLine 500 160 500 410
+
+resetMatrix
+translate 300 480
+setPen blue 0
+
+begin_block clip_lines
+pen_setDashPattern [ 20 4 5 4 1 4 ]
+pen_setDashOffset 26.0
+drawLines [0 0 1000000 10 1000000 10 -1000000 20 -1000000 20 0 30]
+end_block clip_lines
+
+translate 0 45
+setPen blue 5
+repeat_block clip_lines
+
+translate 0 45
+setPen blue 5 SolidLine RoundCap
+repeat_block clip_lines
+
+translate 0 45
+setPen green 0
+
+begin_block clip_poly
+pen_setDashPattern [ 20 4 5 4 1 4 ]
+pen_setDashOffset 26.0
+drawPolyline [0 0 1000000 10 -1000000 20 0 30]
+end_block clip_poly
+
+translate 0 45
+setPen green 5
+repeat_block clip_poly
+
+translate 0 45
+setPen green 5 SolidLine RoundCap
+repeat_block clip_poly
diff --git a/tests/baseline/painting/scripts/linedashes2_aa.qps b/tests/baseline/painting/scripts/linedashes2_aa.qps
new file mode 100644
index 0000000000..c818ab62fe
--- /dev/null
+++ b/tests/baseline/painting/scripts/linedashes2_aa.qps
@@ -0,0 +1,5 @@
+# Version: 1
+# CheckVsReference: 1% (0 0 800 800)
+
+setRenderHint LineAntialiasing
+import "linedashes2.qps" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/lines.qps b/tests/baseline/painting/scripts/lines.qps
new file mode 100644
index 0000000000..274a7f31ec
--- /dev/null
+++ b/tests/baseline/painting/scripts/lines.qps
@@ -0,0 +1,433 @@
+# Version: 1
+# CheckVsReference: 5% (0 0 310 425)
+
+translate 10 10
+
+begin_block draw_lines
+ save
+ translate 50 50
+
+ save
+ setPen 0x7fff0000
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ restore
+
+ # and then draw the lines the other direction
+ save
+ setPen 0x7f0000ff
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ rotate 10
+ drawLine 50 0 10 0
+ restore
+
+ # and now with a clip
+ save
+ setClipRect -30 -30 60 60
+ setPen 0x7f00ff00
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ rotate 10
+ drawLine 10 0 50 0
+ restore
+
+ restore
+end_block
+
+save
+ translate 100 0
+ scale 2 2
+ repeat_block draw_lines
+restore
+
+translate 0 10
+
+save
+ translate 0 200
+ setRenderHint Antialiasing
+ repeat_block draw_lines
+restore
+
+save
+ translate 100 200
+ scale 2 2
+ setRenderHint Antialiasing
+ repeat_block draw_lines
+restore
+
+setPen 0x000000 8
+translate 350 240
+drawText 0 0 "Steep slopes:"
+
+translate 0 10
+
+drawLine 0 0 -8 400
+translate 20 0
+drawLine 0 0 -7 400
+translate 20 0
+drawLine 0 0 -6 400
+translate 20 0
+drawLine 0 0 -5 400
+translate 20 0
+drawLine 0 0 -4 400
+translate 20 0
+drawLine 0 0 -3 400
+translate 20 0
+drawLine 0 0 -2 400
+translate 20 0
+drawLine 0 0 -1 400
+translate 20 0
+drawLine 0 0 0 400
+translate 20 0
+drawLine 0 0 1 400
+translate 20 0
+drawLine 0 0 2 400
+translate 20 0
+drawLine 0 0 3 400
+translate 20 0
+drawLine 0 0 4 400
+translate 20 0
+drawLine 0 0 5 400
+translate 20 0
+drawLine 0 0 6 400
+translate 20 0
+drawLine 0 0 7 400
+translate 20 0
+drawLine 0 0 8 400
+
+resetMatrix
+
+translate 20 450
+
+drawText 0 0 "Zero length lines:"
+
+translate 0 20
+drawText 100 10 "Square cap"
+save
+begin_block points
+setPen 0x000000 1 solidline squarecap
+drawLine 0 0 0 0
+setPen 0x000000 2 solidline squarecap
+drawLine 8 0 8 0
+setPen 0x000000 3 solidline squarecap
+drawLine 16 0 16 0
+setPen 0x000000 4 solidline squarecap
+drawLine 24 0 24 0
+setPen 0x000000 5 solidline squarecap
+drawLine 32 0 32 0
+setPen 0x000000 6 solidline squarecap
+drawLine 40 0 40 0
+setPen 0x000000 7 solidline squarecap
+drawLine 48 0 48 0
+setPen 0x000000 8 solidline squarecap
+drawLine 57 0 57 0
+setPen 0x000000 9 solidline squarecap
+drawLine 67 0 67 0
+setPen 0x000000 10 solidline squarecap
+drawLine 78 0 78 0
+end_block points
+restore
+
+translate 0 12
+setRenderHint Antialiasing off
+repeat_block points
+setRenderHint Antialiasing
+
+translate 0 20
+drawText 100 10 "Round cap"
+save
+begin_block points2
+setPen 0x000000 1 solidline roundcap
+drawLine 0 0 0 0
+setPen 0x000000 2 solidline roundcap
+drawLine 8 0 8 0
+setPen 0x000000 3 solidline roundcap
+drawLine 16 0 16 0
+setPen 0x000000 4 solidline roundcap
+drawLine 24 0 24 0
+setPen 0x000000 5 solidline roundcap
+drawLine 32 0 32 0
+setPen 0x000000 6 solidline roundcap
+drawLine 40 0 40 0
+setPen 0x000000 7 solidline roundcap
+drawLine 48 0 48 0
+setPen 0x000000 8 solidline roundcap
+drawLine 57 0 57 0
+setPen 0x000000 9 solidline roundcap
+drawLine 67 0 67 0
+setPen 0x000000 10 solidline roundcap
+drawLine 78 0 78 0
+end_block points2
+restore
+
+translate 0 12
+setRenderHint Antialiasing off
+repeat_block points2
+setRenderHint Antialiasing
+
+translate 0 20
+drawText 100 10 "Flat cap"
+save
+begin_block points3
+setPen 0x000000 1 solidline flatcap
+drawLine 0 0 0 0
+setPen 0x000000 2 solidline flatcap
+drawLine 8 0 8 0
+setPen 0x000000 3 solidline flatcap
+drawLine 16 0 16 0
+setPen 0x000000 4 solidline flatcap
+drawLine 24 0 24 0
+setPen 0x000000 5 solidline flatcap
+drawLine 32 0 32 0
+setPen 0x000000 6 solidline flatcap
+drawLine 40 0 40 0
+setPen 0x000000 7 solidline flatcap
+drawLine 48 0 48 0
+setPen 0x000000 8 solidline flatcap
+drawLine 57 0 57 0
+setPen 0x000000 9 solidline flatcap
+drawLine 67 0 67 0
+setPen 0x000000 10 solidline flatcap
+drawLine 78 0 78 0
+end_block points3
+restore
+
+translate 0 12
+setRenderHint Antialiasing off
+repeat_block points3
+
+resetMatrix
+translate -220 667.226
+drawText 230 -80 "Task 194266 (should see only one line):"
+setPen black
+drawRect 230.5 -70.5 122 12
+setRenderHint Antialiasing
+setPen red
+drawLine 236.842105263 -63.775117299 247.368421053 -63.775437504
+
+setRenderHint Antialiasing off
+resetMatrix
+translate 10 640
+setPen black
+drawText 0 -10 "Task 207147 (should see two lines):"
+drawRect 0.5 0.5 64 64
+setRenderHint Antialiasing
+setPen red
+
+drawLine 4.5 4.5 4.5001 60.5
+drawLine 4.5 4.5 60.5 4.5001
+
+setRenderHint Antialiasing off
+resetMatrix
+translate 10 730
+setPen black
+drawText 0 -10 "Task 229459 (should see one diagonal line):"
+drawRect 0.5 0.5 64 64
+setPen red 2 solidline flatcap
+
+setClipRect 2 2 63 63
+drawLine 1.5 1.5 33560000 33560000
diff --git a/tests/baseline/painting/scripts/lines2.qps b/tests/baseline/painting/scripts/lines2.qps
new file mode 100644
index 0000000000..af6ad65939
--- /dev/null
+++ b/tests/baseline/painting/scripts/lines2.qps
@@ -0,0 +1,179 @@
+# Version: 1
+# CheckVsReference: 5%
+
+translate 10 20
+drawText 0 0 "Thin lines"
+
+translate 60 70
+
+save
+begin_block lines
+translate 0 -60
+translate 0 5
+setPen 0x000000 0.05
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.1
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.15
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.2
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.25
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.3
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.35
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.2
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.25
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.5
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.55
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.6
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.65
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.7
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.75
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.8
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.85
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.9
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 0.95
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.05
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.1
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.15
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.2
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.25
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.3
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.35
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.2
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.25
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.5
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.55
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.6
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.65
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.7
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.75
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.8
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.85
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.9
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 1.95
+drawLine -60 -2 60 2
+translate 0 5
+setPen 0x000000 2
+drawLine -60 -2 60 2
+end_block
+restore
+
+save
+translate 150 0
+scale -1 1
+repeat_block lines
+restore
+
+save
+translate 80 220
+rotate 90
+repeat_block lines
+restore
+
+save
+translate 80 370
+rotate 90
+scale -1 1
+repeat_block lines
+restore
+
+setRenderHint Antialiasing
+
+translate 300 0
+
+save
+repeat_block lines
+restore
+
+save
+translate 150 0
+scale -1 1
+repeat_block lines
+restore
+
+save
+translate 80 220
+rotate 90
+repeat_block lines
+restore
+
+save
+translate 80 370
+rotate 90
+scale -1 1
+repeat_block lines
+restore \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/lines3.qps b/tests/baseline/painting/scripts/lines3.qps
new file mode 100644
index 0000000000..676235e652
--- /dev/null
+++ b/tests/baseline/painting/scripts/lines3.qps
@@ -0,0 +1,171 @@
+
+clearRenderHint
+setPen black 0 solidline squarecap
+
+save
+translate 20 20
+
+begin_block lines
+
+# 0 -> 45 degress
+drawLine 100 100 200 90
+drawLine 100 100 200 80
+drawLine 100 100 200 70
+drawLine 100 100 200 60
+drawLine 100 100 200 50
+drawLine 100 100 200 40
+drawLine 100 100 200 30
+drawLine 100 100 200 20
+drawLine 100 100 200 10
+
+# 45
+drawLine 100 100 200 0
+
+# 45 -> 90
+drawLine 100 100 190 0
+drawLine 100 100 180 0
+drawLine 100 100 170 0
+drawLine 100 100 160 0
+drawLine 100 100 150 0
+drawLine 100 100 140 0
+drawLine 100 100 130 0
+drawLine 100 100 120 0
+drawLine 100 100 110 0
+
+# 90
+drawLine 100 100 100 0
+
+# 90 -> 135
+drawLine 100 100 90 0
+drawLine 100 100 80 0
+drawLine 100 100 70 0
+drawLine 100 100 60 0
+drawLine 100 100 50 0
+drawLine 100 100 40 0
+drawLine 100 100 30 0
+drawLine 100 100 20 0
+drawLine 100 100 10 0
+
+# 135
+drawLine 100 100 0 0
+
+# 135 -> 180 degress
+drawLine 100 100 0 10
+drawLine 100 100 0 20
+drawLine 100 100 0 30
+drawLine 100 100 0 40
+drawLine 100 100 0 50
+drawLine 100 100 0 60
+drawLine 100 100 0 70
+drawLine 100 100 0 80
+drawLine 100 100 0 90
+
+# 180
+drawLine 100 100 0 100
+
+# 180 -> 225
+drawLine 100 100 0 110
+drawLine 100 100 0 120
+drawLine 100 100 0 130
+drawLine 100 100 0 140
+drawLine 100 100 0 150
+drawLine 100 100 0 160
+drawLine 100 100 0 170
+drawLine 100 100 0 180
+drawLine 100 100 0 190
+
+# 225
+drawLine 100 100 0 200
+
+# 225 -> 270
+drawLine 100 100 10 200
+drawLine 100 100 20 200
+drawLine 100 100 30 200
+drawLine 100 100 40 200
+drawLine 100 100 50 200
+drawLine 100 100 60 200
+drawLine 100 100 70 200
+drawLine 100 100 80 200
+drawLine 100 100 90 200
+
+# 270
+drawLine 100 100 100 200
+
+# 270 -> 315 degrees
+drawLine 100 100 110 200
+drawLine 100 100 120 200
+drawLine 100 100 130 200
+drawLine 100 100 140 200
+drawLine 100 100 150 200
+drawLine 100 100 160 200
+drawLine 100 100 170 200
+drawLine 100 100 180 200
+drawLine 100 100 190 200
+
+# 315
+drawLine 100 100 200 200
+
+# 315 -> 360 degress
+drawLine 100 100 200 100
+drawLine 100 100 200 110
+drawLine 100 100 200 120
+drawLine 100 100 200 130
+drawLine 100 100 200 140
+drawLine 100 100 200 150
+drawLine 100 100 200 160
+drawLine 100 100 200 170
+drawLine 100 100 200 180
+drawLine 100 100 200 190
+
+end_block
+
+setRenderHint Antialiasing
+setPen 0x7fff0000 0 solidline squarecap
+repeat_block lines
+
+translate 250.5 0.5
+clearRenderHint
+setPen black 0 solidline squarecap
+repeat_block lines
+setRenderHint Antialiasing
+setPen 0x7fff0000 0 solidline squarecap
+repeat_block lines
+
+restore
+
+save
+
+translate 20 250
+clearRenderHint
+setPen black 1 solidline squarecap
+repeat_block lines
+setRenderHint Antialiasing
+setPen 0x7fff0000 1 solidline squarecap
+repeat_block lines
+
+translate 250.5 0.5
+clearRenderHint
+setPen black 1 soslidline squarecap
+repeat_block lines
+setRenderHint Antialiasing
+setPen 0x7fff0000 0 solidline squarecap
+repeat_block lines
+
+restore
+
+translate 20 500
+scale 1.5 1.5
+clearRenderHint
+setPen black 1 solidline squarecap
+repeat_block lines
+setRenderHint Antialiasing
+setPen 0x7fff0000 1 solidline squarecap
+repeat_block lines
+
+translate 250.5 0.5
+clearRenderHint
+setPen black 1 soslidline squarecap
+repeat_block lines
+setRenderHint Antialiasing
+setPen 0x7fff0000 0 solidline squarecap
+repeat_block lines
diff --git a/tests/baseline/painting/scripts/pathfill.qps b/tests/baseline/painting/scripts/pathfill.qps
new file mode 100644
index 0000000000..821b4684c9
--- /dev/null
+++ b/tests/baseline/painting/scripts/pathfill.qps
@@ -0,0 +1,38 @@
+# Version: 1
+# CheckVsReference: 1% (0 0 850 420)
+
+setPen afff0000 4
+
+setBrush dome_rgb32.png
+drawEllipse 10 10 200 200
+
+setBrush dome_argb32.png
+drawEllipse 220 10 200 200
+
+setPen NoPen
+
+setBrush dome_rgb32.png
+drawEllipse 10 220 200 200
+
+setBrush dome_argb32.png
+drawEllipse 220 220 200 200
+
+setBrushOrigin -30 -30
+
+setPen afff0000 4
+setBrush dome_rgb32.png
+drawEllipse 430 10 200 200
+
+setBrush dome_argb32.png
+drawEllipse 640 10 200 200
+
+setPen NoPen
+setBrush dome_rgb32.png
+drawEllipse 430 220 200 200
+
+setBrush dome_argb32.png
+drawEllipse 640 220 200 200
+
+setPen black
+drawText 150 450 "No offset RGB/ARGB"
+drawText 550 450 "-30 offset RGB/ARGB" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/paths.qps b/tests/baseline/painting/scripts/paths.qps
new file mode 100644
index 0000000000..454b2a039d
--- /dev/null
+++ b/tests/baseline/painting/scripts/paths.qps
@@ -0,0 +1,49 @@
+# Version: 1
+
+setPen black 1
+setBrush 7f7fff
+
+setFont "arial" 12
+drawText 10 330 "Non-Cosmetic"
+drawText 10 730 "Cosmetic"
+
+path_moveTo star 50 0
+path_lineTo star 30 90
+path_lineTo star 100 60
+path_lineTo star 0 20
+path_lineTo star 80 100
+
+setFont "times" 50
+path_addText text 0 50 "ABCD, 1234, abcd, #¤%&"
+
+path_addRect rectncircle 0 0 75 75
+path_addEllipse rectncircle 25 25 75 75
+path_setFillRule rectncircle winding
+
+path_moveTo curve 100 0
+path_cubicTo curve 100 100 50 50 0 100
+
+begin_block drawing
+drawPath star
+translate 100 0
+drawPath rectncircle
+translate 100 0
+drawPath curve
+translate -200 100
+drawPath text
+end_block
+
+begin_block xform
+save
+translate 50 60
+rotate 10
+scale 1.0 0.7
+repeat_block drawing
+restore
+end_block xform
+
+setPen black 0
+setBrush ff7f7f
+translate 0 300
+repeat_block drawing
+repeat_block xform
diff --git a/tests/baseline/painting/scripts/paths_aa.qps b/tests/baseline/painting/scripts/paths_aa.qps
new file mode 100644
index 0000000000..4812e2fa5f
--- /dev/null
+++ b/tests/baseline/painting/scripts/paths_aa.qps
@@ -0,0 +1,4 @@
+# Version: 1
+
+setRenderHint LineAntialiasing
+import "paths.qps"
diff --git a/tests/baseline/painting/scripts/pens.qps b/tests/baseline/painting/scripts/pens.qps
new file mode 100644
index 0000000000..c72636dcef
--- /dev/null
+++ b/tests/baseline/painting/scripts/pens.qps
@@ -0,0 +1,133 @@
+# Version: 1
+# CheckVsReference: 1% (0 0 800 800)
+
+
+translate 10 10
+
+begin_block penstyles
+setPen black 0 solidline flatcap
+drawLine 0 0 100 0
+setPen black 0 dashline flatcap
+drawLine 100 0 100 40
+setPen black 0 dotline flatcap
+drawLine 100 40 200 0
+setPen black 0 dashdotline flatcap
+drawLine 200 0 300 0
+setPen black 0 dashdotdotline flatcap
+drawLine 300 0 400 40
+
+translate 0 50
+setPen blue 2 solidline flatcap
+drawLine 0 0 100 0
+setPen blue 2 dashline flatcap
+drawLine 100 0 100 40
+setPen blue 2 dotline flatcap
+drawLine 100 40 200 0
+setPen blue 2 dashdotline flatcap
+drawLine 200 0 300 0
+setPen blue 2 dashdotdotline flatcap
+drawLine 300 0 400 40
+
+translate 0 50
+setPen red 5 solidline flatcap
+drawLine 0 0 100 0
+setPen red 5 dashline flatcap
+drawLine 100 0 100 40
+setPen red 5 dotline flatcap
+drawLine 100 40 200 0
+setPen red 5 dashdotline flatcap
+drawLine 200 0 300 0
+setPen red 5 dashdotdotline flatcap
+drawLine 300 0 400 40
+end_block
+
+translate 0 50
+scale 1 2
+repeat_block penstyles
+
+
+# Test cap styles
+resetMatrix
+translate 420 10
+setPen green 5 dashdotline flatcap
+drawLine 0 0 200 0
+setPen green 5 dashdotline roundcap
+drawLine 0 20 200 20
+setPen green 5 dashdotline squarecap
+drawLine 0 40 200 40
+
+
+# Test join styles
+resetMatrix
+translate 420 80
+setBrush nobrush
+begin_block joinstyles
+setPen orange 10 solidline flatcap miterjoin
+drawPolyline [ 0 0 80 0 80 80 0 80 ]
+
+translate 0 100
+setPen aquamarine 10 solidline squarecap beveljoin
+drawPolyline [ 0 0 80 0 80 80 0 80 ]
+
+translate 0 100
+setPen purple 10 solidline roundcap roundjoin
+drawPolyline [ 0 0 80 0 80 80 0 80 ]
+end_block
+
+translate 130 -200
+scale 2 1
+rotate 1
+repeat_block joinstyles
+
+# transparent lines
+resetMatrix
+translate 10 400
+setPen #7f000000
+drawLine 0 0 50 0
+setPen #7f000000 1 SolidLine
+drawLine 0 10 50 10
+setPen #7f000000 5 SolidLine
+drawLine 0 20 50 20
+setPen #7f000000 10 SolidLine
+drawLine 0 30 50 30
+setPen #7f000000
+drawLine 0 0 0 50
+setPen #7f000000 1 SolidLine
+drawLine 10 0 10 50
+setPen #7f000000 5 SolidLine
+drawLine 20 0 20 50
+setPen #7f000000 10 SolidLine
+drawLine 30 0 30 50
+
+# pen styles
+resetMatrix
+translate 0 500
+setPen black 0 DashLine
+drawLine 20 20 100 20
+translate 0 10
+setPen black 0 DotLine
+drawLine 20 20 100 20
+translate 0 10
+setPen black 0 DashDotLine
+drawLine 20 20 100 20
+translate 0 10
+setPen black 0 DashDotDotLine
+drawLine 20 20 100 20
+
+# scaling ellipse
+resetMatrix
+setPen black 0.008 DashLine
+translate 250 550
+rotate 30
+scale 250 250
+drawEllipse -0.4 -0.4 0.8 0.8
+
+# scaling path
+path_addEllipse star -0.3 -0.3 0.6 0.6
+
+resetMatrix
+setPen black 0.008 DashLine
+translate 250 550
+rotate 30
+scale 250 250
+drawPath star
diff --git a/tests/baseline/painting/scripts/pens_aa.qps b/tests/baseline/painting/scripts/pens_aa.qps
new file mode 100644
index 0000000000..066cac365f
--- /dev/null
+++ b/tests/baseline/painting/scripts/pens_aa.qps
@@ -0,0 +1,6 @@
+# Version: 1
+# CheckVsReference: 1% (0 0 800 800)
+
+setRenderHint LineAntialiasing
+
+import "pens.qps" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/pens_cosmetic.qps b/tests/baseline/painting/scripts/pens_cosmetic.qps
new file mode 100644
index 0000000000..9120290462
--- /dev/null
+++ b/tests/baseline/painting/scripts/pens_cosmetic.qps
@@ -0,0 +1,116 @@
+# Version: 1
+# CheckVsReference: 1% (0 0 585 470)
+
+path_addEllipse path 22 0 7 7
+path_addRect path 25 5 4 4
+
+translate 20 20
+
+setPen black 0
+pen_setCosmetic false
+
+begin_block lines
+ save
+ drawLine 0 0 10 10
+ drawLine 2 0 10 0
+ drawLine 0 2 0 10
+ drawPolygon [12 0 20 0 15 10]
+ drawPath path
+ drawEllipse 32 0 8 8
+ drawPoint 36 4
+
+ translate 100 0
+ save
+ scale 4 1
+ drawLine 0 0 10 10
+ drawLine 2 0 10 0
+ drawLine 0 2 0 10
+ drawPolygon [12 0 20 0 15 10]
+ drawPath path
+ drawEllipse 32 0 8 8
+ drawPoint 36 4
+ restore
+
+ translate 200 0
+ save
+ scale 1 4
+ drawLine 0 0 10 10
+ drawLine 2 0 10 0
+ drawLine 0 2 0 10
+ drawPolygon [12 0 20 0 15 10]
+ drawPath path
+ drawEllipse 32 0 8 8
+ drawPoint 36 4
+ restore
+
+ translate 100 0
+ save
+ scale 4 4
+ drawLine 0 0 10 10
+ drawLine 2 0 10 0
+ drawLine 0 2 0 10
+ drawPolygon [12 0 20 0 15 10]
+ drawPath path
+ drawEllipse 32 0 8 8
+ drawPoint 36 4
+ restore
+ restore
+end_block
+
+drawText 580 15 "non-cosmetic, 0-width"
+translate 0 50
+
+setPen black 2
+pen_setCosmetic false
+repeat_block lines
+drawText 580 15 "non-cosmetic, 2-width"
+
+translate 0 20
+translate 0 50
+setPen black 0
+pen_setCosmetic true
+repeat_block lines
+drawText 580 15 "cosmetic, 0-width"
+
+translate 0 50
+setPen black 2
+pen_setCosmetic true
+repeat_block lines
+drawText 580 15 "cosmetic, 2-width"
+
+
+setRenderHint Antialiasing
+translate 0 20
+
+translate 0 50
+setPen black 0
+pen_setCosmetic false
+repeat_block lines
+drawText 580 15 "non-cosmetic, 0-width"
+
+translate 0 50
+
+setPen black 2
+pen_setCosmetic false
+repeat_block lines
+drawText 580 15 "non-cosmetic, 2-width"
+
+translate 0 20
+translate 0 50
+setPen black 0
+pen_setCosmetic true
+repeat_block lines
+drawText 580 15 "cosmetic, 0-width"
+
+translate 0 50
+setPen black 2
+pen_setCosmetic true
+repeat_block lines
+drawText 580 15 "cosmetic, 2-width"
+
+
+translate 0 70
+drawText 0 0 "scale(1, 1)"
+drawText 150 0 "scale(4, 1)"
+drawText 300 0 "scale(1, 4)"
+drawText 450 0 "scale(4, 4)" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/perspectives.qps b/tests/baseline/painting/scripts/perspectives.qps
new file mode 100644
index 0000000000..0b903e5260
--- /dev/null
+++ b/tests/baseline/painting/scripts/perspectives.qps
@@ -0,0 +1,72 @@
+# Version: 1
+
+
+setRenderHint Antialiasing
+
+setPen #00ff00
+
+image_load image.png the_image
+
+translate 10 10
+# standard draw
+drawImage the_image 0 0
+
+# Rotation w/o smooth xform
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 50 0 200 300 300 300 0
+ drawImage the_image 0 0
+restore
+restore
+
+translate 0 320
+
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 100 300 200 300 300 0
+ drawImage the_image 0 0
+restore
+
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 0 300 300 250 300 50
+ drawImage the_image 0 0
+restore
+restore
+
+setRenderHint SmoothPixmapTransform on
+setBrush red
+setPen black
+resetMatrix
+translate 100 720
+rotate_y 85
+scale 7 0.01
+drawRect -150 -150 300 300
+
+resetMatrix
+setBrush gam030.png
+setPen black 30
+translate 700 700
+rotate_y -85
+scale 7 0.01
+drawRect -150 -150 300 300
+
+resetMatrix
+setPen black
+translate 125 20
+drawText 0 0 "No transform"
+translate 350 0
+drawText 0 0 "Left Tilted"
+resetMatrix
+translate 125 350
+drawText 0 0 "Bottom Tilted"
+translate 350 0
+drawText 0 0 "Right Tilted"
+translate 120 0
+resetMatrix
+translate 300 760
+drawText 0 0 "Perspective Clipping" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/perspectives2.qps b/tests/baseline/painting/scripts/perspectives2.qps
new file mode 100644
index 0000000000..6762e21af4
--- /dev/null
+++ b/tests/baseline/painting/scripts/perspectives2.qps
@@ -0,0 +1,309 @@
+# Version: 1
+
+setRenderHint Antialiasing
+
+image_load zebra.png zebra_png
+
+image_convertToFormat zebra_png zebra ARGB32_Premultiplied
+
+translate 75 100
+# standard draw
+begin_block row1
+drawImage zebra -50 -50
+
+translate 90 0
+save
+rotate_y 50
+drawImage zebra -50 -50
+restore
+
+translate 65 0
+save
+rotate_y 60
+drawImage zebra -50 -50
+restore
+
+translate 50 0
+save
+rotate_y 70
+drawImage zebra -50 -50
+restore
+
+translate 30 0
+save
+rotate_y 80
+drawImage zebra -50 -50
+restore
+
+translate 24 0
+save
+rotate_y 82
+drawImage zebra -50 -50
+restore
+
+translate 20 0
+save
+rotate_y 84
+drawImage zebra -50 -50
+restore
+
+translate 16 0
+save
+rotate_y 86
+drawImage zebra -50 -50
+restore
+
+translate 12 0
+save
+rotate_y 87
+drawImage zebra -50 -50
+restore
+
+translate 8 0
+save
+rotate_y 88
+drawImage zebra -50 -50
+restore
+
+translate 6 0
+save
+rotate_y 89
+drawImage zebra -50 -50
+restore
+
+translate 6 0
+save
+rotate_y 91
+drawImage zebra -50 -50
+restore
+
+translate 6 0
+save
+rotate_y 92
+drawImage zebra -50 -50
+restore
+
+translate 8 0
+save
+rotate_y 93
+drawImage zebra -50 -50
+restore
+
+translate 12 0
+save
+rotate_y 94
+drawImage zebra -50 -50
+restore
+
+translate 16 0
+save
+rotate_y 96
+drawImage zebra -50 -50
+restore
+
+translate 20 0
+save
+rotate_y 98
+drawImage zebra -50 -50
+restore
+
+translate 24 0
+save
+rotate_y 100
+drawImage zebra -50 -50
+restore
+
+translate 30 0
+save
+rotate_y 110
+drawImage zebra -50 -50
+restore
+
+translate 50 0
+save
+rotate_y 120
+drawImage zebra -50 -50
+restore
+
+translate 65 0
+save
+rotate_y 130
+drawImage zebra -50 -50
+restore
+
+translate 90 0
+save
+rotate_y 180
+drawImage zebra -50 -50
+restore
+end_block row1
+
+resetMatrix
+translate 75 280
+setRenderHint SmoothPixmapTransform
+repeat_block row1
+
+resetMatrix
+setPen black
+translate 300 20
+drawText 0 0 "Fast Pixmap Transform"
+resetMatrix
+translate 300 210
+drawText 0 0 "Smooth Pixmap Transform"
+
+resetMatrix
+translate 0 400
+
+image_load dome_argb32.png the_pixmap
+
+image_convertToFormat the_pixmap dome ARGB32
+
+setRenderHint SmoothPixmapTransform false
+
+translate 75 100
+# standard draw
+begin_block row2
+drawImage dome -50 -50
+
+translate 90 0
+save
+rotate_y 50
+drawImage dome -50 -50
+restore
+
+translate 65 0
+save
+rotate_y 60
+drawImage dome -50 -50
+restore
+
+translate 50 0
+save
+rotate_y 70
+drawImage dome -50 -50
+restore
+
+translate 30 0
+save
+rotate_y 80
+drawImage dome -50 -50
+restore
+
+translate 24 0
+save
+rotate_y 82
+drawImage dome -50 -50
+restore
+
+translate 20 0
+save
+rotate_y 84
+drawImage dome -50 -50
+restore
+
+translate 16 0
+save
+rotate_y 86
+drawImage dome -50 -50
+restore
+
+translate 12 0
+save
+rotate_y 87
+drawImage dome -50 -50
+restore
+
+translate 8 0
+save
+rotate_y 88
+drawImage dome -50 -50
+restore
+
+translate 6 0
+save
+rotate_y 89
+drawImage dome -50 -50
+restore
+
+translate 6 0
+save
+rotate_y 91
+drawImage dome -50 -50
+restore
+
+translate 6 0
+save
+rotate_y 92
+drawImage dome -50 -50
+restore
+
+translate 8 0
+save
+rotate_y 93
+drawImage dome -50 -50
+restore
+
+translate 12 0
+save
+rotate_y 94
+drawImage dome -50 -50
+restore
+
+translate 16 0
+save
+rotate_y 96
+drawImage dome -50 -50
+restore
+
+translate 20 0
+save
+rotate_y 98
+drawImage dome -50 -50
+restore
+
+translate 24 0
+save
+rotate_y 100
+drawImage dome -50 -50
+restore
+
+translate 30 0
+save
+rotate_y 110
+drawImage dome -50 -50
+restore
+
+translate 50 0
+save
+rotate_y 120
+drawImage dome -50 -50
+restore
+
+translate 65 0
+save
+rotate_y 130
+drawImage dome -50 -50
+restore
+
+translate 90 0
+save
+rotate_y 180
+drawImage dome -50 -50
+restore
+end_block row2
+
+resetMatrix
+translate 0 400
+translate 75 280
+setRenderHint SmoothPixmapTransform
+repeat_block row2
+
+resetMatrix
+setPen black
+translate 0 400
+translate 300 20
+drawText 0 0 "Fast Pixmap Transform"
+resetMatrix
+translate 0 400
+translate 300 210
+drawText 0 0 "Smooth Pixmap Transform"
diff --git a/tests/baseline/painting/scripts/pixmap_rotation.qps b/tests/baseline/painting/scripts/pixmap_rotation.qps
new file mode 100644
index 0000000000..8427af85af
--- /dev/null
+++ b/tests/baseline/painting/scripts/pixmap_rotation.qps
@@ -0,0 +1,31 @@
+# Version: 1
+# CheckVsReference: 0% (0 0 440 220)
+
+translate 120 120
+
+begin_block drawing
+save
+ rotate 90
+ drawPixmap solid.png 0 0
+
+ rotate 90
+ drawPixmap solid.png 0 0
+
+ rotate 90
+ drawPixmap solid.png 0 0
+
+ rotate 90
+ drawPixmap solid.png 0 0
+restore
+end_block
+
+resetMatrix
+
+translate 340 120
+setRenderHint SmoothPixmapTransformation
+repeat_block drawing
+
+resetMatrix
+
+drawText 50 240 "Normal Xform"
+drawText 270 240 "Smooth Xform"
diff --git a/tests/baseline/painting/scripts/pixmap_rotation2.qps b/tests/baseline/painting/scripts/pixmap_rotation2.qps
new file mode 100644
index 0000000000..dfb93fe09c
--- /dev/null
+++ b/tests/baseline/painting/scripts/pixmap_rotation2.qps
@@ -0,0 +1,8 @@
+# Version: 1
+# CheckVsReference: 1%
+
+setRenderHint SmoothPixmapTransformation
+translate 400 -120
+rotate 45
+scale 400 400
+drawImage solid2x2.png 0 0
diff --git a/tests/baseline/painting/scripts/pixmap_scaling.qps b/tests/baseline/painting/scripts/pixmap_scaling.qps
new file mode 100644
index 0000000000..8a5ab2c60e
--- /dev/null
+++ b/tests/baseline/painting/scripts/pixmap_scaling.qps
@@ -0,0 +1,224 @@
+# Version: 1
+# CheckVsReference: 0% (0 30 600 70)
+# CheckVsReference: 0% (290 130 280 60)
+# CheckVsReference: 0% (0 180 250 90)
+
+# Hurra! Force line endings (?)
+
+translate 5 25
+setFont "arial" 8
+
+save
+ drawText 15 0 "opaque image"
+ translate 50 50
+ save
+ translate 1 1
+ scale 20 20
+ drawImage solid2x2.png 0 0
+ restore
+ save
+ translate -1 1
+ scale -20 20
+ drawImage solid2x2.png 0 0
+ restore
+ save
+ translate 1 -1
+ scale 20 -20
+ drawImage solid2x2.png 0 0
+ restore
+ save
+ translate -1 -1
+ scale -20 -20
+ drawImage solid2x2.png 0 0
+ restore
+
+
+restore
+
+save
+ translate 150 0
+ drawText 15 0 "alpha image"
+ translate 50 50
+ save
+ translate 1 1
+ scale 20 20
+ drawImage alpha2x2.png 0 0
+ restore
+ save
+ translate -1 1
+ scale -20 20
+ drawImage alpha2x2.png 0 0
+ restore
+ save
+ translate 1 -1
+ scale 20 -20
+ drawImage alpha2x2.png 0 0
+ restore
+ save
+ translate -1 -1
+ scale -20 -20
+ drawImage alpha2x2.png 0 0
+ restore
+restore
+
+
+save
+ translate 0 150
+ drawText 15 0 "solid pixmap"
+ translate 50 50
+ save
+ translate 1 1
+ scale 20 20
+ drawPixmap solid2x2.png 0 0
+ restore
+ save
+ translate -1 1
+ scale -20 20
+ drawPixmap solid2x2.png 0 0
+ restore
+ save
+ translate 1 -1
+ scale 20 -20
+ drawPixmap solid2x2.png 0 0
+ restore
+ save
+ translate -1 -1
+ scale -20 -20
+ drawPixmap solid2x2.png 0 0
+ restore
+restore
+
+
+save
+ translate 150 150
+ drawText 15 0 "alpha pixmap"
+ translate 50 50
+ save
+ translate 1 1
+ scale 20 20
+ drawPixmap alpha2x2.png 0 0
+ restore
+ save
+ translate -1 1
+ scale -20 20
+ drawPixmap alpha2x2.png 0 0
+ restore
+ save
+ translate 1 -1
+ scale 20 -20
+ drawPixmap alpha2x2.png 0 0
+ restore
+ save
+ translate -1 -1
+ scale -20 -20
+ drawPixmap alpha2x2.png 0 0
+ restore
+restore
+
+
+save
+ translate 300 10
+ save
+ drawText 0 -10 "subrect solid image"
+ drawImage solid2x2.png 0 0 50 5 0 0.0 2 0.2
+ drawImage solid2x2.png 0 5 50 5 0 0.2 2 0.2
+ drawImage solid2x2.png 0 10 50 5 0 0.4 2 0.2
+ drawImage solid2x2.png 0 15 50 5 0 0.6 2 0.2
+ drawImage solid2x2.png 0 20 50 5 0 0.8 2 0.2
+ drawImage solid2x2.png 0 25 50 5 0 1.0 2 0.2
+ drawImage solid2x2.png 0 30 50 5 0 1.2 2 0.2
+ drawImage solid2x2.png 0 35 50 5 0 1.4 2 0.2
+ drawImage solid2x2.png 0 40 50 5 0 1.6 2 0.2
+ drawImage solid2x2.png 0 45 50 5 0 1.8 2 0.2
+ translate 60 0
+ drawImage solid2x2.png 0 0 5 50 0.0 0 0.2 2
+ drawImage solid2x2.png 5 0 5 50 0.2 0 0.2 2
+ drawImage solid2x2.png 10 0 5 50 0.4 0 0.2 2
+ drawImage solid2x2.png 15 0 5 50 0.6 0 0.2 2
+ drawImage solid2x2.png 20 0 5 50 0.8 0 0.2 2
+ drawImage solid2x2.png 25 0 5 50 1.0 0 0.2 2
+ drawImage solid2x2.png 30 0 5 50 1.2 0 0.2 2
+ drawImage solid2x2.png 35 0 5 50 1.4 0 0.2 2
+ drawImage solid2x2.png 40 0 5 50 1.6 0 0.2 2
+ drawImage solid2x2.png 45 0 5 50 1.8 0 0.2 2
+ restore
+
+ save
+ translate 150 0
+ drawText 0 -10 "subrect solid image"
+ drawImage alpha2x2.png 0 0 50 5 0 0.0 2 0.2
+ drawImage alpha2x2.png 0 5 50 5 0 0.2 2 0.2
+ drawImage alpha2x2.png 0 10 50 5 0 0.4 2 0.2
+ drawImage alpha2x2.png 0 15 50 5 0 0.6 2 0.2
+ drawImage alpha2x2.png 0 20 50 5 0 0.8 2 0.2
+ drawImage alpha2x2.png 0 25 50 5 0 1.0 2 0.2
+ drawImage alpha2x2.png 0 30 50 5 0 1.2 2 0.2
+ drawImage alpha2x2.png 0 35 50 5 0 1.4 2 0.2
+ drawImage alpha2x2.png 0 40 50 5 0 1.6 2 0.2
+ drawImage alpha2x2.png 0 45 50 5 0 1.8 2 0.2
+ translate 60 0
+ drawImage alpha2x2.png 0 0 5 50 0.0 0 0.2 2
+ drawImage alpha2x2.png 5 0 5 50 0.2 0 0.2 2
+ drawImage alpha2x2.png 10 0 5 50 0.4 0 0.2 2
+ drawImage alpha2x2.png 15 0 5 50 0.6 0 0.2 2
+ drawImage alpha2x2.png 20 0 5 50 0.8 0 0.2 2
+ drawImage alpha2x2.png 25 0 5 50 1.0 0 0.2 2
+ drawImage alpha2x2.png 30 0 5 50 1.2 0 0.2 2
+ drawImage alpha2x2.png 35 0 5 50 1.4 0 0.2 2
+ drawImage alpha2x2.png 40 0 5 50 1.6 0 0.2 2
+ drawImage alpha2x2.png 45 0 5 50 1.8 0 0.2 2
+ restore
+
+ save
+ translate 0 100
+ drawText 0 -10 "subrect alpha pixmap"
+ drawPixmap solid2x2.png 0 0 50 5 0 0.0 2 0.2
+ drawPixmap solid2x2.png 0 5 50 5 0 0.2 2 0.2
+ drawPixmap solid2x2.png 0 10 50 5 0 0.4 2 0.2
+ drawPixmap solid2x2.png 0 15 50 5 0 0.6 2 0.2
+ drawPixmap solid2x2.png 0 20 50 5 0 0.8 2 0.2
+ drawPixmap solid2x2.png 0 25 50 5 0 1.0 2 0.2
+ drawPixmap solid2x2.png 0 30 50 5 0 1.2 2 0.2
+ drawPixmap solid2x2.png 0 35 50 5 0 1.4 2 0.2
+ drawPixmap solid2x2.png 0 40 50 5 0 1.6 2 0.2
+ drawPixmap solid2x2.png 0 45 50 5 0 1.8 2 0.2
+ translate 60 0
+ drawPixmap solid2x2.png 0 0 5 50 0.0 0 0.2 2
+ drawPixmap solid2x2.png 5 0 5 50 0.2 0 0.2 2
+ drawPixmap solid2x2.png 10 0 5 50 0.4 0 0.2 2
+ drawPixmap solid2x2.png 15 0 5 50 0.6 0 0.2 2
+ drawPixmap solid2x2.png 20 0 5 50 0.8 0 0.2 2
+ drawPixmap solid2x2.png 25 0 5 50 1.0 0 0.2 2
+ drawPixmap solid2x2.png 30 0 5 50 1.2 0 0.2 2
+ drawPixmap solid2x2.png 35 0 5 50 1.4 0 0.2 2
+ drawPixmap solid2x2.png 40 0 5 50 1.6 0 0.2 2
+ drawPixmap solid2x2.png 45 0 5 50 1.8 0 0.2 2
+ restore
+
+ save
+ translate 150 100
+ drawText 0 -10 "subrect alpha pixmap"
+ drawPixmap alpha2x2.png 0 0 50 5 0 0.0 2 0.2
+ drawPixmap alpha2x2.png 0 5 50 5 0 0.2 2 0.2
+ drawPixmap alpha2x2.png 0 10 50 5 0 0.4 2 0.2
+ drawPixmap alpha2x2.png 0 15 50 5 0 0.6 2 0.2
+ drawPixmap alpha2x2.png 0 20 50 5 0 0.8 2 0.2
+ drawPixmap alpha2x2.png 0 25 50 5 0 1.0 2 0.2
+ drawPixmap alpha2x2.png 0 30 50 5 0 1.2 2 0.2
+ drawPixmap alpha2x2.png 0 35 50 5 0 1.4 2 0.2
+ drawPixmap alpha2x2.png 0 40 50 5 0 1.6 2 0.2
+ drawPixmap alpha2x2.png 0 45 50 5 0 1.8 2 0.2
+ translate 60 0
+ drawPixmap alpha2x2.png 0 0 5 50 0.0 0 0.2 2
+ drawPixmap alpha2x2.png 5 0 5 50 0.2 0 0.2 2
+ drawPixmap alpha2x2.png 10 0 5 50 0.4 0 0.2 2
+ drawPixmap alpha2x2.png 15 0 5 50 0.6 0 0.2 2
+ drawPixmap alpha2x2.png 20 0 5 50 0.8 0 0.2 2
+ drawPixmap alpha2x2.png 25 0 5 50 1.0 0 0.2 2
+ drawPixmap alpha2x2.png 30 0 5 50 1.2 0 0.2 2
+ drawPixmap alpha2x2.png 35 0 5 50 1.4 0 0.2 2
+ drawPixmap alpha2x2.png 40 0 5 50 1.6 0 0.2 2
+ drawPixmap alpha2x2.png 45 0 5 50 1.8 0 0.2 2
+ restore
+
+restore \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/pixmap_subpixel.qps b/tests/baseline/painting/scripts/pixmap_subpixel.qps
new file mode 100644
index 0000000000..d5b7b92fc9
--- /dev/null
+++ b/tests/baseline/painting/scripts/pixmap_subpixel.qps
@@ -0,0 +1,117 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+translate 50 50
+
+# Pixmaps at 0.1 offset, unclipped
+begin_block draw_pixmaps
+save
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+ drawPixmap border.png 0 0
+ translate 20.1 0.1
+restore
+end_block
+
+# Tiled pixmaps at 0.1 offsets, unclipped
+translate 0 50
+begin_block draw_tiled
+save
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+ drawTiledPixmap border.png 0 0 16 16 0 0
+ translate 20.1 0.1
+restore
+end_block
+
+
+path_moveTo clip 0 0
+path_lineTo clip width 0
+path_lineTo clip width 400
+path_lineTo clip 0 height
+setClipPath clip
+
+translate 0 50
+# Pixmaps at 0.1 offset, clipped
+repeat_block draw_pixmaps
+
+
+# Tiled pixmaps at 0.1 offsets...
+translate 0 50
+repeat_block draw_tiled
+
diff --git a/tests/baseline/painting/scripts/pixmaps.qps b/tests/baseline/painting/scripts/pixmaps.qps
new file mode 100644
index 0000000000..0b4ba2c4fb
--- /dev/null
+++ b/tests/baseline/painting/scripts/pixmaps.qps
@@ -0,0 +1,106 @@
+# Version: 1
+# CheckVsReference: 1% (0 0 690 580)
+
+
+setRenderHint Antialiasing
+
+setPen #00ff00
+
+pixmap_load dome_argb32.png the_pixmap
+begin_block draw_stuff
+
+save
+
+ # standard draw
+ drawPixmap the_pixmap 0 0
+
+ # sub recting
+ translate 120 0
+ drawPixmap the_pixmap 0 0 40 40 0 0 40 40
+ drawPixmap the_pixmap 60 0 40 40 60 0 40 40
+ drawPixmap the_pixmap 0 60 40 40 0 60 40 40
+ drawPixmap the_pixmap 60 60 40 40 60 60 40 40
+ drawPixmap the_pixmap 0 40 40 20 0 40 40 20
+ drawPixmap the_pixmap 60 40 40 20 60 40 40 20
+ drawPixmap the_pixmap 40 0 20 100 40 0 20 100
+
+ # subrecting w/scale
+ translate 120 0
+ drawPixmap the_pixmap 0 0 50 50 0 0 25 25
+ drawPixmap the_pixmap 50 0 50 50 25 0 25 25
+ drawPixmap the_pixmap 0 50 50 50 0 25 25 25
+ drawPixmap the_pixmap 50 50 50 50 25 25 25 25
+
+ # subrecting w/scale & smooth xform
+ translate 120 0
+ setRenderHint SmoothPixmapTransformation
+ drawPixmap the_pixmap 0 0 50 50 0 0 25 25
+ drawPixmap the_pixmap 50 0 50 50 25 0 25 25
+ drawPixmap the_pixmap 0 50 50 50 0 25 25 25
+ drawPixmap the_pixmap 50 50 50 50 25 25 25 25
+
+
+ # Rotation w/o smooth xform
+ translate 120 0
+ save
+ setRenderHint SmoothPixmapTransform off
+ rotate 10
+ drawPixmap the_pixmap 0 0
+ restore
+
+ # Rotation w smooth xform
+ translate 120 0
+ save
+ setRenderHint SmoothPixmapTransform
+ rotate 10
+ drawPixmap the_pixmap 0 0
+ restore
+
+restore
+
+end_block
+
+
+translate 0 120
+pixmap_load dome_rgb32.png the_pixmap
+repeat_block draw_stuff
+
+translate 0 120
+pixmap_load dome_indexed.png the_pixmap
+repeat_block draw_stuff
+
+translate 0 120
+pixmap_load dome_indexed_mask.png the_pixmap
+repeat_block draw_stuff
+
+translate 0 120
+pixmap_load dome_mono.png the_pixmap
+repeat_block draw_stuff
+
+
+resetMatrix
+translate 700 60
+setPen black
+drawText 0 0 "32 bit w/alpha"
+translate 0 120
+drawText 0 0 "32 bit w/o alpha"
+translate 0 120
+drawText 0 0 "8 bit indexed"
+translate 0 120
+drawText 0 0 "8 bit indexed w/mask"
+translate 0 120
+drawText 0 0 "1 bit"
+resetMatrix
+translate 0 600
+drawText 0 0 "normal"
+translate 120 0
+drawText 0 0 "subrect"
+translate 120 0
+drawText 0 0 "subrect scale"
+translate 120 0
+drawText 0 0 "subrect scale smooth"
+translate 120 0
+drawText 0 0 "xform"
+translate 120 0
+drawText 0 0 "smooth xform"
+translate 120 0 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/porter_duff.qps b/tests/baseline/painting/scripts/porter_duff.qps
new file mode 100644
index 0000000000..94e9c68522
--- /dev/null
+++ b/tests/baseline/painting/scripts/porter_duff.qps
@@ -0,0 +1,251 @@
+# Version: 1
+# CheckVsReference: 5%
+
+
+translate 0 50
+
+surface_begin 0 0 100 100
+
+begin_block predraw
+setRenderHint Antialiasing
+setPen nopen
+setBrush 0x7f000000
+drawEllipse 10 10 80 80
+end_block
+
+setCompositionMode SourceOver
+
+begin_block postdraw
+
+
+setBrush 0x1fff0000
+drawRect 0 0 50 50
+
+setBrush 0xdf00ff00
+drawRect 50 50 50 50
+
+setBrush 0x7f0000ff
+drawEllipse 30 30 40 40
+
+# a black rectangle around
+setCompositionMode SourceOver
+setPen black
+setBrush nobrush
+drawRect 0.5 0.5 99 99
+
+end_block
+surface_end
+
+
+# Destination over
+surface_begin 100 0 100 100
+repeat_block predraw
+setCompositionMode DestinationOver
+repeat_block postdraw
+surface_end
+
+
+# Clear
+surface_begin 200 0 100 100
+repeat_block predraw
+setCompositionMode Clear
+repeat_block postdraw
+surface_end
+
+
+# Source
+surface_begin 300 0 100 100
+repeat_block predraw
+setCompositionMode Source
+repeat_block postdraw
+surface_end
+
+
+# Destination
+surface_begin 400 0 100 100
+repeat_block predraw
+setCompositionMode Destination
+repeat_block postdraw
+surface_end
+
+
+# Source In
+surface_begin 500 0 100 100
+repeat_block predraw
+setCompositionMode SourceIn
+repeat_block postdraw
+surface_end
+
+translate 0 50
+
+# Destination In
+surface_begin 0 100 100 100
+repeat_block predraw
+setCompositionMode DestinationIn
+repeat_block postdraw
+surface_end
+
+
+# Source Out
+surface_begin 100 100 100 100
+repeat_block predraw
+setCompositionMode SourceOut
+repeat_block postdraw
+surface_end
+
+
+# Destination Out
+surface_begin 200 100 100 100
+repeat_block predraw
+setCompositionMode DestinationOut
+repeat_block postdraw
+surface_end
+
+
+# SourceAtop
+surface_begin 300 100 100 100
+repeat_block predraw
+setCompositionMode SourceAtop
+repeat_block postdraw
+surface_end
+
+
+# DestinationAtop
+surface_begin 400 100 100 100
+repeat_block predraw
+setCompositionMode DestinationAtop
+repeat_block postdraw
+surface_end
+
+
+# Xor
+surface_begin 500 100 100 100
+repeat_block predraw
+setCompositionMode Xor
+repeat_block postdraw
+surface_end
+
+translate 0 50
+
+# Plus
+surface_begin 0 200 100 100
+repeat_block predraw
+setCompositionMode Plus
+repeat_block postdraw
+surface_end
+
+
+# Multiply
+surface_begin 100 200 100 100
+repeat_block predraw
+setCompositionMode Multiply
+repeat_block postdraw
+surface_end
+
+
+# Screen
+surface_begin 200 200 100 100
+repeat_block predraw
+setCompositionMode Screen
+repeat_block postdraw
+surface_end
+
+
+# Overlay
+surface_begin 300 200 100 100
+repeat_block predraw
+setCompositionMode Overlay
+repeat_block postdraw
+surface_end
+
+
+# Darken
+surface_begin 400 200 100 100
+repeat_block predraw
+setCompositionMode Darken
+repeat_block postdraw
+surface_end
+
+
+# Lighten
+surface_begin 500 200 100 100
+repeat_block predraw
+setCompositionMode Lighten
+repeat_block postdraw
+surface_end
+
+translate 0 50
+
+# ColorDodge
+surface_begin 0 300 100 100
+repeat_block predraw
+setCompositionMode ColorDodge
+repeat_block postdraw
+surface_end
+
+
+# ColorBurn
+surface_begin 100 300 100 100
+repeat_block predraw
+setCompositionMode ColorBurn
+repeat_block postdraw
+surface_end
+
+
+# HardLight
+surface_begin 200 300 100 100
+repeat_block predraw
+setCompositionMode HardLight
+repeat_block postdraw
+surface_end
+
+
+# SoftLight
+surface_begin 300 300 100 100
+repeat_block predraw
+setCompositionMode SoftLight
+repeat_block postdraw
+surface_end
+
+
+# Difference
+surface_begin 400 300 100 100
+repeat_block predraw
+setCompositionMode Difference
+repeat_block postdraw
+surface_end
+
+
+# Exclusion
+surface_begin 500 300 100 100
+repeat_block predraw
+setCompositionMode Exclusion
+repeat_block postdraw
+surface_end
+
+resetMatrix
+
+drawText 0 50 "SourceOver"
+drawText 100 50 "DestinationOver"
+drawText 200 50 "Clear"
+drawText 300 50 "Source"
+drawText 400 50 "Destination"
+drawText 500 50 "SourceIn"
+drawText 0 200 "DestinationIn"
+drawText 100 200 "SourceOut"
+drawText 200 200 "DestinationOut"
+drawText 300 200 "SourceAtop"
+drawText 400 200 "DestinationAtop"
+drawText 500 200 "Xor"
+drawText 0 350 "Plus"
+drawText 100 350 "Multiply"
+drawText 200 350 "Screen"
+drawText 300 350 "Overlay"
+drawText 400 350 "Darken"
+drawText 500 350 "Lighten"
+drawText 0 500 "ColorDodge"
+drawText 100 500 "ColorBurn"
+drawText 200 500 "HardLight"
+drawText 300 500 "SoftLight"
+drawText 400 500 "Difference"
+drawText 500 500 "Exclusion"
diff --git a/tests/baseline/painting/scripts/porter_duff2.qps b/tests/baseline/painting/scripts/porter_duff2.qps
new file mode 100644
index 0000000000..f538371ca1
--- /dev/null
+++ b/tests/baseline/painting/scripts/porter_duff2.qps
@@ -0,0 +1,261 @@
+# Version: 1
+# CheckVsReference: 1% (0 50 600 100)
+# CheckVsReference: 1% (0 200 600 100)
+# CheckVsReference: 1% (0 350 600 100)
+# CheckVsReference: 1% (0 500 600 100)
+
+translate 0 50
+
+surface_begin 0 0 100 100
+
+begin_block predraw
+setRenderHint Antialiasing
+setPen nopen
+gradient_clearStops
+gradient_appendStop 0 efff0000
+gradient_appendStop 0.5 dfffff00
+gradient_appendStop 1 ef00ff00
+
+gradient_setSpread PadSpread
+gradient_setLinear 10 10 90 90
+drawEllipse 10 10 80 80
+end_block
+
+setCompositionMode SourceOver
+
+begin_block postdraw
+
+gradient_clearStops
+gradient_appendStop 0 afff0000
+gradient_appendStop 0.5 cf0000ff
+gradient_appendStop 1 bf00ff00
+
+gradient_setSpread PadSpread
+gradient_setLinear 0 0 100 0
+drawEllipse 10 10 30 30
+drawEllipse 10 60 30 30
+drawEllipse 60 60 30 30
+drawEllipse 60 10 30 30
+drawEllipse 35 35 30 30
+
+# a black rectangle around
+setCompositionMode SourceOver
+setPen black
+setBrush nobrush
+drawRect 0.5 0.5 99 99
+
+end_block
+surface_end
+
+# Destination over
+surface_begin 100 0 100 100
+repeat_block predraw
+setCompositionMode DestinationOver
+repeat_block postdraw
+surface_end
+
+
+# Clear
+surface_begin 200 0 100 100
+repeat_block predraw
+setCompositionMode Clear
+repeat_block postdraw
+surface_end
+
+
+# Source
+surface_begin 300 0 100 100
+repeat_block predraw
+setCompositionMode Source
+repeat_block postdraw
+surface_end
+
+
+# Destination
+surface_begin 400 0 100 100
+repeat_block predraw
+setCompositionMode Destination
+repeat_block postdraw
+surface_end
+
+
+# Source In
+surface_begin 500 0 100 100
+repeat_block predraw
+setCompositionMode SourceIn
+repeat_block postdraw
+surface_end
+
+translate 0 50
+
+# Destination In
+surface_begin 0 100 100 100
+repeat_block predraw
+setCompositionMode DestinationIn
+repeat_block postdraw
+surface_end
+
+
+# Source Out
+surface_begin 100 100 100 100
+repeat_block predraw
+setCompositionMode SourceOut
+repeat_block postdraw
+surface_end
+
+
+# Destination Out
+surface_begin 200 100 100 100
+repeat_block predraw
+setCompositionMode DestinationOut
+repeat_block postdraw
+surface_end
+
+
+# SourceAtop
+surface_begin 300 100 100 100
+repeat_block predraw
+setCompositionMode SourceAtop
+repeat_block postdraw
+surface_end
+
+
+# DestinationAtop
+surface_begin 400 100 100 100
+repeat_block predraw
+setCompositionMode DestinationAtop
+repeat_block postdraw
+surface_end
+
+
+# Xor
+surface_begin 500 100 100 100
+repeat_block predraw
+setCompositionMode Xor
+repeat_block postdraw
+surface_end
+
+translate 0 50
+
+# Plus
+surface_begin 0 200 100 100
+repeat_block predraw
+setCompositionMode Plus
+repeat_block postdraw
+surface_end
+
+
+# Multiply
+surface_begin 100 200 100 100
+repeat_block predraw
+setCompositionMode Multiply
+repeat_block postdraw
+surface_end
+
+
+# Screen
+surface_begin 200 200 100 100
+repeat_block predraw
+setCompositionMode Screen
+repeat_block postdraw
+surface_end
+
+
+# Overlay
+surface_begin 300 200 100 100
+repeat_block predraw
+setCompositionMode Overlay
+repeat_block postdraw
+surface_end
+
+
+# Darken
+surface_begin 400 200 100 100
+repeat_block predraw
+setCompositionMode Darken
+repeat_block postdraw
+surface_end
+
+
+# Lighten
+surface_begin 500 200 100 100
+repeat_block predraw
+setCompositionMode Lighten
+repeat_block postdraw
+surface_end
+
+translate 0 50
+
+# ColorDodge
+surface_begin 0 300 100 100
+repeat_block predraw
+setCompositionMode ColorDodge
+repeat_block postdraw
+surface_end
+
+
+# ColorBurn
+surface_begin 100 300 100 100
+repeat_block predraw
+setCompositionMode ColorBurn
+repeat_block postdraw
+surface_end
+
+
+# HardLight
+surface_begin 200 300 100 100
+repeat_block predraw
+setCompositionMode HardLight
+repeat_block postdraw
+surface_end
+
+
+# SoftLight
+surface_begin 300 300 100 100
+repeat_block predraw
+setCompositionMode SoftLight
+repeat_block postdraw
+surface_end
+
+
+# Difference
+surface_begin 400 300 100 100
+repeat_block predraw
+setCompositionMode Difference
+repeat_block postdraw
+surface_end
+
+
+# Exclusion
+surface_begin 500 300 100 100
+repeat_block predraw
+setCompositionMode Exclusion
+repeat_block postdraw
+surface_end
+
+resetMatrix
+
+drawText 0 50 "SourceOver"
+drawText 100 50 "DestinationOver"
+drawText 200 50 "Clear"
+drawText 300 50 "Source"
+drawText 400 50 "Destination"
+drawText 500 50 "SourceIn"
+drawText 0 200 "DestinationIn"
+drawText 100 200 "SourceOut"
+drawText 200 200 "DestinationOut"
+drawText 300 200 "SourceAtop"
+drawText 400 200 "DestinationAtop"
+drawText 500 200 "Xor"
+drawText 0 350 "Plus"
+drawText 100 350 "Multiply"
+drawText 200 350 "Screen"
+drawText 300 350 "Overlay"
+drawText 400 350 "Darken"
+drawText 500 350 "Lighten"
+drawText 0 500 "ColorDodge"
+drawText 100 500 "ColorBurn"
+drawText 200 500 "HardLight"
+drawText 300 500 "SoftLight"
+drawText 400 500 "Difference"
+drawText 500 500 "Exclusion"
diff --git a/tests/baseline/painting/scripts/primitives.qps b/tests/baseline/painting/scripts/primitives.qps
new file mode 100644
index 0000000000..f44ba27566
--- /dev/null
+++ b/tests/baseline/painting/scripts/primitives.qps
@@ -0,0 +1,184 @@
+# Version: 1#Version: 1
+# CheckVsReference: 5%
+
+
+# CheckVsReference: 5%
+
+setBrush #ff7f7fff
+setPen black 1 solidline
+translate 20 20
+begin_block testblock
+save
+drawRect 0 0 10 10
+drawRect 20 0 20 10
+drawRect 0 20 10 20
+drawRect 20 20 20 20
+translate 50 0
+setPen NoPen
+drawRect 0 0 10 10
+drawRect 20 0 20 10
+drawRect 0 20 10 20
+drawRect 20 20 20 20
+restore
+save
+translate 0 50
+drawEllipse 0 0 10 10
+drawEllipse 20 0 20 10
+drawEllipse 0 20 10 20
+drawEllipse 20 20 20 20
+translate 50 0
+setPen NoPen
+drawEllipse 0 0 10 10
+drawEllipse 20 0 20 10
+drawEllipse 0 20 10 20
+drawEllipse 20 20 20 20
+restore
+save
+translate 0 100
+drawPolygon [ 0 0 30 0 30 30 10 30 10 10 40 10 40 40 0 40 ]
+save
+translate 0 50
+drawPolygon [ 0 0 30 0 30 30 10 30 10 10 40 10 40 40 0 40 ] Winding
+translate 0 45
+drawPolyline [ 0 0 50 0 25 25 ]
+restore
+setPen NoPen
+translate 50 0
+drawPolygon [ 0 0 30 0 30 30 10 30 10 10 40 10 40 40 0 40 ]
+save
+translate 0 50
+drawPolygon [ 0 0 30 0 30 30 10 30 10 10 40 10 40 40 0 40 ] Winding
+restore
+save
+translate -20 100
+drawPie 0 0 50 50 0 1500
+restore
+restore
+end_block
+setPen black 1 SolidLine FlatCap
+translate 200 0
+scale 2 1
+rotate 10
+repeat_block testblock
+resetMatrix
+translate 0 250
+setBrush 7f7f7fff
+translate 20 20
+repeat_block testblock
+setPen black 1 SolidLine FlatCap
+translate 200 0
+scale 2 1
+rotate 10
+repeat_block testblock
+resetMatrix
+save
+setRenderHint LineAntialiasing
+setBrush 7f7fff
+translate 20 500
+repeat_block testblock
+translate 200 0
+scale 2 1
+rotate 10
+repeat_block testblock
+restore
+setRenderHint LineAntialiasing false
+translate 420 20
+begin_block lines
+drawLine 0 0 100 0
+drawLine 0 0 100 10
+drawLine 0 0 100 20
+drawLine 0 0 100 30
+drawLine 0 0 100 40
+drawLine 0 0 100 50
+drawLine 0 0 100 60
+drawLine 0 0 100 70
+drawLine 0 0 100 80
+drawLine 0 0 100 90
+drawLine 0 0 100 100
+drawLine 0 0 90 100
+drawLine 0 0 80 100
+drawLine 0 0 70 100
+drawLine 0 0 60 100
+drawLine 0 0 50 100
+drawLine 0 0 40 100
+drawLine 0 0 30 100
+drawLine 0 0 20 100
+drawLine 0 0 10 100
+drawLine 0 0 0 100
+end_block
+setRenderHint LineAntialiasing
+translate 0 120
+repeat_block lines
+translate 0 120
+scale 5 2
+repeat_block lines
+resetMatrix
+translate 420 500
+begin_block roundedrects
+save
+drawRoundedRect 0 0 50 30 5 5
+translate 60 0
+drawRoundedRect 0 0 50 30 7.5 7.5
+translate 60 0
+drawRoundedRect 0 0 50 30 10 10
+translate 60 0
+drawRoundedRect 0 0 50 30 12.5 12.5
+translate 60 0
+drawRoundedRect 0 0 50 30 15 15
+restore
+save
+translate 0 40
+drawRoundedRect 0 0 50 30 20 20 RelativeSize
+translate 60 0
+drawRoundedRect 0 0 50 30 40 40 RelativeSize
+translate 60 0
+drawRoundedRect 0 0 50 30 60 60 RelativeSize
+translate 60 0
+drawRoundedRect 0 0 50 30 80 80 RelativeSize
+translate 60 0
+drawRoundedRect 0 0 50 30 100 100 RelativeSize
+restore
+end_block
+translate 0.5 80.5
+repeat_block roundedrects
+translate -0.5 79.5
+setRenderHint Antialiasing off
+repeat_block roundedrects
+resetMatrix
+setRenderHint Antialiasing off
+setPen black 1
+begin_block drawShapes
+translate 550.5 25
+rotate 45
+setBrush nobrush
+drawEllipse -10 -10 20 20
+drawLine 10 0 50 0
+drawRect 50 -7 14 14
+resetMatrix
+end_block
+setPen black 2
+translate 25 0
+repeat_block drawShapes
+setPen black 3
+translate 50 0
+repeat_block drawShapes
+setPen black 4
+translate 75 0
+repeat_block drawShapes
+resetMatrix
+setRenderHint Antialiasing off
+setPen nopen
+translate 550 100
+setBrush #7f7f7fff
+drawRect -0.5 -0.5 21 21
+setBrush red
+drawEllipse 0 0 20 20
+setBrush nobrush
+setPen black
+drawEllipse 0 0 20 20
+translate 25 0
+setPen nopen
+setBrush #7f7f7fff
+drawRect 0 0 20 20
+setBrush red
+drawEllipse 0 0 20 20 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/radial_gradients.qps b/tests/baseline/painting/scripts/radial_gradients.qps
new file mode 100644
index 0000000000..b55df8bde6
--- /dev/null
+++ b/tests/baseline/painting/scripts/radial_gradients.qps
@@ -0,0 +1,99 @@
+# Version: 1
+# CheckVsReference: 5% (0 0 600 400)
+
+path_addRect path 400 0 80 80
+path_addEllipse path 440 40 60 60
+
+setRenderHint Antialiasing
+
+setPen black
+
+begin_block gradients
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setRadial 20 20 50 40 40
+drawRect 0 0 100 100
+
+gradient_setSpread ReflectSpread
+gradient_setRadial 120 20 50 140 40
+drawEllipse 100 0 100 100
+
+gradient_setSpread RepeatSpread
+gradient_setRadial 220 20 50 240 40
+drawRoundRect 200 0 100 100
+
+gradient_clearStops
+gradient_appendStop 0 3f7f7fff
+gradient_appendStop 0.5 dfdfffff
+gradient_appendStop 1 7f00007f
+
+gradient_setSpread PadSpread
+gradient_setRadial 320 20 50 340 40
+drawPolygon [300 0 390 0 350 99]
+
+gradient_setSpread ReflectSpread
+gradient_setRadial 420 20 50 440 40
+drawPath path
+
+gradient_setSpread RepeatSpread
+gradient_setRadial 520 20 50 540 40
+drawPie 500 0 100 100 720 4320
+end_block
+
+translate 0 100
+scale 1 2
+repeat_block gradients
+
+resetMatrix
+translate 0 300
+brushTranslate 30 0
+brushScale 0.9 0.9
+brushRotate 20
+repeat_block gradients
+
+# Some helpful info perhaps?
+resetMatrix
+setPen black
+
+drawText 610 50 "No XForm"
+drawText 610 200 "scale 1x2"
+drawText 610 300 "brush transform"
+drawText 10 450 "Pad"
+drawText 110 450 "Reflect"
+drawText 210 450 "Repeat"
+drawText 310 450 "Pad w/alpha"
+drawText 410 450 "Reflect w/alpha"
+drawText 510 450 "Repeat w/alpha"
+
+# Radius and focal indicators
+setPen 3f000000
+setBrush nobrush
+
+begin_block ellipse_draw
+setClipRect 0 0 100 100
+drawEllipse -30 -30 100 100
+drawEllipse 35 35 11 11
+translate 100 0
+end_block
+
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+
+resetMatrix
+translate 0 100
+scale 1 2
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/radial_gradients_perspectives.qps b/tests/baseline/painting/scripts/radial_gradients_perspectives.qps
new file mode 100644
index 0000000000..4557354dce
--- /dev/null
+++ b/tests/baseline/painting/scripts/radial_gradients_perspectives.qps
@@ -0,0 +1,62 @@
+# Version: 1
+
+
+setRenderHint Antialiasing
+
+setPen #00ff00
+
+translate 10 10
+# standard draw
+begin_block gradient
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setRadial 110 100 230 230 240
+drawRect 0 0 300 300
+end_block gradient
+
+# Rotation w/o smooth xform
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 50 0 200 300 300 300 0
+ repeat_block gradient
+restore
+restore
+
+translate 0 320
+
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 100 300 200 300 300 0
+ repeat_block gradient
+restore
+
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 0 300 300 250 300 50
+ repeat_block gradient
+restore
+restore
+
+
+resetMatrix
+setPen black
+translate 125 20
+drawText 0 0 "No transform"
+translate 350 0
+drawText 0 0 "Left Tilted"
+resetMatrix
+translate 125 350
+drawText 0 0 "Bottom Tilted"
+translate 350 0
+drawText 0 0 "Right Tilted"
+translate 120 0 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/rasterops.qps b/tests/baseline/painting/scripts/rasterops.qps
new file mode 100644
index 0000000000..d0f2da42df
--- /dev/null
+++ b/tests/baseline/painting/scripts/rasterops.qps
@@ -0,0 +1,87 @@
+# Version: 1
+# CheckVsReference: 5%
+
+setPen NoPen
+
+setBrush black
+drawRect 10 10 60 500
+
+setCompositionMode SourceOrDestination
+translate 20 20
+
+begin_block drawShape
+ setBrush 0xffff0000
+ drawEllipse 5 5 30 30
+ setBrush 0xff00ff00
+ drawRect 0 0 20 20
+ setBrush 0xff0000ff
+ drawRect 20 20 20 20
+end_block
+
+begin_block loop
+ setCompositionMode SourceAndDestination
+ translate 0 50
+repeat_block drawShape
+
+setCompositionMode SourceXorDestination
+translate 0 50
+repeat_block drawShape
+
+setCompositionMode NotSourceAndNotDestination
+translate 0 50
+repeat_block drawShape
+
+setCompositionMode NotSourceOrNotDestination
+translate 0 50
+repeat_block drawShape
+
+setCompositionMode NotSourceXorDestination
+translate 0 50
+repeat_block drawShape
+
+setCompositionMode NotSource
+translate 0 50
+repeat_block drawShape
+
+setCompositionMode NotSourceAndDestination
+translate 0 50
+repeat_block drawShape
+
+setCompositionMode SourceAndNotDestination
+translate 0 50
+repeat_block drawShape
+end_block
+
+resetMatrix
+setCompositionMode Source
+setBrush white
+drawRect 100 10 60 500
+translate 110 20
+repeat_block loop
+
+resetMatrix
+setCompositionMode Source
+translate 190 20
+repeat_block loop
+
+resetMatrix
+setPen black
+setCompositionMode SourceOver
+translate 250 45
+drawText 20 0 "Or ROP"
+translate 0 50
+drawText 20 0 "And ROP"
+translate 0 50
+drawText 20 0 "Xor ROP"
+translate 0 50
+drawText 20 0 "Nor ROP"
+translate 0 50
+drawText 20 0 "Nand ROP"
+translate 0 50
+drawText 0 0 "NSrcXorDst ROP"
+translate 0 50
+drawText 20 0 "NSrc ROP"
+translate 0 50
+drawText 0 0 "NSrcAndDst ROP"
+translate 0 50
+drawText 0 0 "SrcAndNDst ROP" \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/richtext.qps b/tests/baseline/painting/scripts/richtext.qps
new file mode 100644
index 0000000000..787c97421b
--- /dev/null
+++ b/tests/baseline/painting/scripts/richtext.qps
@@ -0,0 +1,9 @@
+drawTextDocument 10 10 "<img height=50 width=50 align=top src=:/images/border.png /><img height=10 width=10 valign=bottom src=:/images/border.png /><span style='font-size: 100px'>Xy</span>"
+drawTextDocument 10 210 "<img height=50 width=50 align=top src=:/images/border.png /><img height=10 width=10 valign=bottom src=:/images/border.png /><span style='font-size: 25px'>Xy</span>"
+drawTextDocument 310 210 "<img height=10 width=10 align=top src=:/images/border.png /><img height=50 width=50 valign=bottom src=:/images/border.png /><span style='font-size: 25px'>Xy</span>"
+drawTextDocument 10 310 "<img height=50 width=50 align=top src=:/images/border.png /><img height=50 width=50 valign=bottom src=:/images/border.png /><span style='font-size: 25px'>Xy</span>"
+
+drawTextDocument 10 410 "<img height=10 width=10 align=top src=:/images/border.png /><img height=50 width=50 src=:/images/border.png /><span style='font-size: 25px'>Xy</span>"
+drawTextDocument 10 510 "<img height=10 width=10 valign=bottom src=:/images/border.png /><img height=50 width=50 src=:/images/border.png /><span style='font-size: 25px'>Xy</span>"
+drawTextDocument 310 410 "<img height=50 width=50 align=top src=:/images/border.png /><img height=10 width=10 src=:/images/border.png /><span style='font-size: 25px'>Xy</span>"
+drawTextDocument 310 510 "<img height=50 width=50 valign=bottom src=:/images/border.png /><img height=10 width=10 src=:/images/border.png /><span style='font-size: 25px'>Xy</span>"
diff --git a/tests/baseline/painting/scripts/sizes.qps b/tests/baseline/painting/scripts/sizes.qps
new file mode 100644
index 0000000000..12b0f4af1e
--- /dev/null
+++ b/tests/baseline/painting/scripts/sizes.qps
@@ -0,0 +1,90 @@
+# Version: 1
+# CheckVsReference: 5%
+
+setPen NoPen
+setBrush black
+
+translate 10 10
+
+begin_block testblock
+drawRect 0 0 10 10
+drawRect 20 0 11 11
+drawRect 40 0 12 12
+drawRect 60 0 13 13
+drawRect 80 0 14 14
+drawRect 100 0 15 15
+drawRect 120 0 16 16
+drawRect 140 0 17 17
+drawRect 160 0 18 18
+drawRect 180 0 19 19
+
+drawEllipse 0 20 10 10
+drawEllipse 20 20 11 11
+drawEllipse 40 20 12 12
+drawEllipse 60 20 13 13
+drawEllipse 80 20 14 14
+drawEllipse 100 20 15 15
+drawEllipse 120 20 16 16
+drawEllipse 140 20 17 17
+drawEllipse 160 20 18 18
+drawEllipse 180 20 19 19
+
+drawRoundRect 0 40 10 10
+drawRoundRect 20 40 11 11
+drawRoundRect 40 40 12 12
+drawRoundRect 60 40 13 13
+drawRoundRect 80 40 14 14
+drawRoundRect 100 40 15 15
+drawRoundRect 120 40 16 16
+drawRoundRect 140 40 17 17
+drawRoundRect 160 40 18 18
+drawRoundRect 180 40 19 19
+
+drawPie 0 60 10 10 0 4320
+drawPie 20 60 11 11 0 4320
+drawPie 40 60 12 12 0 4320
+drawPie 60 60 13 13 0 4320
+drawPie 80 60 14 14 0 4320
+drawPie 100 60 15 15 0 4320
+drawPie 120 60 16 16 0 4320
+drawPie 140 60 17 17 0 4320
+drawPie 160 60 18 18 0 4320
+drawPie 180 60 19 19 0 4320
+
+drawArc 0 80 10 10 0 4320
+drawArc 20 80 11 11 0 4320
+drawArc 40 80 12 12 0 4320
+drawArc 60 80 13 13 0 4320
+drawArc 80 80 14 14 0 4320
+drawArc 100 80 15 15 0 4320
+drawArc 120 80 16 16 0 4320
+drawArc 140 80 17 17 0 4320
+drawArc 160 80 18 18 0 4320
+drawArc 180 80 19 19 0 4320
+
+drawChord 0 100 10 10 0 4320
+drawChord 20 100 11 11 0 4320
+drawChord 40 100 12 12 0 4320
+drawChord 60 100 13 13 0 4320
+drawChord 80 100 14 14 0 4320
+drawChord 100 100 15 15 0 4320
+drawChord 120 100 16 16 0 4320
+drawChord 140 100 17 17 0 4320
+drawChord 160 100 18 18 0 4320
+drawChord 180 100 19 19 0 4320
+
+end_block
+
+setPen red
+translate 0 150
+repeat_block testblock
+
+setRenderHint LineAntialiasing
+
+setPen nopen
+translate 0 150
+repeat_block testblock
+
+setPen red
+translate 0 150
+repeat_block testblock
diff --git a/tests/baseline/painting/scripts/smallcaps_path.qps b/tests/baseline/painting/scripts/smallcaps_path.qps
new file mode 100644
index 0000000000..4e89b50d96
--- /dev/null
+++ b/tests/baseline/painting/scripts/smallcaps_path.qps
@@ -0,0 +1,9 @@
+# Version: 1
+
+setPen black 1
+setBrush 7f7fff
+
+setFont "times" 50 Light false Default false false false SmallCaps
+path_addText text 0 50 "Hello Qt"
+
+drawPath text
diff --git a/tests/baseline/painting/scripts/statictext.qps b/tests/baseline/painting/scripts/statictext.qps
new file mode 100644
index 0000000000..c2a30d0864
--- /dev/null
+++ b/tests/baseline/painting/scripts/statictext.qps
@@ -0,0 +1,175 @@
+drawStaticText -5 5 "Text that is drawn outside the bounds..."
+
+translate 20 20
+begin_block text_drawing
+save
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawStaticText 0 60 "sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "sansserif 10pt, bold italic"
+
+
+ translate 0 100
+ setPen #7fff0000
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "alpha sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "alpha sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawStaticText 0 60 "alpha sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "alpha sansserif 10pt, bold italic"
+
+
+ translate 0 100
+ setPen black
+ save
+ scale 0.9 0.9
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "scaled sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "scaled sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawStaticText 0 60 "scaled sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "scaled sansserif 10pt, bold italic"
+ restore
+
+ translate 200 200
+ setPen black
+ save
+ scale -1 -1
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "flipped sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "flipped sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawStaticText 0 60 "flipped sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "flipped sansserif 10pt, bold italic"
+ restore
+
+ translate -200 20
+ setPen black
+ save
+ translate 200 90
+ rotate 185
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "rotated sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "rotated sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawStaticText 0 60 "rotated sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "rotated sansserif 10pt, bold italic"
+ restore
+
+ translate 0 100
+ gradient_appendStop 0 red
+ gradient_appendStop 0.5 #00ff00
+ gradient_appendStop 1 blue
+ gradient_setLinear 0 0 200 0
+ setPen brush
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 0 "gradient sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 20 "gradient sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawStaticText 0 40 "gradient sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 60 "gradient sansserif 10pt, bold italic"
+restore
+end_block
+
+translate 250 0
+drawStaticText 25 640 "clipped to rectangle"
+save
+ setPen #3f000000
+ setBrush nobrush
+ drawRect 20 0 100 620
+ setClipRect 20 0 100 620
+ setPen black
+ repeat_block text_drawing
+restore
+
+translate 150 0
+drawStaticText 25 640 "clipped to path"
+save
+ path_moveTo clip 20 0
+ path_cubicTo clip 0 200 40 400 20 400
+ path_lineTo clip 30 620
+ path_lineTo clip 30 0
+ path_lineTo clip 40 0
+ path_lineTo clip 40 620
+ path_lineTo clip 120 620
+ path_lineTo clip 120 0
+ path_lineTo clip 20 0
+ setPen #3f000000
+ setBrush nobrush
+ drawPath clip
+ setClipPath clip
+ setPen black
+ repeat_block text_drawing
+restore
+
+translate 150 0
+save
+ setPen black
+ setFont "sansserif" 16 normal
+ drawStaticText 0 40 "e😃m😇o😍j😜i😸!"
+restore
+
+translate 0 55
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default underline
+ drawStaticText 0 20 "Underlined text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default normal strikeout
+ drawStaticText 0 20 "Struck out text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default normal normal overline
+ drawStaticText 0 20 "Overlined text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default underline strikeout overline
+ drawStaticText 0 20 "All the effects text drawing"
+restore
diff --git a/tests/baseline/painting/scripts/text.qps b/tests/baseline/painting/scripts/text.qps
new file mode 100644
index 0000000000..4d81b3084c
--- /dev/null
+++ b/tests/baseline/painting/scripts/text.qps
@@ -0,0 +1,199 @@
+# Version: 1
+
+drawText -5 5 "Text that is drawn outside the bounds..."
+
+translate 20 20
+begin_block text_drawing
+save
+ setFont "sansserif" 10 normal
+ drawText 0 20 "sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawText 0 40 "sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawText 0 60 "sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawText 0 80 "sansserif 10pt, bold italic"
+
+
+ translate 0 100
+ setPen #7fff0000
+
+ setFont "sansserif" 10 normal
+ drawText 0 20 "alpha sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawText 0 40 "alpha sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawText 0 60 "alpha sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawText 0 80 "alpha sansserif 10pt, bold italic"
+
+
+ translate 0 100
+ setPen black
+ save
+ scale 0.9 0.9
+
+ setFont "sansserif" 10 normal
+ drawText 0 20 "scaled sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawText 0 40 "scaled sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawText 0 60 "scaled sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawText 0 80 "scaled sansserif 10pt, bold italic"
+ restore
+
+ translate 200 200
+ setPen black
+ save
+ scale -1 -1
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "flipped sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "flipped sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawStaticText 0 60 "flipped sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "flipped sansserif 10pt, bold italic"
+ restore
+
+ translate -200 20
+ setPen black
+ save
+ translate 200 90
+ rotate 185
+
+ setFont "sansserif" 10 normal
+ drawText 0 20 "rotated sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawText 0 40 "rotated sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawText 0 60 "rotated sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawText 0 80 "rotated sansserif 10pt, bold italic"
+ restore
+
+ translate 0 100
+ gradient_appendStop 0 red
+ gradient_appendStop 0.5 #00ff00
+ gradient_appendStop 1 blue
+ gradient_setLinear 0 0 200 0
+ setPen brush
+
+ setFont "sansserif" 10 normal
+ drawText 0 0 "gradient sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawText 0 20 "gradient sansserif 12pt, normal"
+
+ setFont "sansserif" 12 bold
+ drawText 0 40 "gradient sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawText 0 60 "gradient sansserif 10pt, bold italic"
+restore
+end_block
+
+translate 250 0
+drawText 25 640 "clipped to rectangle"
+save
+ setPen #3f000000
+ setBrush nobrush
+ drawRect 20 0 100 620
+ setClipRect 20 0 100 620
+ setPen black
+ repeat_block text_drawing
+restore
+
+translate 150 0
+drawText 25 640 "clipped to path"
+save
+ path_moveTo clip 20 0
+ path_cubicTo clip 0 200 40 400 20 400
+ path_lineTo clip 30 620
+ path_lineTo clip 30 0
+ path_lineTo clip 40 0
+ path_lineTo clip 40 620
+ path_lineTo clip 120 620
+ path_lineTo clip 120 0
+ path_lineTo clip 20 0
+ setPen #3f000000
+ setBrush nobrush
+ drawPath clip
+ setClipPath clip
+ setPen black
+ repeat_block text_drawing
+restore
+
+translate 150 0
+save
+ setPen black
+ setFont "sansserif" 10 normal
+ drawText 0 20 "testing glyph cache textures"
+
+ # Important that this gradient doesn't match any earlier
+ # gradients, so that it's not cached from before.
+ gradient_clearStops
+ gradient_appendStop 0 blue
+ gradient_appendStop 0.5 #00ff00
+ gradient_appendStop 1 red
+ gradient_setLinear 0 0 100 0
+ setPen nopen
+ drawRect 0 30 100 20
+
+ setPen black
+ drawText 0 70 "testing glyph cache textures"
+restore
+
+translate 0 75
+save
+ setPen black
+ setFont "sansserif" 16 normal
+ drawText 0 40 "e😃m😇o😍j😜i😸!"
+restore
+
+translate 0 75
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default underline
+ drawText 0 20 "Underlined text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default normal strikeout
+ drawText 0 20 "Struck out text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default normal normal overline
+ drawText 0 20 "Overlined text drawing"
+restore
+
+translate 0 35
+save
+ setPen black
+ setFont "sansserif" 12 normal normal default underline strikeout overline
+ drawText 0 20 "All the effects text drawing"
+restore
+
+
diff --git a/tests/baseline/painting/scripts/text_perspectives.qps b/tests/baseline/painting/scripts/text_perspectives.qps
new file mode 100644
index 0000000000..4c74306265
--- /dev/null
+++ b/tests/baseline/painting/scripts/text_perspectives.qps
@@ -0,0 +1,102 @@
+# Version: 1
+
+
+setRenderHint Antialiasing
+
+setPen black
+
+translate 10 10
+# standard draw
+begin_block text
+setBrush gray
+drawRect 0 0 300 300
+
+setFont "times" 3
+drawText 10 10 "Hello World...."
+
+setFont "times" 4
+drawText 10 20 "Hello World...."
+
+setFont "times" 5
+drawText 10 30 "Hello World...."
+
+setFont "times" 6
+drawText 10 40 "Hello World...."
+
+setFont "times" 7
+drawText 10 50 "Hello World...."
+
+setFont "times" 8
+drawText 10 60 "Hello World...."
+
+setFont "times" 9
+drawText 10 70 "Hello World...."
+
+setFont "times" 10
+drawText 10 80 "Hello World...."
+
+setFont "times" 16
+drawText 10 100 "Hello World...."
+
+setFont "times" 17
+drawText 10 120 "Hello World...."
+
+setFont "times" 18
+drawText 10 140 "Hello World...."
+
+setFont "times" 20
+drawText 10 160 "Hello World...."
+
+setFont "times" 22
+drawText 10 180 "Hello World...."
+
+setFont "times" 24
+drawText 10 205 "Hello World...."
+
+setFont "times" 26
+drawText 10 230 "Hello World...."
+
+setFont "times" 32
+drawText 10 260 "Hello World...."
+end_block text
+
+# Rotation w/o smooth xform
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 50 0 200 300 300 300 0
+ repeat_block text
+restore
+restore
+
+translate 0 320
+
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 100 300 200 300 300 0
+ repeat_block text
+restore
+
+save
+translate 350 0
+save
+ setRenderHint SmoothPixmapTransform on
+ mapQuadToQuad 0 0 0 300 300 300 300 0 0 0 0 300 300 250 300 50
+ repeat_block text
+restore
+restore
+
+
+resetMatrix
+setPen black
+translate 125 20
+drawText 0 0 "No transform"
+translate 350 0
+drawText 0 0 "Left Tilted"
+resetMatrix
+translate 125 350
+drawText 0 0 "Bottom Tilted"
+translate 350 0
+drawText 0 0 "Right Tilted"
+translate 120 0 \ No newline at end of file
diff --git a/tests/baseline/painting/scripts/thinlines.qps b/tests/baseline/painting/scripts/thinlines.qps
new file mode 100644
index 0000000000..dddfff4538
--- /dev/null
+++ b/tests/baseline/painting/scripts/thinlines.qps
@@ -0,0 +1,79 @@
+# Version: 1
+# CheckVsReference: 5%
+
+drawRect 0 0 800 800
+
+path_addRect p 0 0 75 75
+path_addEllipse p 25 25 75 75
+
+translate -500 -500
+
+begin_block drawing
+ save
+ drawLine 0 0 100 100
+
+ translate 0 100
+ drawPath p
+
+ translate 0 110
+ drawRect 0 0 100 100
+
+ translate 0 110
+ drawPolyline [0 0 100 0 50 50]
+
+ drawPoint 40 40
+ drawPoint 41 40
+ drawPoint 42 40
+ drawPoint 43 40
+ drawPoint 44 40
+ drawPoint 45 40
+ drawPoint 46 40
+ drawPoint 47 40
+ drawPoint 48 40
+ drawPoint 49 40
+ drawPoint 50 40
+
+ restore
+end_block
+
+begin_block univsnonuni
+ save
+
+ save
+ scale 0.7 0.7
+ repeat_block drawing
+ restore
+
+ translate 100 0
+ save
+ scale 0.7 0.8
+ repeat_block drawing
+ restore
+
+ restore
+end_block
+
+resetMatrix
+translate 20.5 20.5
+
+begin_block row
+save
+ repeat_block univsnonuni
+
+ translate 240 0
+ save
+ rotate 10
+ repeat_block univsnonuni
+ restore
+
+ translate 220 0
+ save
+ rotate_y 30
+ repeat_block univsnonuni
+ restore
+restore
+end_block
+
+translate 0 320
+setRenderHint AntiAliasing
+repeat_block row
diff --git a/tests/baseline/painting/scripts/tiled_pixmap.qps b/tests/baseline/painting/scripts/tiled_pixmap.qps
new file mode 100644
index 0000000000..0ce3a7834c
--- /dev/null
+++ b/tests/baseline/painting/scripts/tiled_pixmap.qps
@@ -0,0 +1,84 @@
+# Version: 1
+# CheckVsReference: 5% (0 0 639 638)
+
+
+translate 0 10
+setRenderHint Antialiasing
+
+pixmap_load dome_argb32 the_pixmap
+
+begin_block draw_stuff
+save
+
+ # Standard draw
+ drawTiledPixmap the_pixmap 0 0 150 100 0 0
+
+ # Standard draw with offset
+ translate 160 0
+ drawTiledPixmap the_pixmap 0 0 150 100 25 25
+
+ # xformed
+ translate 160 0
+ save
+ translate 10 -10
+ rotate 10
+ setRenderHint SmoothPixmapTransform false
+ drawTiledPixmap the_pixmap 0 0 150 100 25 25
+ restore
+
+ # xformed with smooth xform
+ translate 160 0
+ save
+ translate 10 -10
+ rotate 10
+ setRenderHint SmoothPixmapTransform
+ drawTiledPixmap the_pixmap 0 0 150 100 25 25
+ restore
+restore
+end_block
+
+translate 0 120
+pixmap_load dome_rgb32 the_pixmap
+repeat_block draw_stuff
+
+
+translate 0 120
+pixmap_load dome_indexed the_pixmap
+repeat_block draw_stuff
+
+
+translate 0 120
+pixmap_load dome_indexed_mask the_pixmap
+repeat_block draw_stuff
+
+
+translate 0 120
+pixmap_load dome_mono the_pixmap
+repeat_block draw_stuff
+
+
+################################################################################
+# Some helpful text...
+#
+
+resetMatrix
+translate 650 80
+drawText 0 0 "32 bit w/alpha"
+translate 0 120
+drawText 0 0 "32 bit w/o alpha"
+translate 0 120
+drawText 0 0 "8 bit indexed"
+translate 0 120
+drawText 0 0 "8 bit indexed w/mask"
+translate 0 120
+drawText 0 0 "1 bit"
+
+resetMatrix
+translate 10 630
+drawText 0 0 "normal"
+translate 160 0
+drawText 0 0 "offset"
+translate 160 0
+drawText 0 0 "xformed"
+translate 160 0
+drawText 0 0 "smooth xformed"
diff --git a/tests/baseline/painting/scripts/tinydashes.qps b/tests/baseline/painting/scripts/tinydashes.qps
new file mode 100644
index 0000000000..d41ced7f5f
--- /dev/null
+++ b/tests/baseline/painting/scripts/tinydashes.qps
@@ -0,0 +1,34 @@
+# Version: 1
+# CheckVsReference: 5%
+
+path_addEllipse mypath 20.0 20.0 200.0 200.0
+
+save
+setPen blue 20 SolidLine FlatCap
+pen_setCosmetic true
+pen_setDashPattern [ 0.0004 0.0004 ]
+setBrush yellow
+
+drawPath mypath
+translate 300 0
+setRenderHint Antialiasing true
+drawPath mypath
+restore
+
+path_addEllipse bigpath 200000.0 200000.0 2000000.0 2000000.0
+
+setPen blue 20 DotLine FlatCap
+setBrush yellow
+
+save
+translate 0 300
+scale 0.0001 0.00011
+drawPath bigpath
+restore
+
+save
+translate 300 300
+setRenderHint Antialiasing true
+scale 0.0001 0.00011
+drawPath bigpath
+restore
diff --git a/tests/baseline/painting/tst_baseline_painting.cpp b/tests/baseline/painting/tst_baseline_painting.cpp
new file mode 100644
index 0000000000..a5d787f6ce
--- /dev/null
+++ b/tests/baseline/painting/tst_baseline_painting.cpp
@@ -0,0 +1,489 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "paintcommands.h"
+#include <qbaselinetest.h>
+#include <QDir>
+#include <QPainter>
+#include <QPdfWriter>
+#include <QTemporaryFile>
+#if QT_CONFIG(process)
+#include <QProcess>
+#endif
+
+#ifndef QT_NO_OPENGL
+#include <QOpenGLFramebufferObjectFormat>
+#include <QOpenGLContext>
+#include <QOpenGLPaintDevice>
+#endif
+
+#include <algorithm>
+
+#ifndef GL_RGB10
+#define GL_RGB10 0x8052
+#endif
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2 0x8059
+#endif
+
+class tst_Lancelot : public QObject
+{
+Q_OBJECT
+
+public:
+ tst_Lancelot();
+
+private:
+ enum GraphicsEngine {
+ Raster = 0,
+ OpenGL = 1,
+ Pdf = 2
+ };
+
+ void setupTestSuite(const QStringList& blacklist = QStringList());
+ void runTestSuite(GraphicsEngine engine, QImage::Format format, const QSurfaceFormat &contextFormat = QSurfaceFormat());
+ void paint(QPaintDevice *device, GraphicsEngine engine, QImage::Format format, const QStringList &script, const QString &filePath);
+
+ QStringList qpsFiles;
+ QHash<QString, QStringList> scripts;
+ QHash<QString, quint16> scriptChecksums;
+ QString scriptsDir;
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase() {}
+
+ void testRasterARGB32PM_data();
+ void testRasterARGB32PM();
+ void testRasterRGB32_data();
+ void testRasterRGB32();
+ void testRasterARGB32_data();
+ void testRasterARGB32();
+ void testRasterRGB16_data();
+ void testRasterRGB16();
+ void testRasterA2RGB30PM_data();
+ void testRasterA2RGB30PM();
+ void testRasterBGR30_data();
+ void testRasterBGR30();
+ void testRasterARGB8565PM_data();
+ void testRasterARGB8565PM();
+ void testRasterGrayscale8_data();
+ void testRasterGrayscale8();
+ void testRasterRGBA64PM_data();
+ void testRasterRGBA64PM();
+ void testRasterRGBA16F_data();
+ void testRasterRGBA16F();
+ void testRasterRGBA32FPM_data();
+ void testRasterRGBA32FPM();
+
+ void testPdf_data();
+ void testPdf();
+
+#ifndef QT_NO_OPENGL
+ void testOpenGL_data();
+ void testOpenGL();
+ void testOpenGLBGR30_data();
+ void testOpenGLBGR30();
+ void testCoreOpenGL_data();
+ void testCoreOpenGL();
+private:
+ bool checkSystemGLSupport();
+ bool checkSystemCoreGLSupport();
+#endif
+};
+
+tst_Lancelot::tst_Lancelot()
+{
+}
+
+void tst_Lancelot::initTestCase()
+{
+ // Check and setup the environment. We treat failures because of test environment
+ // (e.g. script files not found) as just warnings, and not QFAILs, to avoid false negatives
+ // caused by environment or server instability
+
+ QByteArray msg;
+ if (!QBaselineTest::connectToBaselineServer(&msg))
+ QSKIP(msg);
+
+ QString baseDir = QFINDTESTDATA("scripts/text.qps");
+ scriptsDir = baseDir.left(baseDir.lastIndexOf('/')) + '/';
+ QDir qpsDir(scriptsDir);
+ qpsFiles = qpsDir.entryList(QStringList() << QLatin1String("*.qps"), QDir::Files | QDir::Readable);
+ if (qpsFiles.isEmpty()) {
+ qWarning() << "No qps script files found in" << qpsDir.path();
+ QSKIP("Aborted due to errors.");
+ }
+
+ std::sort(qpsFiles.begin(), qpsFiles.end());
+ foreach (const QString& fileName, qpsFiles) {
+ QFile file(scriptsDir + fileName);
+ file.open(QFile::ReadOnly);
+ QByteArray cont = file.readAll();
+ scripts.insert(fileName, QString::fromUtf8(cont).split(QLatin1Char('\n'), Qt::SkipEmptyParts));
+ scriptChecksums.insert(fileName, qChecksum(cont));
+ }
+}
+
+
+void tst_Lancelot::testRasterARGB32PM_data()
+{
+ setupTestSuite();
+}
+
+
+void tst_Lancelot::testRasterARGB32PM()
+{
+ runTestSuite(Raster, QImage::Format_ARGB32_Premultiplied);
+}
+
+
+void tst_Lancelot::testRasterARGB32_data()
+{
+ setupTestSuite();
+}
+
+void tst_Lancelot::testRasterARGB32()
+{
+ runTestSuite(Raster, QImage::Format_ARGB32);
+}
+
+
+void tst_Lancelot::testRasterRGB32_data()
+{
+ setupTestSuite();
+}
+
+
+void tst_Lancelot::testRasterRGB32()
+{
+ runTestSuite(Raster, QImage::Format_RGB32);
+}
+
+
+void tst_Lancelot::testRasterRGB16_data()
+{
+ setupTestSuite();
+}
+
+
+void tst_Lancelot::testRasterRGB16()
+{
+ runTestSuite(Raster, QImage::Format_RGB16);
+}
+
+
+void tst_Lancelot::testRasterA2RGB30PM_data()
+{
+ setupTestSuite();
+}
+
+
+void tst_Lancelot::testRasterA2RGB30PM()
+{
+ runTestSuite(Raster, QImage::Format_A2RGB30_Premultiplied);
+}
+
+
+void tst_Lancelot::testRasterBGR30_data()
+{
+ setupTestSuite();
+}
+
+
+void tst_Lancelot::testRasterBGR30()
+{
+ runTestSuite(Raster, QImage::Format_BGR30);
+}
+
+
+void tst_Lancelot::testRasterARGB8565PM_data()
+{
+ setupTestSuite();
+}
+
+void tst_Lancelot::testRasterARGB8565PM()
+{
+ runTestSuite(Raster, QImage::Format_ARGB8565_Premultiplied);
+}
+
+
+void tst_Lancelot::testRasterGrayscale8_data()
+{
+ setupTestSuite();
+}
+
+void tst_Lancelot::testRasterGrayscale8()
+{
+ runTestSuite(Raster, QImage::Format_Grayscale8);
+}
+
+
+void tst_Lancelot::testRasterRGBA64PM_data()
+{
+ setupTestSuite();
+}
+
+void tst_Lancelot::testRasterRGBA64PM()
+{
+ runTestSuite(Raster, QImage::Format_RGBA64_Premultiplied);
+}
+
+
+void tst_Lancelot::testRasterRGBA16F_data()
+{
+ setupTestSuite();
+}
+
+void tst_Lancelot::testRasterRGBA16F()
+{
+ runTestSuite(Raster, QImage::Format_RGBA16FPx4);
+}
+
+void tst_Lancelot::testRasterRGBA32FPM_data()
+{
+ setupTestSuite();
+}
+
+void tst_Lancelot::testRasterRGBA32FPM()
+{
+ runTestSuite(Raster, QImage::Format_RGBA32FPx4_Premultiplied);
+}
+
+
+void tst_Lancelot::testPdf_data()
+{
+#ifdef Q_OS_MACOS
+ setupTestSuite();
+#else
+ QSKIP("Pdf testing only implemented for macOS");
+#endif
+}
+
+void tst_Lancelot::testPdf()
+{
+ runTestSuite(Pdf, QImage::Format_RGB32);
+}
+
+
+#ifndef QT_NO_OPENGL
+bool tst_Lancelot::checkSystemGLSupport()
+{
+ QWindow win;
+ win.setSurfaceType(QSurface::OpenGLSurface);
+ win.create();
+ QOpenGLFramebufferObjectFormat fmt;
+ fmt.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ fmt.setSamples(4);
+ QOpenGLContext ctx;
+ if (!ctx.create() || !ctx.makeCurrent(&win))
+ return false;
+ QOpenGLFramebufferObject fbo(800, 800, fmt);
+ if (!fbo.isValid() || !fbo.bind())
+ return false;
+
+ return true;
+}
+
+bool tst_Lancelot::checkSystemCoreGLSupport()
+{
+ if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL)
+ return false;
+
+ QSurfaceFormat coreFormat;
+ coreFormat.setVersion(3, 2);
+ coreFormat.setProfile(QSurfaceFormat::CoreProfile);
+ QWindow win;
+ win.setSurfaceType(QSurface::OpenGLSurface);
+ win.setFormat(coreFormat);
+ win.create();
+ QOpenGLFramebufferObjectFormat fmt;
+ fmt.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ fmt.setSamples(4);
+ QOpenGLContext ctx;
+ ctx.setFormat(coreFormat);
+ if (!ctx.create() || !ctx.makeCurrent(&win))
+ return false;
+ QOpenGLFramebufferObject fbo(800, 800, fmt);
+ if (!fbo.isValid() || !fbo.bind())
+ return false;
+
+ return true;
+}
+
+void tst_Lancelot::testOpenGL_data()
+{
+ if (!checkSystemGLSupport())
+ QSKIP("System under test does not meet preconditions for GL testing. Skipping.");
+ QStringList localBlacklist = QStringList() << QLatin1String("rasterops.qps");
+ setupTestSuite(localBlacklist);
+}
+
+
+void tst_Lancelot::testOpenGL()
+{
+ runTestSuite(OpenGL, QImage::Format_RGB32);
+}
+
+void tst_Lancelot::testOpenGLBGR30_data()
+{
+ tst_Lancelot::testOpenGL_data();
+}
+
+void tst_Lancelot::testOpenGLBGR30()
+{
+ runTestSuite(OpenGL, QImage::Format_BGR30);
+}
+
+void tst_Lancelot::testCoreOpenGL_data()
+{
+ if (!checkSystemCoreGLSupport())
+ QSKIP("System under test does not meet preconditions for Core Profile GL testing. Skipping.");
+ QStringList localBlacklist = QStringList() << QLatin1String("rasterops.qps");
+ setupTestSuite(localBlacklist);
+}
+
+void tst_Lancelot::testCoreOpenGL()
+{
+ QSurfaceFormat coreFormat;
+ coreFormat.setVersion(3, 2);
+ coreFormat.setProfile(QSurfaceFormat::CoreProfile);
+ runTestSuite(OpenGL, QImage::Format_RGB32, coreFormat);
+}
+#endif
+
+
+void tst_Lancelot::setupTestSuite(const QStringList& blacklist)
+{
+ QTest::addColumn<QString>("qpsFile");
+ foreach (const QString &fileName, qpsFiles) {
+ if (blacklist.contains(fileName))
+ continue;
+ QBaselineTest::newRow(fileName.toLatin1(), scriptChecksums.value(fileName)) << fileName;
+ }
+}
+
+
+void tst_Lancelot::runTestSuite(GraphicsEngine engine, QImage::Format format, const QSurfaceFormat &contextFormat)
+{
+ QFETCH(QString, qpsFile);
+
+ QString filePath = scriptsDir + qpsFile;
+ QStringList script = scripts.value(qpsFile);
+ QImage rendered;
+
+ if (engine == Raster) {
+ QImage img(800, 800, format);
+ paint(&img, engine, format, script, QFileInfo(filePath).absoluteFilePath());
+ rendered = img;
+#ifndef QT_NO_OPENGL
+ } else if (engine == OpenGL) {
+ QWindow win;
+ win.setSurfaceType(QSurface::OpenGLSurface);
+ win.setFormat(contextFormat);
+ win.create();
+ QOpenGLContext ctx;
+ ctx.setFormat(contextFormat);
+ QVERIFY(ctx.create());
+ QVERIFY(ctx.makeCurrent(&win));
+ QOpenGLFramebufferObjectFormat fmt;
+ fmt.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ fmt.setSamples(4);
+ if (format == QImage::Format_BGR30)
+ fmt.setInternalTextureFormat(ctx.isOpenGLES() ? GL_RGB10_A2 : GL_RGB10);
+ QOpenGLFramebufferObject fbo(800, 800, fmt);
+ fbo.bind();
+ QOpenGLPaintDevice pdv(800, 800);
+ paint(&pdv, engine, format, script, QFileInfo(filePath).absoluteFilePath());
+ rendered = fbo.toImage().convertToFormat(format);
+#endif
+ } else if (engine == Pdf) {
+#if QT_CONFIG(process)
+ QString tempStem(QDir::tempPath() + QLatin1String("/lancelot_XXXXXX_") + qpsFile.chopped(4));
+
+ QTemporaryFile pdfFile(tempStem + QLatin1String(".pdf"));
+ pdfFile.open();
+ QPdfWriter writer(&pdfFile);
+ writer.setPdfVersion(QPdfWriter::PdfVersion_1_6);
+ writer.setResolution(150);
+ paint(&writer, engine, format, script, QFileInfo(filePath).absoluteFilePath());
+ pdfFile.close();
+
+ // Convert pdf to something we can read into a QImage, using macOS' sips utility
+ QTemporaryFile pngFile(tempStem + QLatin1String(".png"));
+ pngFile.open(); // Just create the file name
+ pngFile.close();
+ QProcess proc;
+ const char *rawArgs = "-s format png --cropOffset 20 20 -c 800 800 -o";
+ QStringList argList = QString::fromLatin1(rawArgs).split(QLatin1Char(' '));
+ proc.start(QLatin1String("sips"), argList << pngFile.fileName() << pdfFile.fileName());
+ proc.waitForFinished(2 * 60 * 1000); // May need some time
+
+ rendered = QImage(pngFile.fileName());
+#endif
+ }
+
+ QBASELINE_TEST(rendered);
+}
+
+void tst_Lancelot::paint(QPaintDevice *device, GraphicsEngine engine, QImage::Format format, const QStringList &script, const QString &filePath)
+{
+ QPainter p(device);
+ PaintCommands pcmd(script, 800, 800, format);
+ //pcmd.setShouldDrawText(false);
+ switch (engine) {
+ case OpenGL:
+ pcmd.setType(OpenGLBufferType); // version/profile is communicated through the context's format()
+ break;
+ case Pdf:
+ pcmd.setType(PdfType);
+ break;
+ case Raster: // fallthrough
+ default:
+ pcmd.setType(ImageType);
+ break;
+ }
+ pcmd.setPainter(&p);
+ pcmd.setFilePath(filePath);
+ pcmd.runCommands();
+ p.end();
+}
+
+#define main _realmain
+QTEST_MAIN(tst_Lancelot)
+#undef main
+
+int main(int argc, char *argv[])
+{
+ qSetGlobalQHashSeed(0); // Avoid rendering variations caused by QHash randomization
+
+ QBaselineTest::handleCmdLineArgs(&argc, &argv);
+ return _realmain(argc, argv);
+}
+
+#include "tst_baseline_painting.moc"
diff --git a/tests/baseline/shared/baselineprotocol.cpp b/tests/baseline/shared/baselineprotocol.cpp
new file mode 100644
index 0000000000..63cce0bd80
--- /dev/null
+++ b/tests/baseline/shared/baselineprotocol.cpp
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "baselineprotocol.h"
+#include <QLibraryInfo>
+#include <QImage>
+#include <QBuffer>
+#include <QHostInfo>
+#include <QSysInfo>
+#if QT_CONFIG(process)
+# include <QProcess>
+#endif
+#include <QFileInfo>
+#include <QDir>
+#include <QTime>
+#include <QPointer>
+#include <QRegularExpression>
+
+const QString PI_Project(QLS("Project"));
+const QString PI_TestCase(QLS("TestCase"));
+const QString PI_HostName(QLS("HostName"));
+const QString PI_HostAddress(QLS("HostAddress"));
+const QString PI_OSName(QLS("OSName"));
+const QString PI_OSVersion(QLS("OSVersion"));
+const QString PI_QtVersion(QLS("QtVersion"));
+const QString PI_QtBuildMode(QLS("QtBuildMode"));
+const QString PI_GitCommit(QLS("GitCommit"));
+const QString PI_QMakeSpec(QLS("QMakeSpec"));
+const QString PI_PulseGitBranch(QLS("PulseGitBranch"));
+const QString PI_PulseTestrBranch(QLS("PulseTestrBranch"));
+
+#ifndef QMAKESPEC
+#define QMAKESPEC "Unknown"
+#endif
+
+#if defined(Q_OS_WIN)
+#include <QtCore/qt_windows.h>
+#endif
+#if defined(Q_OS_UNIX)
+#include <time.h>
+#endif
+void BaselineProtocol::sysSleep(int ms)
+{
+#if defined(Q_OS_WIN)
+ Sleep(DWORD(ms));
+#else
+ struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
+ nanosleep(&ts, NULL);
+#endif
+}
+
+PlatformInfo::PlatformInfo()
+ : QMap<QString, QString>(), adHoc(true)
+{
+}
+
+PlatformInfo PlatformInfo::localHostInfo()
+{
+ PlatformInfo pi;
+ pi.insert(PI_HostName, QHostInfo::localHostName());
+ pi.insert(PI_QtVersion, QLS(qVersion()));
+ pi.insert(PI_QMakeSpec, QString(QLS(QMAKESPEC)).remove(QRegularExpression(QLS("^.*mkspecs/"))));
+ pi.insert(PI_QtBuildMode, QLibraryInfo::isDebugBuild() ? QLS("QtDebug") : QLS("QtRelease"));
+#if defined(Q_OS_LINUX) && QT_CONFIG(process)
+ pi.insert(PI_OSName, QLS("Linux"));
+#elif defined(Q_OS_WIN)
+ pi.insert(PI_OSName, QLS("Windows"));
+#elif defined(Q_OS_DARWIN)
+ pi.insert(PI_OSName, QLS("Darwin"));
+#else
+ pi.insert(PI_OSName, QLS("Other"));
+#endif
+ pi.insert(PI_OSVersion, QSysInfo::kernelVersion());
+
+#if QT_CONFIG(process)
+ QProcess git;
+ QString cmd;
+ QStringList args;
+#if defined(Q_OS_WIN)
+ cmd = QLS("cmd.exe");
+ args << QLS("/c") << QLS("git");
+#else
+ cmd = QLS("git");
+#endif
+ args << QLS("log") << QLS("--max-count=1") << QLS("--pretty=%H [%an] [%ad] %s");
+ git.start(cmd, args);
+ git.waitForFinished(3000);
+ if (!git.exitCode())
+ pi.insert(PI_GitCommit, QString::fromLocal8Bit(git.readAllStandardOutput().constData()).simplified());
+ else
+ pi.insert(PI_GitCommit, QLS("Unknown"));
+
+ QByteArray gb = qgetenv("PULSE_GIT_BRANCH");
+ if (!gb.isEmpty()) {
+ pi.insert(PI_PulseGitBranch, QString::fromLatin1(gb));
+ pi.setAdHocRun(false);
+ }
+ QByteArray tb = qgetenv("PULSE_TESTR_BRANCH");
+ if (!tb.isEmpty()) {
+ pi.insert(PI_PulseTestrBranch, QString::fromLatin1(tb));
+ pi.setAdHocRun(false);
+ }
+ if (!qgetenv("JENKINS_HOME").isEmpty()) {
+ pi.setAdHocRun(false);
+ gb = qgetenv("GIT_BRANCH");
+ if (!gb.isEmpty()) {
+ // FIXME: the string "Pulse" should be eliminated, since that is not the used tool.
+ pi.insert(PI_PulseGitBranch, QString::fromLatin1(gb));
+ }
+ }
+#endif // QT_CONFIG(process)
+
+ return pi;
+}
+
+
+PlatformInfo::PlatformInfo(const PlatformInfo &other)
+ : QMap<QString, QString>(other)
+{
+ orides = other.orides;
+ adHoc = other.adHoc;
+}
+
+
+PlatformInfo &PlatformInfo::operator=(const PlatformInfo &other)
+{
+ QMap<QString, QString>::operator=(other);
+ orides = other.orides;
+ adHoc = other.adHoc;
+ return *this;
+}
+
+
+void PlatformInfo::addOverride(const QString& key, const QString& value)
+{
+ orides.append(key);
+ orides.append(value);
+}
+
+
+QStringList PlatformInfo::overrides() const
+{
+ return orides;
+}
+
+
+void PlatformInfo::setAdHocRun(bool isAdHoc)
+{
+ adHoc = isAdHoc;
+}
+
+
+bool PlatformInfo::isAdHocRun() const
+{
+ return adHoc;
+}
+
+
+QDataStream & operator<< (QDataStream &stream, const PlatformInfo &pi)
+{
+ stream << static_cast<const QMap<QString, QString>&>(pi);
+ stream << pi.orides << pi.adHoc;
+ return stream;
+}
+
+
+QDataStream & operator>> (QDataStream &stream, PlatformInfo &pi)
+{
+ stream >> static_cast<QMap<QString, QString>&>(pi);
+ stream >> pi.orides >> pi.adHoc;
+ return stream;
+}
+
+
+ImageItem &ImageItem::operator=(const ImageItem &other)
+{
+ testFunction = other.testFunction;
+ itemName = other.itemName;
+ itemChecksum = other.itemChecksum;
+ status = other.status;
+ image = other.image;
+ imageChecksums = other.imageChecksums;
+ return *this;
+}
+
+// Defined in lookup3.c:
+void hashword2 (
+const quint32 *k, /* the key, an array of quint32 values */
+size_t length, /* the length of the key, in quint32s */
+quint32 *pc, /* IN: seed OUT: primary hash value */
+quint32 *pb); /* IN: more seed OUT: secondary hash value */
+
+quint64 ImageItem::computeChecksum(const QImage &image)
+{
+ QImage img(image);
+ const qsizetype bpl = img.bytesPerLine();
+ const int padBytes = bpl - (qsizetype(img.width()) * img.depth() / 8);
+ if (padBytes) {
+ uchar *p = img.bits() + bpl - padBytes;
+ const int h = img.height();
+ for (int y = 0; y < h; ++y) {
+ memset(p, 0, padBytes);
+ p += bpl;
+ }
+ }
+
+ quint32 h1 = 0xfeedbacc;
+ quint32 h2 = 0x21604894;
+ hashword2((const quint32 *)img.constBits(), img.sizeInBytes()/4, &h1, &h2);
+ return (quint64(h1) << 32) | h2;
+}
+
+#if 0
+QString ImageItem::engineAsString() const
+{
+ switch (engine) {
+ case Raster:
+ return QLS("Raster");
+ break;
+ case OpenGL:
+ return QLS("OpenGL");
+ break;
+ default:
+ break;
+ }
+ return QLS("Unknown");
+}
+
+QString ImageItem::formatAsString() const
+{
+ static const int numFormats = 16;
+ static const char *formatNames[numFormats] = {
+ "Invalid",
+ "Mono",
+ "MonoLSB",
+ "Indexed8",
+ "RGB32",
+ "ARGB32",
+ "ARGB32-Premult",
+ "RGB16",
+ "ARGB8565-Premult",
+ "RGB666",
+ "ARGB6666-Premult",
+ "RGB555",
+ "ARGB8555-Premult",
+ "RGB888",
+ "RGB444",
+ "ARGB4444-Premult"
+ };
+ if (renderFormat < 0 || renderFormat >= numFormats)
+ return QLS("UnknownFormat");
+ return QLS(formatNames[renderFormat]);
+}
+#endif
+
+void ImageItem::writeImageToStream(QDataStream &out) const
+{
+ if (image.isNull() || image.format() == QImage::Format_Invalid) {
+ out << quint8(0);
+ return;
+ }
+ out << quint8('Q') << quint8(image.format());
+ out << quint8(QSysInfo::ByteOrder) << quint8(0); // pad to multiple of 4 bytes
+ out << quint32(image.width()) << quint32(image.height()) << quint32(image.bytesPerLine());
+ out << qCompress(reinterpret_cast<const uchar *>(image.constBits()),
+ int(image.sizeInBytes()));
+ //# can be followed by colormap for formats that use it
+}
+
+void ImageItem::readImageFromStream(QDataStream &in)
+{
+ quint8 hdr, fmt, endian, pad;
+ quint32 width, height, bpl;
+ QByteArray data;
+
+ in >> hdr;
+ if (hdr != 'Q') {
+ image = QImage();
+ return;
+ }
+ in >> fmt >> endian >> pad;
+ if (!fmt || fmt >= QImage::NImageFormats) {
+ image = QImage();
+ return;
+ }
+ if (endian != QSysInfo::ByteOrder) {
+ qWarning("ImageItem cannot read streamed image with different endianness");
+ image = QImage();
+ return;
+ }
+ in >> width >> height >> bpl;
+ in >> data;
+ data = qUncompress(data);
+ QImage res((const uchar *)data.constData(), width, height, bpl, QImage::Format(fmt));
+ image = res.copy(); //# yuck, seems there is currently no way to avoid data copy
+}
+
+QDataStream & operator<< (QDataStream &stream, const ImageItem &ii)
+{
+ stream << ii.testFunction << ii.itemName << ii.itemChecksum << quint8(ii.status) << ii.imageChecksums << ii.misc;
+ ii.writeImageToStream(stream);
+ return stream;
+}
+
+QDataStream & operator>> (QDataStream &stream, ImageItem &ii)
+{
+ quint8 encStatus;
+ stream >> ii.testFunction >> ii.itemName >> ii.itemChecksum >> encStatus >> ii.imageChecksums >> ii.misc;
+ ii.status = ImageItem::ItemStatus(encStatus);
+ ii.readImageFromStream(stream);
+ return stream;
+}
+
+BaselineProtocol::BaselineProtocol()
+{
+}
+
+BaselineProtocol::~BaselineProtocol()
+{
+ disconnect();
+}
+
+bool BaselineProtocol::disconnect()
+{
+ socket.close();
+ return (socket.state() == QTcpSocket::UnconnectedState) ? true : socket.waitForDisconnected(Timeout);
+}
+
+
+bool BaselineProtocol::connect(const QString &testCase, bool *dryrun, const PlatformInfo& clientInfo)
+{
+ errMsg.clear();
+ QByteArray serverName(qgetenv("QT_LANCELOT_SERVER"));
+ if (serverName.isNull())
+ serverName = "lancelot.test.qt-project.org";
+
+ socket.connectToHost(serverName, ServerPort);
+ if (!socket.waitForConnected(Timeout)) {
+ sysSleep(3000); // Wait a bit and try again, the server might just be restarting
+ if (!socket.waitForConnected(Timeout)) {
+ errMsg += QLS("TCP connectToHost failed. Host:") + QLS(serverName) + QLS(" port:") + QString::number(ServerPort);
+ return false;
+ }
+ }
+
+ PlatformInfo pi = clientInfo.isEmpty() ? PlatformInfo::localHostInfo() : clientInfo;
+ pi.insert(PI_TestCase, testCase);
+ QByteArray block;
+ QDataStream ds(&block, QIODevice::ReadWrite);
+ ds << pi;
+ if (!sendBlock(AcceptPlatformInfo, block)) {
+ errMsg += QLS("Failed to send data to server.");
+ return false;
+ }
+
+ Command cmd = UnknownError;
+ if (!receiveBlock(&cmd, &block)) {
+ errMsg.prepend(QLS("Failed to get response from server. "));
+ return false;
+ }
+
+ if (cmd == Abort) {
+ errMsg += QLS("Server rejected connection. Reason: ") + QString::fromLatin1(block);
+ return false;
+ }
+
+ if (dryrun)
+ *dryrun = (cmd == DoDryRun);
+
+ if (cmd != Ack && cmd != DoDryRun) {
+ errMsg += QLS("Unexpected response from server.");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool BaselineProtocol::acceptConnection(PlatformInfo *pi)
+{
+ errMsg.clear();
+
+ QByteArray block;
+ Command cmd = AcceptPlatformInfo;
+ if (!receiveBlock(&cmd, &block) || cmd != AcceptPlatformInfo)
+ return false;
+
+ if (pi) {
+ QDataStream ds(block);
+ ds >> *pi;
+ pi->insert(PI_HostAddress, socket.peerAddress().toString());
+ }
+
+ return true;
+}
+
+
+bool BaselineProtocol::requestBaselineChecksums(const QString &testFunction, ImageItemList *itemList)
+{
+ errMsg.clear();
+ if (!itemList)
+ return false;
+
+ for(ImageItemList::iterator it = itemList->begin(); it != itemList->end(); it++)
+ it->testFunction = testFunction;
+
+ QByteArray block;
+ QDataStream ds(&block, QIODevice::WriteOnly);
+ ds << *itemList;
+ if (!sendBlock(RequestBaselineChecksums, block))
+ return false;
+
+ Command cmd;
+ QByteArray rcvBlock;
+ if (!receiveBlock(&cmd, &rcvBlock) || cmd != BaselineProtocol::Ack)
+ return false;
+ QDataStream rds(&rcvBlock, QIODevice::ReadOnly);
+ rds >> *itemList;
+ return true;
+}
+
+
+bool BaselineProtocol::submitMatch(const ImageItem &item, QByteArray *serverMsg)
+{
+ Command cmd;
+ ImageItem smallItem = item;
+ smallItem.image = QImage(); // No need to waste bandwith sending image (identical to baseline) to server
+ return (sendItem(AcceptMatch, smallItem) && receiveBlock(&cmd, serverMsg) && cmd == Ack);
+}
+
+
+bool BaselineProtocol::submitNewBaseline(const ImageItem &item, QByteArray *serverMsg)
+{
+ Command cmd;
+ return (sendItem(AcceptNewBaseline, item) && receiveBlock(&cmd, serverMsg) && cmd == Ack);
+}
+
+
+bool BaselineProtocol::submitMismatch(const ImageItem &item, QByteArray *serverMsg, bool *fuzzyMatch)
+{
+ Command cmd;
+ if (sendItem(AcceptMismatch, item) && receiveBlock(&cmd, serverMsg) && (cmd == Ack || cmd == FuzzyMatch)) {
+ if (fuzzyMatch)
+ *fuzzyMatch = (cmd == FuzzyMatch);
+ return true;
+ }
+ return false;
+}
+
+
+bool BaselineProtocol::sendItem(Command cmd, const ImageItem &item)
+{
+ errMsg.clear();
+ QBuffer buf;
+ buf.open(QIODevice::WriteOnly);
+ QDataStream ds(&buf);
+ ds << item;
+ if (!sendBlock(cmd, buf.data())) {
+ errMsg.prepend(QLS("Failed to submit image to server. "));
+ return false;
+ }
+ return true;
+}
+
+
+bool BaselineProtocol::sendBlock(Command cmd, const QByteArray &block)
+{
+ QDataStream s(&socket);
+ // TBD: set qds version as a constant
+ s << quint16(ProtocolVersion) << quint16(cmd);
+ s.writeBytes(block.constData(), block.size());
+ return true;
+}
+
+
+bool BaselineProtocol::receiveBlock(Command *cmd, QByteArray *block)
+{
+ while (socket.bytesAvailable() < int(2*sizeof(quint16) + sizeof(quint32))) {
+ if (!socket.waitForReadyRead(Timeout))
+ return false;
+ }
+ QDataStream ds(&socket);
+ quint16 rcvProtocolVersion, rcvCmd;
+ ds >> rcvProtocolVersion >> rcvCmd;
+ if (rcvProtocolVersion != ProtocolVersion) {
+ errMsg = QLS("Baseline protocol version mismatch, received:") + QString::number(rcvProtocolVersion)
+ + QLS(" expected:") + QString::number(ProtocolVersion);
+ return false;
+ }
+ if (cmd)
+ *cmd = Command(rcvCmd);
+
+ QByteArray uMsg;
+ quint32 remaining;
+ ds >> remaining;
+ uMsg.resize(remaining);
+ int got = 0;
+ char* uMsgBuf = uMsg.data();
+ do {
+ got = ds.readRawData(uMsgBuf, remaining);
+ remaining -= got;
+ uMsgBuf += got;
+ } while (remaining && got >= 0 && socket.waitForReadyRead(Timeout));
+
+ if (got < 0)
+ return false;
+
+ if (block)
+ *block = uMsg;
+
+ return true;
+}
+
+
+QString BaselineProtocol::errorMessage()
+{
+ QString ret = errMsg;
+ if (socket.error() >= 0)
+ ret += QLS(" Socket state: ") + socket.errorString();
+ return ret;
+}
+
diff --git a/tests/baseline/shared/baselineprotocol.h b/tests/baseline/shared/baselineprotocol.h
new file mode 100644
index 0000000000..510762e304
--- /dev/null
+++ b/tests/baseline/shared/baselineprotocol.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BASELINEPROTOCOL_H
+#define BASELINEPROTOCOL_H
+
+#include <QDataStream>
+#include <QTcpSocket>
+#include <QImage>
+#include <QList>
+#include <QMap>
+#include <QPointer>
+#include <QStringList>
+
+#define QLS QLatin1String
+#define QLC QLatin1Char
+
+#define FileFormat "png"
+
+extern const QString PI_Project;
+extern const QString PI_TestCase;
+extern const QString PI_HostName;
+extern const QString PI_HostAddress;
+extern const QString PI_OSName;
+extern const QString PI_OSVersion;
+extern const QString PI_QtVersion;
+extern const QString PI_QtBuildMode;
+extern const QString PI_GitCommit;
+extern const QString PI_QMakeSpec;
+extern const QString PI_PulseGitBranch;
+extern const QString PI_PulseTestrBranch;
+
+class PlatformInfo : public QMap<QString, QString>
+{
+public:
+ PlatformInfo();
+ PlatformInfo(const PlatformInfo &other);
+ ~PlatformInfo()
+ {}
+ PlatformInfo &operator=(const PlatformInfo &other);
+
+ static PlatformInfo localHostInfo();
+
+ void addOverride(const QString& key, const QString& value);
+ QStringList overrides() const;
+ bool isAdHocRun() const;
+ void setAdHocRun(bool isAdHoc);
+
+private:
+ QStringList orides;
+ bool adHoc;
+ friend QDataStream & operator<< (QDataStream &stream, const PlatformInfo &pi);
+ friend QDataStream & operator>> (QDataStream &stream, PlatformInfo& pi);
+};
+QDataStream & operator<< (QDataStream &stream, const PlatformInfo &pi);
+QDataStream & operator>> (QDataStream &stream, PlatformInfo& pi);
+
+
+struct ImageItem
+{
+public:
+ ImageItem()
+ : status(Ok), itemChecksum(0)
+ {}
+ ImageItem(const ImageItem &other)
+ { *this = other; }
+ ~ImageItem()
+ {}
+ ImageItem &operator=(const ImageItem &other);
+
+ static quint64 computeChecksum(const QImage& image);
+
+ enum ItemStatus {
+ Ok = 0,
+ BaselineNotFound = 1,
+ IgnoreItem = 2,
+ Mismatch = 3,
+ FuzzyMatch = 4,
+ Error = 5
+ };
+
+ QString testFunction;
+ QString itemName;
+ ItemStatus status;
+ QImage image;
+ QList<quint64> imageChecksums;
+ quint16 itemChecksum;
+ QByteArray misc;
+
+ void writeImageToStream(QDataStream &stream) const;
+ void readImageFromStream(QDataStream &stream);
+};
+QDataStream & operator<< (QDataStream &stream, const ImageItem &ii);
+QDataStream & operator>> (QDataStream &stream, ImageItem& ii);
+
+Q_DECLARE_METATYPE(ImageItem);
+
+typedef QList<ImageItem> ImageItemList;
+
+class BaselineProtocol
+{
+public:
+ BaselineProtocol();
+ ~BaselineProtocol();
+
+ static BaselineProtocol *instance(QObject *parent = nullptr);
+
+ // ****************************************************
+ // Important constants here
+ // ****************************************************
+ enum Constant {
+ ProtocolVersion = 5,
+ ServerPort = 54129,
+ Timeout = 15000
+ };
+
+ enum Command {
+ UnknownError = 0,
+ // Queries
+ AcceptPlatformInfo = 1,
+ RequestBaselineChecksums = 2,
+ AcceptMatch = 3,
+ AcceptNewBaseline = 4,
+ AcceptMismatch = 5,
+ // Responses
+ Ack = 128,
+ Abort = 129,
+ DoDryRun = 130,
+ FuzzyMatch = 131
+ };
+
+ // For client:
+
+ // For advanced client:
+ bool connect(const QString &testCase, bool *dryrun = nullptr, const PlatformInfo& clientInfo = PlatformInfo());
+ bool disconnect();
+ bool requestBaselineChecksums(const QString &testFunction, ImageItemList *itemList);
+ bool submitMatch(const ImageItem &item, QByteArray *serverMsg);
+ bool submitNewBaseline(const ImageItem &item, QByteArray *serverMsg);
+ bool submitMismatch(const ImageItem &item, QByteArray *serverMsg, bool *fuzzyMatch = nullptr);
+
+ // For server:
+ bool acceptConnection(PlatformInfo *pi);
+
+ QString errorMessage();
+
+private:
+ bool sendItem(Command cmd, const ImageItem &item);
+
+ bool sendBlock(Command cmd, const QByteArray &block);
+ bool receiveBlock(Command *cmd, QByteArray *block);
+ void sysSleep(int ms);
+
+ QString errMsg;
+ QTcpSocket socket;
+
+ friend class BaselineThread;
+ friend class BaselineHandler;
+};
+
+
+#endif // BASELINEPROTOCOL_H
diff --git a/tests/baseline/shared/baselineprotocol.pri b/tests/baseline/shared/baselineprotocol.pri
new file mode 100644
index 0000000000..996f9d5a1f
--- /dev/null
+++ b/tests/baseline/shared/baselineprotocol.pri
@@ -0,0 +1,10 @@
+INCLUDEPATH += $$PWD
+
+QT *= network
+
+SOURCES += \
+ $$PWD/baselineprotocol.cpp \
+ $$PWD/lookup3.cpp
+
+HEADERS += \
+ $$PWD/baselineprotocol.h
diff --git a/tests/baseline/shared/lookup3.cpp b/tests/baseline/shared/lookup3.cpp
new file mode 100644
index 0000000000..3d8d763bb7
--- /dev/null
+++ b/tests/baseline/shared/lookup3.cpp
@@ -0,0 +1,846 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*
+These functions are based on:
+
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions. Routines to test the hash are included
+if SELF_TEST is defined. You can use this free for any purpose. It's in
+the public domain. It has no warranty.
+
+You probably want to use hashlittle(). hashlittle() and hashbig()
+hash byte arrays. hashlittle() is is faster than hashbig() on
+little-endian machines. Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+ a = i1; b = i2; c = i3;
+ mix(a,b,c);
+ a += i4; b += i5; c += i6;
+ mix(a,b,c);
+ a += i7;
+ final(a,b,c);
+then use c as the hash value. If you have a variable length array of
+4-byte integers to hash, use hashword(). If you have a byte array (like
+a character string), use hashlittle(). If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers. This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+
+#include <QtGlobal>
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((quint32)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta. I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche. There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a. The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism. Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism. I did what I could. Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different. This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+/*
+--------------------------------------------------------------------
+ This works on all machines. To be useful, it requires
+ -- that the key be an array of quint32's, and
+ -- that the length be the number of quint32's in the key
+
+ The function hashword() is identical to hashlittle() on little-endian
+ machines, and identical to hashbig() on big-endian machines,
+ except that the length has to be measured in quint32s rather than in
+ bytes. hashlittle() is more complicated than hashword() only because
+ hashlittle() has to dance around fitting the key bytes into registers.
+--------------------------------------------------------------------
+*/
+quint32 hashword(
+const quint32 *k, /* the key, an array of quint32 values */
+size_t length, /* the length of the key, in quint32s */
+quint32 initval) /* the previous hash, or an arbitrary value */
+{
+ quint32 a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + (((quint32)length)<<2) + initval;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 quint32's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ Q_FALLTHROUGH();
+ case 2 : b+=k[1];
+ Q_FALLTHROUGH();
+ case 1 : a+=k[0];
+ final(a,b,c);
+ Q_FALLTHROUGH();
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ return c;
+}
+
+
+/*
+--------------------------------------------------------------------
+hashword2() -- same as hashword(), but take two seeds and return two
+32-bit values. pc and pb must both be nonnull, and *pc and *pb must
+both be initialized with seeds. If you pass in (*pb)==0, the output
+(*pc) will be the same as the return value from hashword().
+--------------------------------------------------------------------
+*/
+void hashword2 (
+const quint32 *k, /* the key, an array of quint32 values */
+size_t length, /* the length of the key, in quint32s */
+quint32 *pc, /* IN: seed OUT: primary hash value */
+quint32 *pb) /* IN: more seed OUT: secondary hash value */
+{
+ quint32 a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((quint32)(length<<2)) + *pc;
+ c += *pb;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 quint32's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ Q_FALLTHROUGH();
+ case 2 : b+=k[1];
+ Q_FALLTHROUGH();
+ case 1 : a+=k[0];
+ final(a,b,c);
+ Q_FALLTHROUGH();
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ *pc=c; *pb=b;
+}
+
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (quint8 **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+quint32 hashlittle( const void *key, size_t length, quint32 initval)
+{
+ quint32 a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((quint32)length) + initval;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const quint32 *k = (const quint32 *)key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ const quint8 *k8 = (const quint8 *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((quint32)k8[10])<<16;
+ Q_FALLTHROUGH();
+ case 10: c+=((quint32)k8[9])<<8;
+ Q_FALLTHROUGH();
+ case 9 : c+=k8[8];
+ Q_FALLTHROUGH();
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((quint32)k8[6])<<16;
+ Q_FALLTHROUGH();
+ case 6 : b+=((quint32)k8[5])<<8;
+ Q_FALLTHROUGH();
+ case 5 : b+=k8[4];
+ Q_FALLTHROUGH();
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((quint32)k8[2])<<16;
+ Q_FALLTHROUGH();
+ case 2 : a+=((quint32)k8[1])<<8;
+ Q_FALLTHROUGH();
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const quint16 *k = (const quint16 *)key; /* read 16-bit chunks */
+ const quint8 *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((quint32)k[1])<<16);
+ b += k[2] + (((quint32)k[3])<<16);
+ c += k[4] + (((quint32)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const quint8 *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((quint32)k[5])<<16);
+ b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 11: c+=((quint32)k8[10])<<16;
+ Q_FALLTHROUGH();
+ case 10: c+=k[4];
+ b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 9 : c+=k8[8];
+ Q_FALLTHROUGH();
+ case 8 : b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 7 : b+=((quint32)k8[6])<<16;
+ Q_FALLTHROUGH();
+ case 6 : b+=k[2];
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 5 : b+=k8[4];
+ Q_FALLTHROUGH();
+ case 4 : a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 3 : a+=((quint32)k8[2])<<16;
+ Q_FALLTHROUGH();
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const quint8 *k = (const quint8 *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((quint32)k[1])<<8;
+ a += ((quint32)k[2])<<16;
+ a += ((quint32)k[3])<<24;
+ b += k[4];
+ b += ((quint32)k[5])<<8;
+ b += ((quint32)k[6])<<16;
+ b += ((quint32)k[7])<<24;
+ c += k[8];
+ c += ((quint32)k[9])<<8;
+ c += ((quint32)k[10])<<16;
+ c += ((quint32)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((quint32)k[11])<<24;
+ Q_FALLTHROUGH();
+ case 11: c+=((quint32)k[10])<<16;
+ Q_FALLTHROUGH();
+ case 10: c+=((quint32)k[9])<<8;
+ Q_FALLTHROUGH();
+ case 9 : c+=k[8];
+ Q_FALLTHROUGH();
+ case 8 : b+=((quint32)k[7])<<24;
+ Q_FALLTHROUGH();
+ case 7 : b+=((quint32)k[6])<<16;
+ Q_FALLTHROUGH();
+ case 6 : b+=((quint32)k[5])<<8;
+ Q_FALLTHROUGH();
+ case 5 : b+=k[4];
+ Q_FALLTHROUGH();
+ case 4 : a+=((quint32)k[3])<<24;
+ Q_FALLTHROUGH();
+ case 3 : a+=((quint32)k[2])<<16;
+ Q_FALLTHROUGH();
+ case 2 : a+=((quint32)k[1])<<8;
+ Q_FALLTHROUGH();
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+
+/*
+ * hashlittle2: return 2 32-bit hash values
+ *
+ * This is identical to hashlittle(), except it returns two 32-bit hash
+ * values instead of just one. This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key. *pc is better mixed than *pb, so use *pc first. If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ */
+void hashlittle2(
+ const void *key, /* the key to hash */
+ size_t length, /* length of the key */
+ quint32 *pc, /* IN: primary initval, OUT: primary hash */
+ quint32 *pb) /* IN: secondary initval, OUT: secondary hash */
+{
+ quint32 a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((quint32)length) + *pc;
+ c += *pb;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const quint32 *k = (const quint32 *)key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ const quint8 *k8 = (const quint8 *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((quint32)k8[10])<<16;
+ Q_FALLTHROUGH();
+ case 10: c+=((quint32)k8[9])<<8;
+ Q_FALLTHROUGH();
+ case 9 : c+=k8[8];
+ Q_FALLTHROUGH();
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((quint32)k8[6])<<16;
+ Q_FALLTHROUGH();
+ case 6 : b+=((quint32)k8[5])<<8;
+ Q_FALLTHROUGH();
+ case 5 : b+=k8[4];
+ Q_FALLTHROUGH();
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((quint32)k8[2])<<16;
+ Q_FALLTHROUGH();
+ case 2 : a+=((quint32)k8[1])<<8;
+ Q_FALLTHROUGH();
+ case 1 : a+=k8[0]; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const quint16 *k = (const quint16 *)key; /* read 16-bit chunks */
+ const quint8 *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((quint32)k[1])<<16);
+ b += k[2] + (((quint32)k[3])<<16);
+ c += k[4] + (((quint32)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const quint8 *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((quint32)k[5])<<16);
+ b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 11: c+=((quint32)k8[10])<<16;
+ Q_FALLTHROUGH();
+ case 10: c+=k[4];
+ b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 9 : c+=k8[8];
+ Q_FALLTHROUGH();
+ case 8 : b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 7 : b+=((quint32)k8[6])<<16;
+ Q_FALLTHROUGH();
+ case 6 : b+=k[2];
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 5 : b+=k8[4];
+ Q_FALLTHROUGH();
+ case 4 : a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 3 : a+=((quint32)k8[2])<<16;
+ Q_FALLTHROUGH();
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const quint8 *k = (const quint8 *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((quint32)k[1])<<8;
+ a += ((quint32)k[2])<<16;
+ a += ((quint32)k[3])<<24;
+ b += k[4];
+ b += ((quint32)k[5])<<8;
+ b += ((quint32)k[6])<<16;
+ b += ((quint32)k[7])<<24;
+ c += k[8];
+ c += ((quint32)k[9])<<8;
+ c += ((quint32)k[10])<<16;
+ c += ((quint32)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((quint32)k[11])<<24;
+ Q_FALLTHROUGH();
+ case 11: c+=((quint32)k[10])<<16;
+ Q_FALLTHROUGH();
+ case 10: c+=((quint32)k[9])<<8;
+ Q_FALLTHROUGH();
+ case 9 : c+=k[8];
+ Q_FALLTHROUGH();
+ case 8 : b+=((quint32)k[7])<<24;
+ Q_FALLTHROUGH();
+ case 7 : b+=((quint32)k[6])<<16;
+ Q_FALLTHROUGH();
+ case 6 : b+=((quint32)k[5])<<8;
+ Q_FALLTHROUGH();
+ case 5 : b+=k[4];
+ Q_FALLTHROUGH();
+ case 4 : a+=((quint32)k[3])<<24;
+ Q_FALLTHROUGH();
+ case 3 : a+=((quint32)k[2])<<16;
+ Q_FALLTHROUGH();
+ case 2 : a+=((quint32)k[1])<<8;
+ Q_FALLTHROUGH();
+ case 1 : a+=k[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+ }
+
+ final(a,b,c);
+ *pc=c; *pb=b;
+}
+
+
+
+/*
+ * hashbig():
+ * This is the same as hashword() on big-endian machines. It is different
+ * from hashlittle() on all machines. hashbig() takes advantage of
+ * big-endian byte ordering.
+ */
+quint32 hashbig( const void *key, size_t length, quint32 initval)
+{
+ quint32 a,b,c;
+ union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((quint32)length) + initval;
+
+ u.ptr = key;
+ if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+ const quint32 *k = (const quint32 *)key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]<<8" actually reads beyond the end of the string, but
+ * then shifts out the part it's not allowed to read. Because the
+ * string is aligned, the illegal read is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff00; break;
+ case 2 : a+=k[0]&0xffff0000; break;
+ case 1 : a+=k[0]&0xff000000; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ const quint8 *k8 = (const quint8 *)k;
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((quint32)k8[10])<<8;
+ Q_FALLTHROUGH();
+ case 10: c+=((quint32)k8[9])<<16;
+ Q_FALLTHROUGH();
+ case 9 : c+=((quint32)k8[8])<<24;
+ Q_FALLTHROUGH();
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((quint32)k8[6])<<8;
+ Q_FALLTHROUGH();
+ case 6 : b+=((quint32)k8[5])<<16;
+ Q_FALLTHROUGH();
+ case 5 : b+=((quint32)k8[4])<<24;
+ Q_FALLTHROUGH();
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((quint32)k8[2])<<8;
+ Q_FALLTHROUGH();
+ case 2 : a+=((quint32)k8[1])<<16;
+ Q_FALLTHROUGH();
+ case 1 : a+=((quint32)k8[0])<<24; break;
+ case 0 : return c;
+ }
+
+#endif /* !VALGRIND */
+
+ } else { /* need to read the key one byte at a time */
+ const quint8 *k = (const quint8 *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += ((quint32)k[0])<<24;
+ a += ((quint32)k[1])<<16;
+ a += ((quint32)k[2])<<8;
+ a += ((quint32)k[3]);
+ b += ((quint32)k[4])<<24;
+ b += ((quint32)k[5])<<16;
+ b += ((quint32)k[6])<<8;
+ b += ((quint32)k[7]);
+ c += ((quint32)k[8])<<24;
+ c += ((quint32)k[9])<<16;
+ c += ((quint32)k[10])<<8;
+ c += ((quint32)k[11]);
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[11];
+ Q_FALLTHROUGH();
+ case 11: c+=((quint32)k[10])<<8;
+ Q_FALLTHROUGH();
+ case 10: c+=((quint32)k[9])<<16;
+ Q_FALLTHROUGH();
+ case 9 : c+=((quint32)k[8])<<24;
+ Q_FALLTHROUGH();
+ case 8 : b+=k[7];
+ Q_FALLTHROUGH();
+ case 7 : b+=((quint32)k[6])<<8;
+ Q_FALLTHROUGH();
+ case 6 : b+=((quint32)k[5])<<16;
+ Q_FALLTHROUGH();
+ case 5 : b+=((quint32)k[4])<<24;
+ Q_FALLTHROUGH();
+ case 4 : a+=k[3];
+ Q_FALLTHROUGH();
+ case 3 : a+=((quint32)k[2])<<8;
+ Q_FALLTHROUGH();
+ case 2 : a+=((quint32)k[1])<<16;
+ Q_FALLTHROUGH();
+ case 1 : a+=((quint32)k[0])<<24;
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
diff --git a/tests/baseline/shared/qbaselinetest.cpp b/tests/baseline/shared/qbaselinetest.cpp
new file mode 100644
index 0000000000..3587cd01ea
--- /dev/null
+++ b/tests/baseline/shared/qbaselinetest.cpp
@@ -0,0 +1,423 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qbaselinetest.h"
+#include "baselineprotocol.h"
+#include <QtCore/QDir>
+#include <QFile>
+
+#define MAXCMDLINEARGS 128
+
+namespace QBaselineTest {
+
+static char *fargv[MAXCMDLINEARGS];
+static bool simfail = false;
+static PlatformInfo customInfo;
+static bool customAutoModeSet = false;
+
+static BaselineProtocol proto;
+static bool connected = false;
+static bool triedConnecting = false;
+static bool dryRunMode = false;
+static enum { UploadMissing, UploadAll, UploadNone } baselinePolicy = UploadMissing;
+
+static QByteArray curFunction;
+static ImageItemList itemList;
+static bool gotBaselines;
+
+static QString definedTestProject;
+static QString definedTestCase;
+
+
+void handleCmdLineArgs(int *argcp, char ***argvp)
+{
+ if (!argcp || !argvp)
+ return;
+
+ bool showHelp = false;
+
+ int fargc = 0;
+ int numArgs = *argcp;
+
+ for (int i = 0; i < numArgs; i++) {
+ QByteArray arg = (*argvp)[i];
+ QByteArray nextArg = (i+1 < numArgs) ? (*argvp)[i+1] : 0;
+
+ if (arg == "-simfail") {
+ simfail = true;
+ } else if (arg == "-fuzzlevel") {
+ i++;
+ bool ok = false;
+ (void)nextArg.toInt(&ok);
+ if (!ok) {
+ qWarning() << "-fuzzlevel requires integer parameter";
+ showHelp = true;
+ break;
+ }
+ customInfo.insert("FuzzLevel", QString::fromLatin1(nextArg));
+ } else if (arg == "-auto") {
+ customAutoModeSet = true;
+ customInfo.setAdHocRun(false);
+ } else if (arg == "-adhoc") {
+ customAutoModeSet = true;
+ customInfo.setAdHocRun(true);
+ } else if (arg == "-setbaselines") {
+ baselinePolicy = UploadAll;
+ } else if (arg == "-nosetbaselines") {
+ baselinePolicy = UploadNone;
+ } else if (arg == "-compareto") {
+ i++;
+ int split = qMax(0, nextArg.indexOf('='));
+ QByteArray key = nextArg.left(split).trimmed();
+ QByteArray value = nextArg.mid(split+1).trimmed();
+ if (key.isEmpty() || value.isEmpty()) {
+ qWarning() << "-compareto requires parameter of the form <key>=<value>";
+ showHelp = true;
+ break;
+ }
+ customInfo.addOverride(key, value);
+ } else {
+ if ( (arg == "-help") || (arg == "--help") )
+ showHelp = true;
+ if (fargc >= MAXCMDLINEARGS) {
+ qWarning() << "Too many command line arguments!";
+ break;
+ }
+ fargv[fargc++] = (*argvp)[i];
+ }
+ }
+ *argcp = fargc;
+ *argvp = fargv;
+
+ if (showHelp) {
+ // TBD: arrange for this to be printed *after* QTest's help
+ QTextStream out(stdout);
+ out << "\n Baseline testing (lancelot) options:\n";
+ out << " -simfail : Force an image comparison mismatch. For testing purposes.\n";
+ out << " -fuzzlevel <int> : Specify the percentage of fuzziness in comparison. Overrides server default. 0 means exact match.\n";
+ out << " -auto : Inform server that this run is done by a daemon, CI system or similar.\n";
+ out << " -adhoc (default) : The inverse of -auto; this run is done by human, e.g. for testing.\n";
+ out << " -setbaselines : Store ALL rendered images as new baselines. Forces replacement of previous baselines.\n";
+ out << " -nosetbaselines : Do not store rendered images as new baselines when previous baselines are missing.\n";
+ out << " -compareto KEY=VAL : Force comparison to baselines from a different client,\n";
+ out << " for example: -compareto QtVersion=4.8.0\n";
+ out << " Multiple -compareto client specifications may be given.\n";
+ out << "\n";
+ }
+}
+
+
+void addClientProperty(const QString& key, const QString& value)
+{
+ customInfo.insert(key, value);
+}
+
+
+/*
+ If a client property script is present, run it and accept its output
+ in the form of one 'key: value' property per line
+*/
+void fetchCustomClientProperties()
+{
+ QFile file("hostinfo.txt");
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ return;
+ QTextStream in(&file);
+
+ while (!in.atEnd()) {
+ QString line = in.readLine().trimmed(); // ###local8bit? utf8?
+ if (line.startsWith(QLatin1Char('#'))) // Ignore comments in file
+ continue;
+ QString key, val;
+ int colonPos = line.indexOf(':');
+ if (colonPos > 0) {
+ key = line.left(colonPos).simplified().replace(' ', '_');
+ val = line.mid(colonPos+1).trimmed();
+ }
+ if (!key.isEmpty() && key.length() < 64 && val.length() < 256) // ###TBD: maximum 256 chars in value?
+ addClientProperty(key, val);
+ else
+ qDebug() << "Unparseable script output ignored:" << line;
+ }
+}
+
+
+bool connect(QByteArray *msg, bool *error)
+{
+ if (connected) {
+ return true;
+ }
+ else if (triedConnecting) {
+ // Avoid repeated connection attempts, to avoid the program using Timeout * #testItems seconds before giving up
+ *msg = "Not connected to baseline server.";
+ *error = true;
+ return false;
+ }
+
+ triedConnecting = true;
+ fetchCustomClientProperties();
+ // Merge the platform info set by the program with the protocols default info
+ PlatformInfo clientInfo = customInfo;
+ PlatformInfo defaultInfo = PlatformInfo::localHostInfo();
+ foreach (QString key, defaultInfo.keys()) {
+ if (!clientInfo.contains(key))
+ clientInfo.insert(key, defaultInfo.value(key));
+ }
+ if (!customAutoModeSet)
+ clientInfo.setAdHocRun(defaultInfo.isAdHocRun());
+
+ if (!definedTestProject.isEmpty())
+ clientInfo.insert(PI_Project, definedTestProject);
+
+ QString testCase = definedTestCase;
+ if (testCase.isEmpty() && QTest::testObject() && QTest::testObject()->metaObject()) {
+ //qDebug() << "Trying to Read TestCaseName from Testlib!";
+ testCase = QTest::testObject()->metaObject()->className();
+ }
+ if (testCase.isEmpty()) {
+ qWarning("QBaselineTest::connect: No test case name specified, cannot connect.");
+ return false;
+ }
+
+ if (!proto.connect(testCase, &dryRunMode, clientInfo)) {
+ *msg += "Failed to connect to baseline server: " + proto.errorMessage().toLatin1();
+ *error = true;
+ return false;
+ }
+ connected = true;
+ return true;
+}
+
+bool disconnectFromBaselineServer()
+{
+ if (proto.disconnect()) {
+ connected = false;
+ triedConnecting = false;
+ return true;
+ }
+
+ return false;
+}
+
+bool connectToBaselineServer(QByteArray *msg, const QString &testProject, const QString &testCase)
+{
+ bool dummy;
+ QByteArray dummyMsg;
+
+ definedTestProject = testProject;
+ definedTestCase = testCase;
+
+ return connect(msg ? msg : &dummyMsg, &dummy);
+}
+
+void setAutoMode(bool mode)
+{
+ customInfo.setAdHocRun(!mode);
+ customAutoModeSet = true;
+}
+
+void setSimFail(bool fail)
+{
+ simfail = fail;
+}
+
+
+void modifyImage(QImage *img)
+{
+ uint c0 = 0x0000ff00;
+ uint c1 = 0x0080ff00;
+ img->setPixel(1,1,c0);
+ img->setPixel(2,1,c1);
+ img->setPixel(3,1,c0);
+ img->setPixel(1,2,c1);
+ img->setPixel(1,3,c0);
+ img->setPixel(2,3,c1);
+ img->setPixel(3,3,c0);
+ img->setPixel(1,4,c1);
+ img->setPixel(1,5,c0);
+}
+
+
+bool compareItem(const ImageItem &baseline, const QImage &img, QByteArray *msg, bool *error)
+{
+ ImageItem item = baseline;
+ if (simfail) {
+ // Simulate test failure by forcing image mismatch; for testing purposes
+ QImage misImg = img;
+ modifyImage(&misImg);
+ item.image = misImg;
+ simfail = false; // One failure is typically enough
+ } else {
+ item.image = img;
+ }
+ item.imageChecksums.clear();
+ item.imageChecksums.prepend(ImageItem::computeChecksum(item.image));
+ QByteArray srvMsg;
+ switch (baseline.status) {
+ case ImageItem::Ok:
+ break;
+ case ImageItem::IgnoreItem :
+ qDebug() << msg->constData() << "Ignored, blacklisted on server.";
+ return true;
+ break;
+ case ImageItem::BaselineNotFound:
+ if (!customInfo.overrides().isEmpty() || baselinePolicy == UploadNone) {
+ qWarning() << "Cannot compare to baseline: No such baseline found on server.";
+ return true;
+ }
+ if (proto.submitNewBaseline(item, &srvMsg))
+ qDebug() << msg->constData() << "Baseline not found on server. New baseline uploaded.";
+ else
+ qDebug() << msg->constData() << "Baseline not found on server. Uploading of new baseline failed:" << srvMsg;
+ return true;
+ break;
+ default:
+ qWarning() << "Unexpected reply from baseline server.";
+ return true;
+ break;
+ }
+ *error = false;
+ // The actual comparison of the given image with the baseline:
+ if (baseline.imageChecksums.contains(item.imageChecksums.at(0))) {
+ if (!proto.submitMatch(item, &srvMsg))
+ qWarning() << "Failed to report image match to server:" << srvMsg;
+ return true;
+ }
+ // At this point, we have established a legitimate mismatch
+ if (baselinePolicy == UploadAll) {
+ if (proto.submitNewBaseline(item, &srvMsg))
+ qDebug() << msg->constData() << "Forcing new baseline; uploaded ok.";
+ else
+ qDebug() << msg->constData() << "Forcing new baseline; uploading failed:" << srvMsg;
+ return true;
+ }
+ bool fuzzyMatch = false;
+ bool res = proto.submitMismatch(item, &srvMsg, &fuzzyMatch);
+ if (res && fuzzyMatch) {
+ *error = true; // To force a QSKIP/debug output; somewhat kludgy
+ *msg += srvMsg;
+ return true; // The server decides: a fuzzy match means no mismatch
+ }
+ *msg += "Mismatch. See report:\n " + srvMsg;
+ if (dryRunMode) {
+ qDebug() << "Dryrun, so ignoring" << *msg;
+ return true;
+ }
+ return false;
+}
+
+bool checkImage(const QImage &img, const char *name, quint16 checksum, QByteArray *msg, bool *error, int manualdatatag)
+{
+ if (!connected && !connect(msg, error))
+ return true;
+
+ QByteArray itemName;
+ bool hasName = qstrlen(name);
+
+ const char *tag = QTest::currentDataTag();
+ if (qstrlen(tag)) {
+ itemName = tag;
+ if (hasName)
+ itemName.append('_').append(name);
+ } else {
+ itemName = hasName ? name : "default_name";
+ }
+
+ if (manualdatatag > 0)
+ {
+ itemName.prepend("_");
+ itemName.prepend(QByteArray::number(manualdatatag));
+ }
+
+ *msg = "Baseline check of image '" + itemName + "': ";
+
+
+ ImageItem item;
+ item.itemName = QString::fromLatin1(itemName);
+ item.itemChecksum = checksum;
+ item.testFunction = QString::fromLatin1(QTest::currentTestFunction());
+ ImageItemList list;
+ list.append(item);
+ if (!proto.requestBaselineChecksums(QLatin1String(QTest::currentTestFunction()), &list) || list.isEmpty()) {
+ *msg = "Communication with baseline server failed: " + proto.errorMessage().toLatin1();
+ *error = true;
+ return true;
+ }
+
+ return compareItem(list.at(0), img, msg, error);
+}
+
+
+QTestData &newRow(const char *dataTag, quint16 checksum)
+{
+ if (QTest::currentTestFunction() != curFunction) {
+ curFunction = QTest::currentTestFunction();
+ itemList.clear();
+ gotBaselines = false;
+ }
+ ImageItem item;
+ item.itemName = QString::fromLatin1(dataTag);
+ item.itemChecksum = checksum;
+ item.testFunction = QString::fromLatin1(QTest::currentTestFunction());
+ itemList.append(item);
+
+ return QTest::newRow(dataTag);
+}
+
+
+bool testImage(const QImage& img, QByteArray *msg, bool *error)
+{
+ if (!connected && !connect(msg, error))
+ return true;
+
+ if (QTest::currentTestFunction() != curFunction || itemList.isEmpty()) {
+ qWarning() << "Usage error: QBASELINE_TEST used without corresponding QBaselineTest::newRow()";
+ return true;
+ }
+
+ if (!gotBaselines) {
+ if (!proto.requestBaselineChecksums(QString::fromLatin1(QTest::currentTestFunction()), &itemList) || itemList.isEmpty()) {
+ *msg = "Communication with baseline server failed: " + proto.errorMessage().toLatin1();
+ *error = true;
+ return true;
+ }
+ gotBaselines = true;
+ }
+
+ QString curTag = QString::fromLatin1(QTest::currentDataTag());
+ ImageItemList::const_iterator it = itemList.constBegin();
+ while (it != itemList.constEnd() && it->itemName != curTag)
+ ++it;
+ if (it == itemList.constEnd()) {
+ qWarning() << "Usage error: QBASELINE_TEST used without corresponding QBaselineTest::newRow() for row" << curTag;
+ return true;
+ }
+ return compareItem(*it, img, msg, error);
+}
+
+}
diff --git a/tests/baseline/shared/qbaselinetest.h b/tests/baseline/shared/qbaselinetest.h
new file mode 100644
index 0000000000..ede0fe42e3
--- /dev/null
+++ b/tests/baseline/shared/qbaselinetest.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BASELINETEST_H
+#define BASELINETEST_H
+
+#include <QTest>
+
+namespace QBaselineTest {
+void setAutoMode(bool mode);
+void setSimFail(bool fail);
+void handleCmdLineArgs(int *argcp, char ***argvp);
+void addClientProperty(const QString& key, const QString& value);
+bool connectToBaselineServer(QByteArray *msg = nullptr, const QString &testProject = QString(), const QString &testCase = QString());
+bool checkImage(const QImage& img, const char *name, quint16 checksum, QByteArray *msg, bool *error, int manualdatatag = 0);
+bool testImage(const QImage& img, QByteArray *msg, bool *error);
+QTestData &newRow(const char *dataTag, quint16 checksum = 0);
+bool disconnectFromBaselineServer();
+}
+
+#define QBASELINE_CHECK_SUM(image, name, checksum)\
+do {\
+ QByteArray _msg;\
+ bool _err = false;\
+ if (!QBaselineTest::checkImage((image), (name), (checksum), &_msg, &_err)) {\
+ QFAIL(_msg.constData());\
+ } else if (_err) {\
+ QSKIP(_msg.constData());\
+ }\
+} while (0)
+
+#define QBASELINE_CHECK(image, name) QBASELINE_CHECK_SUM(image, name, 0)
+
+#define QBASELINE_TEST(image)\
+do {\
+ QByteArray _msg;\
+ bool _err = false;\
+ if (!QBaselineTest::testImage((image), &_msg, &_err)) {\
+ QFAIL(_msg.constData());\
+ } else if (_err) {\
+ QSKIP(_msg.constData());\
+ }\
+} while (0)
+
+#endif // BASELINETEST_H
diff --git a/tests/baseline/shared/qbaselinetest.pri b/tests/baseline/shared/qbaselinetest.pri
new file mode 100644
index 0000000000..921871b189
--- /dev/null
+++ b/tests/baseline/shared/qbaselinetest.pri
@@ -0,0 +1,13 @@
+QT *= testlib
+
+SOURCES += \
+ $$PWD/qbaselinetest.cpp
+
+HEADERS += \
+ $$PWD/qbaselinetest.h
+
+win32:MKSPEC=$$replace(QMAKESPEC, \\\\, /)
+else:MKSPEC=$$QMAKESPEC
+DEFINES += QMAKESPEC=\\\"$$MKSPEC\\\"
+
+include($$PWD/baselineprotocol.pri)