tests/arthur/common/paintcommands.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/arthur/common/paintcommands.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,2641 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "paintcommands.h"
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qpainter.h>
+#include <qbitmap.h>
+#include <qtextstream.h>
+#include <qtextlayout.h>
+#include <qdebug.h>
+
+#ifdef QT3_SUPPORT
+#include <q3painter.h>
+#endif
+
+#ifndef QT_NO_OPENGL
+#include <qglpixelbuffer.h>
+#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::clipOperationTable[] = {
+    "NoClip",
+    "ReplaceClip",
+    "IntersectClip",
+    "UniteClip"
+};
+
+const char *PaintCommands::spreadMethodTable[] = {
+    "PadSpread",
+    "ReflectSpread",
+    "RepeatSpread"
+};
+
+const char *PaintCommands::coordinateMethodTable[] = {
+    "LogicalMode",
+    "StretchToDeviceMode",
+    "ObjectBoundingMode"
+};
+
+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"
+};
+
+int PaintCommands::translateEnum(const char *table[], const QString &pattern, int limit)
+{
+    for (int i=0; i<limit; ++i)
+        if (pattern.toLower() == QString(QLatin1String(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> >();
+
+#define DECL_PAINTCOMMAND(identifier, method, regexp, syntax, sample) \
+    s_commandInfoTable << PaintCommandInfos(QLatin1String(identifier), &PaintCommands::method, QRegExp(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$",
+                      "end_block",
+                      "end_block");
+    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 <pixmapFileName>\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*)$",
+                      "setFont <fontFace> [size] [font weight|font weight enum] [italic]\n  - font weight is an integer between 0 and 99",
+                      "setFont \"times\" normal");
+    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 angle in degrees\n  - F is the focal point",
+                      "gradient_setRadial 1.0 1.0 45.0 2.0 2.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");
+#ifdef QT3_SUPPORT
+    DECL_PAINTCOMMANDSECTION("qt3 drawing ops");
+    DECL_PAINTCOMMAND("qt3_drawArc", command_qt3_drawArc,
+                      "^qt3_drawArc\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+                      "qt3_drawArc <x> <y> <w> <h> <angleStart> <angleArc>\n  - angles are expressed in 1/16th of degree",
+                      "qt3_drawArc 10 10 20 20 0 5760");
+    DECL_PAINTCOMMAND("qt3_drawChord", command_qt3_drawChord,
+                      "^qt3_drawChord\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+                      "qt3_drawChord <x> <y> <w> <h> <angleStart> <angleArc>\n  - angles are expressed in 1/16th of degree",
+                      "qt3_drawChord 10 10 20 20 0 5760");
+    DECL_PAINTCOMMAND("qt3_drawEllipse", command_qt3_drawEllipse,
+                      "^qt3_drawEllipse\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+                      "qt3_drawEllipse <x> <y> <w> <h>",
+                      "qt3_drawEllipse 10 10 20 20");
+    DECL_PAINTCOMMAND("qt3_drawPie", command_qt3_drawPie,
+                      "^qt3_drawPie\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+                      "qt3_drawPie <x> <y> <w> <h> <angleStart> <angleArc>\n  - angles are expressed in 1/16th of degree",
+                      "qt3_drawPie 10 10 20 20 0 5760");
+    DECL_PAINTCOMMAND("qt3_drawRect", command_qt3_drawRect,
+                      "^qt3_drawRect\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)$",
+                      "qt3_drawRect <x> <y> <w> <h>",
+                      "qt3_drawRect 10 10 20 20");
+    DECL_PAINTCOMMAND("qt3_drawRoundRect", command_qt3_drawRoundRect,
+                      "^qt3_drawRoundRect\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s*(-?\\w)?\\s*(-?\\w)?$",
+                      "qt3_drawRoundRect <x> <y> <w> <h> [rx] [ry]",
+                      "qt3_drawRoundRect 10 10 20 20 3 3");
+#endif
+    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("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("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_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("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_setNumColors", command_image_setNumColors,
+                      "^image_setNumColors\\s+([\\w.:\\/]*)\\s+([0-9]*)$",
+                      "image_setNumColors <imageName> <nbColors>",
+                      "image_setNumColors myImage 128");
+
+    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 enums list
+    ADD_ENUMLIST("brush styles", brushStyleTable);
+    ADD_ENUMLIST("pen styles", penStyleTable);
+    ADD_ENUMLIST("font weights", fontWeightTable);
+    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 = QString("%1/%2").arg(dir.absolutePath()).arg(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)
+{
+    staticInit();
+    foreach (PaintCommandInfos command, s_commandInfoTable)
+        if (!command.isSectionHeader() && command.regExp.indexIn(scriptLine) >= 0) {
+            (this->*(command.paintMethod))(command.regExp);
+            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;
+
+    // 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));
+
+        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 QRegExp 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;
+    }
+    if (re.indexIn(str) >= 0) {
+        int index = re.cap(1).toInt();
+        bool is_it_x = re.cap(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 QRegExp alphaColor("#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})");
+    static QRegExp opaqueColor("#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})");
+
+    Q_ASSERT(alphaColor.isValid());
+    Q_ASSERT(opaqueColor.isValid());
+
+    if (alphaColor.indexIn(str) >= 0) {
+        return QColor(alphaColor.cap(2).toInt(0, 16),
+                      alphaColor.cap(3).toInt(0, 16),
+                      alphaColor.cap(4).toInt(0, 16),
+                      alphaColor.cap(1).toInt(0, 16));
+    } else if (opaqueColor.indexIn(str) >= 0) {
+        return QColor(opaqueColor.cap(1).toInt(0, 16),
+                      opaqueColor.cap(2).toInt(0, 16),
+                      opaqueColor.cap(3).toInt(0, 16));
+    }
+    return QColor(str);
+}
+
+/*********************************************************************************
+** command implementations
+**********************************************************************************/
+void PaintCommands::command_comment(QRegExp)
+{
+    if (m_verboseMode)
+        printf(" -(lance) comment: %s\n", qPrintable(m_currentCommand));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_import(QRegExp re)
+{
+    QString importFile(re.cap(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] = QString("# import file (%1) start").arg(fileinfo.fileName());
+    QTextStream textFile(file);
+    QString rawContent = textFile.readAll();
+    QStringList importedData = rawContent.split('\n', QString::SkipEmptyParts);
+    importedData.append(QString("# import file (%1) end ---").arg(fileinfo.fileName()));
+    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(QRegExp re)
+{
+    const QString &blockName = re.cap(1);
+    if (m_verboseMode)
+        printf(" -(lance) begin_block (%s)\n", qPrintable(blockName));
+
+    m_commands[m_currentCommandIndex] = QString("# begin block (%1)").arg(blockName);
+    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] = QString("# end block (%1)").arg(blockName);
+            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(QRegExp)
+{
+    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(QRegExp re)
+{
+    QString blockName = re.cap(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] = QString("# repeated block (%1)").arg(blockName);
+    insertAt(m_currentCommandIndex, block);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawLine(QRegExp 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_drawPath(QRegExp re)
+{
+    if (m_verboseMode)
+        printf(" -(lance) drawPath(name=%s)\n", qPrintable(re.cap(1)));
+
+    QPainterPath &path = m_pathMap[re.cap(1)];
+    m_painter->drawPath(path);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawPixmap(QRegExp re)
+{
+    QPixmap pm;
+    pm = m_pixmapMap[re.cap(1)]; // try cache first
+    if (pm.isNull())
+        pm = image_load<QPixmap>(re.cap(1));
+    if (pm.isNull()) {
+        QFileInfo fi(m_filepath);
+        QDir dir = fi.absoluteDir();
+        dir.cdUp();
+        dir.cd("images");
+        QString fileName = QString("%1/%2").arg(dir.absolutePath()).arg(re.cap(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.cap(1)));
+        return;
+    }
+
+    qreal tx = convertToFloat(re.cap(2));
+    qreal ty = convertToFloat(re.cap(3));
+    qreal tw = convertToFloat(re.cap(4));
+    qreal th = convertToFloat(re.cap(5));
+
+    qreal sx = convertToFloat(re.cap(6));
+    qreal sy = convertToFloat(re.cap(7));
+    qreal sw = convertToFloat(re.cap(8));
+    qreal sh = convertToFloat(re.cap(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, (%d, %d, %d, %d), (%d, %d, %d, %d)\n",
+               qPrintable(re.cap(1)), pm.width(), pm.height(), pm.depth(),
+               tx, ty, tw, th, sx, sy, sw, sh);
+
+    m_painter->drawPixmap(QRectF(tx, ty, tw, th), pm, QRectF(sx, sy, sw, sh));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawImage(QRegExp re)
+{
+    QImage im;
+    im = m_imageMap[re.cap(1)]; // try cache first
+    if (im.isNull())
+        im = image_load<QImage>(re.cap(1));
+
+    if (im.isNull()) {
+        QFileInfo fi(m_filepath);
+        QDir dir = fi.absoluteDir();
+        dir.cdUp();
+        dir.cd("images");
+        QString fileName = QString("%1/%2").arg(dir.absolutePath()).arg(re.cap(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.cap(1)));
+        return;
+    }
+
+    qreal tx = convertToFloat(re.cap(2));
+    qreal ty = convertToFloat(re.cap(3));
+    qreal tw = convertToFloat(re.cap(4));
+    qreal th = convertToFloat(re.cap(5));
+
+    qreal sx = convertToFloat(re.cap(6));
+    qreal sy = convertToFloat(re.cap(7));
+    qreal sw = convertToFloat(re.cap(8));
+    qreal sh = convertToFloat(re.cap(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), (%d, %d, %d, %d), (%d, %d, %d, %d)\n",
+               qPrintable(re.cap(1)), im.width(), im.height(), tx, ty, tw, th, sx, sy, sw, sh);
+
+    m_painter->drawImage(QRectF(tx, ty, tw, th), im, QRectF(sx, sy, sw, sh), Qt::OrderedDither | Qt::OrderedAlphaDither);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawTiledPixmap(QRegExp re)
+{
+    QPixmap pm;
+    pm = m_pixmapMap[re.cap(1)]; // try cache first
+    if (pm.isNull())
+        pm = image_load<QPixmap>(re.cap(1));
+    if (pm.isNull()) {
+        QFileInfo fi(m_filepath);
+        QDir dir = fi.absoluteDir();
+        dir.cdUp();
+        dir.cd("images");
+        QString fileName = QString("%1/%2").arg(dir.absolutePath()).arg(re.cap(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.cap(1)));
+        return;
+    }
+
+    int tx = convertToInt(re.cap(2));
+    int ty = convertToInt(re.cap(3));
+    int tw = convertToInt(re.cap(4));
+    int th = convertToInt(re.cap(5));
+
+    int sx = convertToInt(re.cap(6));
+    int sy = convertToInt(re.cap(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.cap(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(QRegExp 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(QRegExp re)
+{
+    static QRegExp separators("\\s");
+    QStringList caps = re.capturedTexts();
+    QString cap = caps.at(1);
+    QStringList numbers = cap.split(separators, QString::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=%d)\n", array.size());
+
+    m_painter->drawPolygon(array, caps.at(2).toLower() == "winding" ? Qt::WindingFill : Qt::OddEvenFill);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawPolyline(QRegExp re)
+{
+    static QRegExp separators("\\s");
+    QStringList numbers = re.cap(1).split(separators, QString::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=%d)\n", array.size());
+
+    m_painter->drawPolyline(array.toPolygon());
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawRect(QRegExp 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(QRegExp 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(QRegExp 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);
+
+    m_painter->drawRoundRect(x, y, w, h, xs, ys);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_drawEllipse(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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);
+}
+
+#ifdef QT3_SUPPORT
+/***************************************************************************************************/
+void PaintCommands::command_qt3_drawRect(QRegExp re)
+{
+    Q_UNUSED(re);
+#ifdef QT3_SUPPORT
+    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 (m_verboseMode)
+        printf(" -(lance) qt3_drawRect(%d, %d, %d, %d)\n", x, y, w, h);
+
+    static_cast<Q3Painter*>(m_painter)->drawRect(x, y, w, h);
+#endif
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_qt3_drawRoundRect(QRegExp re)
+{
+    Q_UNUSED(re);
+#ifdef QT3_SUPPORT
+    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 xrnd = caps.at(5).isEmpty() ? 25 : convertToInt(caps.at(5));
+    int yrnd = caps.at(6).isEmpty() ? 25 : convertToInt(caps.at(6));
+
+    if (m_verboseMode)
+        printf(" -(lance) qt3_drawRoundRect(%d, %d, %d, %d), %d, %d\n", x, y, w, h, xrnd, yrnd);
+
+    static_cast<Q3Painter*>(m_painter)->drawRoundRect(x, y, w, h, xrnd, yrnd);
+#endif
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_qt3_drawEllipse(QRegExp re)
+{
+    Q_UNUSED(re);
+#ifdef QT3_SUPPORT
+    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 (m_verboseMode)
+        printf(" -(lance) qt3_drawEllipse(%d, %d, %d, %d)\n", x, y, w, h);
+
+    static_cast<Q3Painter*>(m_painter)->drawEllipse(x, y, w, h);
+#endif
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_qt3_drawPie(QRegExp re)
+{
+    Q_UNUSED(re);
+#ifdef QT3_SUPPORT
+    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) qt3_drawPie(%d, %d, %d, %d, %d, %d)\n", x, y, w, h, angle, sweep);
+
+    static_cast<Q3Painter*>(m_painter)->drawPie(x, y, w, h, angle, sweep);
+#endif
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_qt3_drawChord(QRegExp re)
+{
+    Q_UNUSED(re);
+#ifdef QT3_SUPPORT
+    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) qt3_drawChord(%d, %d, %d, %d, %d, %d)\n", x, y, w, h, angle, sweep);
+
+    static_cast<Q3Painter*>(m_painter)->drawChord(x, y, w, h, angle, sweep);
+#endif
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_qt3_drawArc(QRegExp re)
+{
+    Q_UNUSED(re);
+#ifdef QT3_SUPPORT
+    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) qt3_drawArc(%d, %d, %d, %d, %d, %d)\n", x, y, w, h, angle, sweep);
+
+    static_cast<Q3Painter*>(m_painter)->drawArc(x, y, w, h, angle, sweep);
+#endif
+}
+#endif //QT3_SUPPORT
+/***************************************************************************************************/
+void PaintCommands::command_drawText(QRegExp re)
+{
+    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_noop(QRegExp)
+{
+    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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp re)
+{
+    static QRegExp separators("\\s");
+    QStringList caps = re.capturedTexts();
+    QString name = caps.at(1);
+    QString cap = caps.at(2);
+    QStringList numbers = cap.split(separators, QString::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=%d)\n", qPrintable(name), array.size());
+
+    m_pathMap[name].addPolygon(array);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_path_arcTo(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp re)
+{
+    QStringList caps = re.capturedTexts();
+    QString name = caps.at(1);
+    qt_debug_path(m_pathMap[name], name);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_region_addRect(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp)
+{
+    if (m_verboseMode)
+        printf(" -(lance) resetMatrix()\n");
+
+    m_painter->resetTransform();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_restore(QRegExp)
+{
+    if (m_verboseMode)
+        printf(" -(lance) restore()\n");
+
+    m_painter->restore();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_rotate(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp)
+{
+    if (m_verboseMode)
+        printf(" -(lance) save()\n");
+
+    m_painter->save();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_mapQuadToQuad(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp re)
+{
+    QString cap = re.cap(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(QRegExp re)
+{
+    QStringList caps = re.capturedTexts();
+
+    QPixmap pm = image_load<QPixmap>(caps.at(1));
+    if (!pm.isNull()) { // Assume pixmap
+        if (m_verboseMode)
+            printf(" -(lance) setBrush(pixmap=%s, width=%d, height=%d)\n",
+                   qPrintable(caps.at(1)), pm.width(), pm.height());
+
+        m_painter->setBrush(QBrush(pm));
+    } 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(QRegExp re)
+{
+    int x = convertToInt(re.cap(1));
+    int y = convertToInt(re.cap(2));
+
+    if (m_verboseMode)
+        printf(" -(lance) setBrushOrigin(%d, %d)\n", x, y);
+
+    m_painter->setBrushOrigin(x, y);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_brushTranslate(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp re)
+{
+    bool clipping = re.cap(1).toLower() == "true";
+
+    if (m_verboseMode)
+        printf(" -(lance) setClipping(%d)\n", clipping);
+
+    m_painter->setClipping(clipping);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setClipRect(QRegExp 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::UniteClip + 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(QRegExp re)
+{
+    int combine = translateEnum(clipOperationTable, re.cap(2), Qt::UniteClip + 1);
+    if (combine == -1)
+        combine = Qt::ReplaceClip;
+
+    if (m_verboseMode)
+        printf(" -(lance) setClipPath(name=%s), %s\n", qPrintable(re.cap(1)), clipOperationTable[combine]);
+
+    if (!m_pathMap.contains(re.cap(1)))
+        fprintf(stderr, " - setClipPath, no such path");
+    m_painter->setClipPath(m_pathMap[re.cap(1)], Qt::ClipOperation(combine));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setClipRegion(QRegExp re)
+{
+    int combine = translateEnum(clipOperationTable, re.cap(2), Qt::UniteClip + 1);
+    if (combine == -1)
+        combine = Qt::ReplaceClip;
+    QRegion r = m_regionMap[re.cap(1)];
+
+    if (m_verboseMode)
+        printf(" -(lance) setClipRegion(name=%s), bounds=[%d, %d, %d, %d], %s\n",
+               qPrintable(re.cap(1)),
+               r.boundingRect().x(),
+               r.boundingRect().y(),
+               r.boundingRect().width(),
+               r.boundingRect().height(),
+               clipOperationTable[combine]);
+
+    m_painter->setClipRegion(m_regionMap[re.cap(1)], Qt::ClipOperation(combine));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setFont(QRegExp re)
+{
+    QStringList caps = re.capturedTexts();
+    QString family = caps.at(1);
+    int size = convertToInt(caps.at(2));
+
+    int weight = translateEnum(fontWeightTable, re.cap(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.cap(3));
+    }
+
+    bool italic = caps.at(4).toLower() == "true" || caps.at(4).toLower() == "italic";
+
+    if (m_verboseMode)
+        printf(" -(lance) setFont(family=%s, size=%d, weight=%d, italic=%d\n",
+               qPrintable(family), size, weight, italic);
+
+    m_painter->setFont(QFont(family, size, weight, italic));
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setPen(QRegExp re)
+{
+    QString cap = re.cap(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(QRegExp 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(QRegExp re)
+{
+    QString hintString = re.cap(1).toLower();
+    bool on = re.cap(2).isEmpty() || re.cap(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(QRegExp /*re*/)
+{
+    m_painter->setRenderHint(QPainter::Antialiasing, false);
+    m_painter->setRenderHint(QPainter::SmoothPixmapTransform, false);
+    if (m_verboseMode)
+        printf(" -(lance) clearRenderHint\n");
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setCompositionMode(QRegExp re)
+{
+    QString modeString = re.cap(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(QRegExp 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(QRegExp 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(QRegExp 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_setMask(QRegExp 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(QRegExp 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_setNumColors(QRegExp re)
+{
+    QStringList caps = re.capturedTexts();
+
+    QString name = caps.at(1);
+    int count = convertToInt(caps.at(2));
+
+    if (m_verboseMode)
+        printf(" -(lance) image_setNumColors(%s), %d -> %d\n",
+               qPrintable(name), m_imageMap[name].numColors(), count);
+
+    m_imageMap[name].setNumColors(count);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_image_setColor(QRegExp 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_abort(QRegExp)
+{
+    m_abort = true;
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_clearStops(QRegExp)
+{
+    if (m_verboseMode)
+        printf(" -(lance) gradient_clearStops\n");
+    m_gradientStops.clear();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_gradient_appendStop(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp 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_setConical(QRegExp 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(QRegExp re)
+{
+    int spreadMethod = translateEnum(spreadMethodTable, re.cap(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(QRegExp re)
+{
+    int coord = translateEnum(coordinateMethodTable, re.cap(1), 3);
+
+    if (m_verboseMode)
+        printf(" -(lance) gradient_setCoordinateMode %d=[%s]\n", coord,
+               coordinateMethodTable[coord]);
+
+    m_gradientCoordinate = QGradient::CoordinateMode(coord);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_surface_begin(QRegExp 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 == OpenGLPBufferType) {
+#ifndef QT_NO_OPENGL
+        m_surface_pbuffer = new QGLPixelBuffer(qRound(w), qRound(h));
+        m_painter = new QPainter(m_surface_pbuffer);
+        m_painter->fillRect(QRect(0, 0, qRound(w), qRound(h)), Qt::transparent);
+#endif
+#ifdef Q_WS_X11
+    } else if (m_type == WidgetType) {
+        m_surface_pixmap = QPixmap(qRound(w), qRound(h));
+        m_surface_pixmap.fill(Qt::transparent);
+        m_painter = new QPainter(&m_surface_pixmap);
+#endif
+    } else {
+        m_surface_image = QImage(qRound(w), qRound(h), QImage::Format_ARGB32_Premultiplied);
+        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(QRegExp)
+{
+    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 == OpenGLPBufferType) {
+#ifndef QT_NO_OPENGL
+        QImage image = m_surface_pbuffer->toImage();
+        QImage new_image(image.bits(), image.width(),
+                         image.height(), QImage::Format_ARGB32_Premultiplied);
+        QPaintDevice *pdev = m_painter->device();
+        if (pdev->devType() == QInternal::Widget) {
+            QWidget *w = static_cast<QWidget *>(pdev);
+            static_cast<QGLWidget *>(w)->makeCurrent();
+        } else if (pdev->devType() == QInternal::Pbuffer) {
+            static_cast<QGLPixelBuffer *>(pdev)->makeCurrent();
+        }
+
+        m_painter->drawImage(m_surface_rect, new_image);
+
+        delete m_surface_pbuffer;
+        m_surface_pbuffer = 0;
+#endif
+#ifdef Q_WS_X11
+    } else if (m_type == WidgetType) {
+        m_painter->drawPixmap(m_surface_rect.topLeft(), m_surface_pixmap);
+        m_surface_pixmap = QPixmap();
+#endif
+    } else {
+        m_painter->drawImage(m_surface_rect, m_surface_image);
+        m_surface_image = QImage();
+    }
+    m_surface_rect = QRectF();
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_image_convertToFormat(QRegExp 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(QRegExp 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(QRegExp 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(QRegExp re)
+{
+    static QRegExp separators("\\s");
+    QStringList caps = re.capturedTexts();
+    QString cap = caps.at(1);
+    QStringList numbers = cap.split(separators, QString::SkipEmptyParts);
+
+    QVector<qreal> pattern;
+    for (int i=0; i<numbers.size(); ++i)
+        pattern.append(convertToDouble(numbers.at(i)));
+
+    if (m_verboseMode)
+        printf(" -(lance) pen_setDashPattern(size=%d)\n", pattern.size());
+
+    QPen p = m_painter->pen();
+    p.setDashPattern(pattern);
+    m_painter->setPen(p);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_pen_setCosmetic(QRegExp 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(QRegExp re)
+{
+    static QRegExp separators("\\s");
+    QStringList caps = re.capturedTexts();
+    QString cap = caps.at(1);
+    QStringList numbers = cap.split(separators, QString::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=%d)\n", array.size());
+
+
+    m_painter->drawConvexPolygon(array);
+}