summaryrefslogtreecommitdiffstats
path: root/tests/arthur/common
diff options
context:
space:
mode:
Diffstat (limited to 'tests/arthur/common')
-rw-r--r--tests/arthur/common/baselineprotocol.cpp525
-rw-r--r--tests/arthur/common/baselineprotocol.h193
-rw-r--r--tests/arthur/common/baselineprotocol.pri11
-rw-r--r--tests/arthur/common/common.pri18
-rw-r--r--tests/arthur/common/common.pro20
-rw-r--r--tests/arthur/common/framework.cpp130
-rw-r--r--tests/arthur/common/framework.h76
-rw-r--r--tests/arthur/common/images.qrc34
-rw-r--r--tests/arthur/common/images/alpha.pngbin0 -> 2422 bytes
-rw-r--r--tests/arthur/common/images/alpha2x2.pngbin0 -> 169 bytes
-rw-r--r--tests/arthur/common/images/bitmap.pngbin0 -> 254 bytes
-rw-r--r--tests/arthur/common/images/border.pngbin0 -> 182 bytes
-rw-r--r--tests/arthur/common/images/borderimage.pngbin0 -> 826 bytes
-rw-r--r--tests/arthur/common/images/dome_argb32.pngbin0 -> 18234 bytes
-rw-r--r--tests/arthur/common/images/dome_indexed.pngbin0 -> 7946 bytes
-rw-r--r--tests/arthur/common/images/dome_indexed_mask.pngbin0 -> 5411 bytes
-rw-r--r--tests/arthur/common/images/dome_mono.pngbin0 -> 1391 bytes
-rw-r--r--tests/arthur/common/images/dome_mono_128.pngbin0 -> 2649 bytes
-rw-r--r--tests/arthur/common/images/dome_mono_palette.pngbin0 -> 1404 bytes
-rw-r--r--tests/arthur/common/images/dome_rgb32.pngbin0 -> 17890 bytes
-rw-r--r--tests/arthur/common/images/dot.pngbin0 -> 287 bytes
-rw-r--r--tests/arthur/common/images/face.pngbin0 -> 2414 bytes
-rw-r--r--tests/arthur/common/images/gam030.pngbin0 -> 213 bytes
-rw-r--r--tests/arthur/common/images/gam045.pngbin0 -> 216 bytes
-rw-r--r--tests/arthur/common/images/gam056.pngbin0 -> 216 bytes
-rw-r--r--tests/arthur/common/images/gam100.pngbin0 -> 205 bytes
-rw-r--r--tests/arthur/common/images/gam200.pngbin0 -> 187 bytes
-rw-r--r--tests/arthur/common/images/image.pngbin0 -> 169554 bytes
-rw-r--r--tests/arthur/common/images/mask.pngbin0 -> 274 bytes
-rw-r--r--tests/arthur/common/images/mask_100.pngbin0 -> 319 bytes
-rw-r--r--tests/arthur/common/images/masked.pngbin0 -> 788 bytes
-rw-r--r--tests/arthur/common/images/sign.pngbin0 -> 10647 bytes
-rw-r--r--tests/arthur/common/images/solid.pngbin0 -> 607 bytes
-rw-r--r--tests/arthur/common/images/solid2x2.pngbin0 -> 169 bytes
-rw-r--r--tests/arthur/common/images/struct-image-01.jpgbin0 -> 4751 bytes
-rw-r--r--tests/arthur/common/images/struct-image-01.pngbin0 -> 63238 bytes
-rw-r--r--tests/arthur/common/images/zebra.pngbin0 -> 426 bytes
-rw-r--r--tests/arthur/common/lookup3.cpp786
-rw-r--r--tests/arthur/common/paintcommands.cpp2684
-rw-r--r--tests/arthur/common/paintcommands.h340
-rw-r--r--tests/arthur/common/qbaselinetest.cpp193
-rw-r--r--tests/arthur/common/qbaselinetest.h77
-rw-r--r--tests/arthur/common/qbaselinetest.pri13
-rw-r--r--tests/arthur/common/qengines.cpp733
-rw-r--r--tests/arthur/common/qengines.h241
-rw-r--r--tests/arthur/common/xmldata.cpp110
-rw-r--r--tests/arthur/common/xmldata.h153
47 files changed, 6337 insertions, 0 deletions
diff --git a/tests/arthur/common/baselineprotocol.cpp b/tests/arthur/common/baselineprotocol.cpp
new file mode 100644
index 0000000000..88cea362ee
--- /dev/null
+++ b/tests/arthur/common/baselineprotocol.cpp
@@ -0,0 +1,525 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "baselineprotocol.h"
+#include <QLibraryInfo>
+#include <QImage>
+#include <QBuffer>
+#include <QHostInfo>
+#include <QSysInfo>
+#include <QProcess>
+#include <QFileInfo>
+#include <QDir>
+#include <QTime>
+#include <QPointer>
+
+const QString PI_TestCase(QLS("TestCase"));
+const QString PI_HostName(QLS("HostName"));
+const QString PI_HostAddress(QLS("HostAddress"));
+const QString PI_OSName(QLS("OSName"));
+const QString PI_OSVersion(QLS("OSVersion"));
+const QString PI_QtVersion(QLS("QtVersion"));
+const QString PI_BuildKey(QLS("BuildKey"));
+const QString PI_GitCommit(QLS("GitCommit"));
+const QString PI_QMakeSpec(QLS("QMakeSpec"));
+const QString PI_PulseGitBranch(QLS("PulseGitBranch"));
+const QString PI_PulseTestrBranch(QLS("PulseTestrBranch"));
+
+#ifndef QMAKESPEC
+#define QMAKESPEC "Unknown"
+#endif
+
+#if defined(Q_OS_WIN)
+#include <QtCore/qt_windows.h>
+#endif
+#if defined(Q_OS_UNIX)
+#include <time.h>
+#endif
+void BaselineProtocol::sysSleep(int ms)
+{
+#if defined(Q_OS_WIN)
+ Sleep(DWORD(ms));
+#else
+ struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
+ nanosleep(&ts, NULL);
+#endif
+}
+
+PlatformInfo::PlatformInfo()
+ : QMap<QString, QString>(), replaceDefault(false)
+{
+}
+
+PlatformInfo PlatformInfo::localHostInfo()
+{
+ PlatformInfo pi;
+ pi.insert(PI_HostName, QHostInfo::localHostName());
+ pi.insert(PI_QtVersion, QLS(qVersion()));
+ pi.insert(PI_QMakeSpec, QString(QLS(QMAKESPEC)).remove(QRegExp(QLS("^.*mkspecs/"))));
+ pi.insert(PI_BuildKey, QLibraryInfo::buildKey());
+#if defined(Q_OS_LINUX)
+ pi.insert(PI_OSName, QLS("Linux"));
+ QProcess uname;
+ uname.start(QLS("uname"), QStringList() << QLS("-r"));
+ if (uname.waitForFinished(3000))
+ pi.insert(PI_OSVersion, QString::fromLocal8Bit(uname.readAllStandardOutput().constData()).simplified());
+#elif defined(Q_OS_WINCE)
+ pi.insert(PI_OSName, QLS("WinCE"));
+ pi.insert(PI_OSVersion, QString::number(QSysInfo::windowsVersion()));
+#elif defined(Q_OS_WIN)
+ pi.insert(PI_OSName, QLS("Windows"));
+ pi.insert(PI_OSVersion, QString::number(QSysInfo::windowsVersion()));
+#elif defined(Q_OS_MAC)
+ pi.insert(PI_OSName, QLS("MacOS"));
+ pi.insert(PI_OSVersion, QString::number(qMacVersion()));
+#elif defined(Q_OS_SYMBIAN)
+ pi.insert(PI_OSName, QLS("Symbian"));
+ pi.insert(PI_OSVersion, QString::number(QSysInfo::symbianVersion());
+#else
+ pi.insert(PI_OSName, QLS("Other"));
+#endif
+
+ QProcess git;
+ QString cmd;
+ QStringList args;
+#if defined(Q_OS_WIN)
+ cmd = QLS("cmd.exe");
+ args << QLS("/c") << QLS("git");
+#else
+ cmd = QLS("git");
+#endif
+ args << QLS("log") << QLS("--max-count=1") << QLS("--pretty=%H [%an] [%ad] %s");
+ git.start(cmd, args);
+ git.waitForFinished(3000);
+ if (!git.exitCode())
+ pi.insert(PI_GitCommit, QString::fromLocal8Bit(git.readAllStandardOutput().constData()).simplified());
+ else
+ pi.insert(PI_GitCommit, QLS("Unknown"));
+
+ QByteArray gb = qgetenv("PULSE_GIT_BRANCH");
+ if (!gb.isEmpty())
+ pi.insert(PI_PulseGitBranch, QString::fromLatin1(gb));
+ QByteArray tb = qgetenv("PULSE_TESTR_BRANCH");
+ if (!tb.isEmpty())
+ pi.insert(PI_PulseTestrBranch, QString::fromLatin1(tb));
+
+ return pi;
+}
+
+
+PlatformInfo::PlatformInfo(const PlatformInfo &other)
+ : QMap<QString, QString>(other)
+{
+ sigKeys = other.sigKeys;
+ replaceDefault = other.replaceDefault;
+}
+
+
+PlatformInfo &PlatformInfo::operator=(const PlatformInfo &other)
+{
+ QMap<QString, QString>::operator=(other);
+ sigKeys = other.sigKeys;
+ replaceDefault = other.replaceDefault;
+ return *this;
+}
+
+
+void PlatformInfo::addSignificantKeys(const QStringList &keys, bool replaceDefaultKeys)
+{
+ sigKeys = keys;
+ replaceDefault = replaceDefaultKeys;
+}
+
+
+QStringList PlatformInfo::addedKeys() const
+{
+ return sigKeys;
+}
+
+
+bool PlatformInfo::addedKeysReplaceDefault() const
+{
+ return replaceDefault;
+}
+
+
+QDataStream & operator<< (QDataStream &stream, const PlatformInfo &pi)
+{
+ stream << static_cast<const QMap<QString, QString>&>(pi);
+ stream << pi.sigKeys << pi.replaceDefault;
+ return stream;
+}
+
+
+QDataStream & operator>> (QDataStream &stream, PlatformInfo &pi)
+{
+ stream >> static_cast<QMap<QString, QString>&>(pi);
+ stream >> pi.sigKeys >> pi.replaceDefault;
+ return stream;
+}
+
+
+ImageItem &ImageItem::operator=(const ImageItem &other)
+{
+ testFunction = other.testFunction;
+ itemName = other.itemName;
+ itemChecksum = other.itemChecksum;
+ status = other.status;
+ image = other.image;
+ imageChecksums = other.imageChecksums;
+ return *this;
+}
+
+// Defined in lookup3.c:
+void hashword2 (
+const quint32 *k, /* the key, an array of quint32 values */
+size_t length, /* the length of the key, in quint32s */
+quint32 *pc, /* IN: seed OUT: primary hash value */
+quint32 *pb); /* IN: more seed OUT: secondary hash value */
+
+quint64 ImageItem::computeChecksum(const QImage &image)
+{
+ QImage img(image);
+ const int bpl = img.bytesPerLine();
+ const int padBytes = bpl - (img.width() * img.depth() / 8);
+ if (padBytes) {
+ uchar *p = img.bits() + bpl - padBytes;
+ const int h = img.height();
+ for (int y = 0; y < h; ++y) {
+ qMemSet(p, 0, padBytes);
+ p += bpl;
+ }
+ }
+
+ quint32 h1 = 0xfeedbacc;
+ quint32 h2 = 0x21604894;
+ hashword2((const quint32 *)img.constBits(), img.byteCount()/4, &h1, &h2);
+ return (quint64(h1) << 32) | h2;
+}
+
+#if 0
+QString ImageItem::engineAsString() const
+{
+ switch (engine) {
+ case Raster:
+ return QLS("Raster");
+ break;
+ case OpenGL:
+ return QLS("OpenGL");
+ break;
+ default:
+ break;
+ }
+ return QLS("Unknown");
+}
+
+QString ImageItem::formatAsString() const
+{
+ static const int numFormats = 16;
+ static const char *formatNames[numFormats] = {
+ "Invalid",
+ "Mono",
+ "MonoLSB",
+ "Indexed8",
+ "RGB32",
+ "ARGB32",
+ "ARGB32-Premult",
+ "RGB16",
+ "ARGB8565-Premult",
+ "RGB666",
+ "ARGB6666-Premult",
+ "RGB555",
+ "ARGB8555-Premult",
+ "RGB888",
+ "RGB444",
+ "ARGB4444-Premult"
+ };
+ if (renderFormat < 0 || renderFormat >= numFormats)
+ return QLS("UnknownFormat");
+ return QLS(formatNames[renderFormat]);
+}
+#endif
+
+void ImageItem::writeImageToStream(QDataStream &out) const
+{
+ if (image.isNull() || image.format() == QImage::Format_Invalid) {
+ out << quint8(0);
+ return;
+ }
+ out << quint8('Q') << quint8(image.format());
+ out << quint8(QSysInfo::ByteOrder) << quint8(0); // pad to multiple of 4 bytes
+ out << quint32(image.width()) << quint32(image.height()) << quint32(image.bytesPerLine());
+ out << qCompress((const uchar *)image.constBits(), image.byteCount());
+ //# can be followed by colormap for formats that use it
+}
+
+void ImageItem::readImageFromStream(QDataStream &in)
+{
+ quint8 hdr, fmt, endian, pad;
+ quint32 width, height, bpl;
+ QByteArray data;
+
+ in >> hdr;
+ if (hdr != 'Q') {
+ image = QImage();
+ return;
+ }
+ in >> fmt >> endian >> pad;
+ if (!fmt || fmt >= QImage::NImageFormats) {
+ image = QImage();
+ return;
+ }
+ if (endian != QSysInfo::ByteOrder) {
+ qWarning("ImageItem cannot read streamed image with different endianness");
+ image = QImage();
+ return;
+ }
+ in >> width >> height >> bpl;
+ in >> data;
+ data = qUncompress(data);
+ QImage res((const uchar *)data.constData(), width, height, bpl, QImage::Format(fmt));
+ image = res.copy(); //# yuck, seems there is currently no way to avoid data copy
+}
+
+QDataStream & operator<< (QDataStream &stream, const ImageItem &ii)
+{
+ stream << ii.testFunction << ii.itemName << ii.itemChecksum << quint8(ii.status) << ii.imageChecksums << ii.misc;
+ ii.writeImageToStream(stream);
+ return stream;
+}
+
+QDataStream & operator>> (QDataStream &stream, ImageItem &ii)
+{
+ quint8 encStatus;
+ stream >> ii.testFunction >> ii.itemName >> ii.itemChecksum >> encStatus >> ii.imageChecksums >> ii.misc;
+ ii.status = ImageItem::ItemStatus(encStatus);
+ ii.readImageFromStream(stream);
+ return stream;
+}
+
+BaselineProtocol::BaselineProtocol()
+{
+}
+
+BaselineProtocol::~BaselineProtocol()
+{
+ socket.close();
+ if (socket.state() != QTcpSocket::UnconnectedState)
+ socket.waitForDisconnected(Timeout);
+}
+
+
+bool BaselineProtocol::connect(const QString &testCase, bool *dryrun)
+{
+ errMsg.clear();
+ QByteArray serverName(qgetenv("QT_LANCELOT_SERVER"));
+ if (serverName.isNull())
+ serverName = "lancelot.test.qt.nokia.com";
+
+ socket.connectToHost(serverName, ServerPort);
+ if (!socket.waitForConnected(Timeout)) {
+ sysSleep(Timeout); // Wait a bit and try again, the server might just be restarting
+ if (!socket.waitForConnected(Timeout)) {
+ errMsg += QLS("TCP connectToHost failed. Host:") + serverName + QLS(" port:") + QString::number(ServerPort);
+ return false;
+ }
+ }
+
+ PlatformInfo pi = PlatformInfo::localHostInfo();
+ pi.insert(PI_TestCase, testCase);
+ QByteArray block;
+ QDataStream ds(&block, QIODevice::ReadWrite);
+ ds << pi;
+ if (!sendBlock(AcceptPlatformInfo, block)) {
+ errMsg += QLS("Failed to send data to server.");
+ return false;
+ }
+
+ Command cmd = UnknownError;
+ if (!receiveBlock(&cmd, &block)) {
+ errMsg += QLS("Failed to get response from server.");
+ return false;
+ }
+
+ if (cmd == Abort) {
+ errMsg += QLS("Server rejected connection. Reason: ") + QString::fromLatin1(block);
+ return false;
+ }
+
+ if (dryrun)
+ *dryrun = (cmd == DoDryRun);
+
+ if (cmd != Ack && cmd != DoDryRun) {
+ errMsg += QLS("Unexpected response from server.");
+ return false;
+ }
+
+ return true;
+}
+
+
+bool BaselineProtocol::acceptConnection(PlatformInfo *pi)
+{
+ errMsg.clear();
+
+ QByteArray block;
+ Command cmd = AcceptPlatformInfo;
+ if (!receiveBlock(&cmd, &block) || cmd != AcceptPlatformInfo)
+ return false;
+
+ if (pi) {
+ QDataStream ds(block);
+ ds >> *pi;
+ pi->insert(PI_HostAddress, socket.peerAddress().toString());
+ }
+
+ return true;
+}
+
+
+bool BaselineProtocol::requestBaselineChecksums(const QString &testFunction, ImageItemList *itemList)
+{
+ errMsg.clear();
+ if (!itemList)
+ return false;
+
+ for(ImageItemList::iterator it = itemList->begin(); it != itemList->end(); it++)
+ it->testFunction = testFunction;
+
+ QByteArray block;
+ QDataStream ds(&block, QIODevice::ReadWrite);
+ ds << *itemList;
+ if (!sendBlock(RequestBaselineChecksums, block))
+ return false;
+ Command cmd;
+ if (!receiveBlock(&cmd, &block))
+ return false;
+ ds.device()->seek(0);
+ ds >> *itemList;
+ return true;
+}
+
+
+bool BaselineProtocol::submitNewBaseline(const ImageItem &item, QByteArray *serverMsg)
+{
+ Command cmd;
+ return (sendItem(AcceptNewBaseline, item) && receiveBlock(&cmd, serverMsg) && cmd == Ack);
+}
+
+
+bool BaselineProtocol::submitMismatch(const ImageItem &item, QByteArray *serverMsg)
+{
+ Command cmd;
+ return (sendItem(AcceptMismatch, item) && receiveBlock(&cmd, serverMsg) && cmd == Ack);
+}
+
+
+bool BaselineProtocol::sendItem(Command cmd, const ImageItem &item)
+{
+ errMsg.clear();
+ QBuffer buf;
+ buf.open(QIODevice::WriteOnly);
+ QDataStream ds(&buf);
+ ds << item;
+ if (!sendBlock(cmd, buf.data())) {
+ errMsg.prepend(QLS("Failed to submit image to server. "));
+ return false;
+ }
+ return true;
+}
+
+
+bool BaselineProtocol::sendBlock(Command cmd, const QByteArray &block)
+{
+ QDataStream s(&socket);
+ // TBD: set qds version as a constant
+ s << quint16(ProtocolVersion) << quint16(cmd);
+ s.writeBytes(block.constData(), block.size());
+ return true;
+}
+
+
+bool BaselineProtocol::receiveBlock(Command *cmd, QByteArray *block)
+{
+ while (socket.bytesAvailable() < int(2*sizeof(quint16) + sizeof(quint32))) {
+ if (!socket.waitForReadyRead(Timeout))
+ return false;
+ }
+ QDataStream ds(&socket);
+ quint16 rcvProtocolVersion, rcvCmd;
+ ds >> rcvProtocolVersion >> rcvCmd;
+ if (rcvProtocolVersion != ProtocolVersion) {
+ errMsg = QLS("Baseline protocol version mismatch, received:") + QString::number(rcvProtocolVersion)
+ + QLS(" expected:") + QString::number(ProtocolVersion);
+ return false;
+ }
+ if (cmd)
+ *cmd = Command(rcvCmd);
+
+ QByteArray uMsg;
+ quint32 remaining;
+ ds >> remaining;
+ uMsg.resize(remaining);
+ int got = 0;
+ char* uMsgBuf = uMsg.data();
+ do {
+ got = ds.readRawData(uMsgBuf, remaining);
+ remaining -= got;
+ uMsgBuf += got;
+ } while (remaining && got >= 0 && socket.waitForReadyRead(Timeout));
+
+ if (got < 0)
+ return false;
+
+ if (block)
+ *block = uMsg;
+
+ return true;
+}
+
+
+QString BaselineProtocol::errorMessage()
+{
+ QString ret = errMsg;
+ if (socket.error() >= 0)
+ ret += QLS(" Socket state: ") + socket.errorString();
+ return ret;
+}
+
diff --git a/tests/arthur/common/baselineprotocol.h b/tests/arthur/common/baselineprotocol.h
new file mode 100644
index 0000000000..8a99ace6ee
--- /dev/null
+++ b/tests/arthur/common/baselineprotocol.h
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef BASELINEPROTOCOL_H
+#define BASELINEPROTOCOL_H
+
+#include <QDataStream>
+#include <QTcpSocket>
+#include <QImage>
+#include <QVector>
+#include <QMap>
+#include <QPointer>
+#include <QStringList>
+
+#define QLS QLatin1String
+#define QLC QLatin1Char
+
+#define FileFormat "png"
+
+extern const QString PI_TestCase;
+extern const QString PI_HostName;
+extern const QString PI_HostAddress;
+extern const QString PI_OSName;
+extern const QString PI_OSVersion;
+extern const QString PI_QtVersion;
+extern const QString PI_BuildKey;
+extern const QString PI_GitCommit;
+extern const QString PI_QMakeSpec;
+extern const QString PI_PulseGitBranch;
+extern const QString PI_PulseTestrBranch;
+
+class PlatformInfo : public QMap<QString, QString>
+{
+public:
+ PlatformInfo();
+ PlatformInfo(const PlatformInfo &other);
+ ~PlatformInfo()
+ {}
+ PlatformInfo &operator=(const PlatformInfo &other);
+
+ static PlatformInfo localHostInfo();
+
+ void addSignificantKeys(const QStringList& keys, bool replaceDefaultKeys=false);
+ QStringList addedKeys() const;
+ bool addedKeysReplaceDefault() const;
+
+private:
+ QStringList sigKeys;
+ bool replaceDefault;
+ friend QDataStream & operator<< (QDataStream &stream, const PlatformInfo &pi);
+ friend QDataStream & operator>> (QDataStream &stream, PlatformInfo& pi);
+};
+QDataStream & operator<< (QDataStream &stream, const PlatformInfo &pi);
+QDataStream & operator>> (QDataStream &stream, PlatformInfo& pi);
+
+
+struct ImageItem
+{
+public:
+ ImageItem()
+ : status(Ok), itemChecksum(0)
+ {}
+ ImageItem(const ImageItem &other)
+ { *this = other; }
+ ~ImageItem()
+ {}
+ ImageItem &operator=(const ImageItem &other);
+
+ static quint64 computeChecksum(const QImage& image);
+
+ enum ItemStatus {
+ Ok = 0,
+ BaselineNotFound = 1,
+ IgnoreItem = 2,
+ Mismatch = 3
+ };
+
+ QString testFunction;
+ QString itemName;
+ ItemStatus status;
+ QImage image;
+ QList<quint64> imageChecksums;
+ quint16 itemChecksum;
+ QByteArray misc;
+
+ void writeImageToStream(QDataStream &stream) const;
+ void readImageFromStream(QDataStream &stream);
+};
+QDataStream & operator<< (QDataStream &stream, const ImageItem &ii);
+QDataStream & operator>> (QDataStream &stream, ImageItem& ii);
+
+Q_DECLARE_METATYPE(ImageItem);
+
+typedef QVector<ImageItem> ImageItemList;
+
+
+class BaselineProtocol
+{
+public:
+ BaselineProtocol();
+ ~BaselineProtocol();
+
+ static BaselineProtocol *instance(QObject *parent = 0);
+
+ // ****************************************************
+ // Important constants here
+ // ****************************************************
+ enum Constant {
+ ProtocolVersion = 5,
+ ServerPort = 54129,
+ Timeout = 5000
+ };
+
+ enum Command {
+ UnknownError = 0,
+ // Queries
+ AcceptPlatformInfo = 1,
+ RequestBaselineChecksums = 2,
+ AcceptNewBaseline = 4,
+ AcceptMismatch = 5,
+ // Responses
+ Ack = 128,
+ Abort = 129,
+ DoDryRun = 130
+ };
+
+ // For client:
+
+ // For advanced client:
+ bool connect(const QString &testCase, bool *dryrun = 0);
+ bool requestBaselineChecksums(const QString &testFunction, ImageItemList *itemList);
+ bool submitNewBaseline(const ImageItem &item, QByteArray *serverMsg);
+ bool submitMismatch(const ImageItem &item, QByteArray *serverMsg);
+
+ // For server:
+ bool acceptConnection(PlatformInfo *pi);
+
+ QString errorMessage();
+
+private:
+ bool sendItem(Command cmd, const ImageItem &item);
+
+ bool sendBlock(Command cmd, const QByteArray &block);
+ bool receiveBlock(Command *cmd, QByteArray *block);
+ void sysSleep(int ms);
+
+ QString errMsg;
+ QTcpSocket socket;
+
+ friend class BaselineThread;
+ friend class BaselineHandler;
+};
+
+
+#endif // BASELINEPROTOCOL_H
diff --git a/tests/arthur/common/baselineprotocol.pri b/tests/arthur/common/baselineprotocol.pri
new file mode 100644
index 0000000000..62e38a6ab5
--- /dev/null
+++ b/tests/arthur/common/baselineprotocol.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+
+QT *= network
+
+SOURCES += \
+ $$PWD/baselineprotocol.cpp \
+ $$PWD/lookup3.cpp
+
+HEADERS += \
+ $$PWD/baselineprotocol.h
diff --git a/tests/arthur/common/common.pri b/tests/arthur/common/common.pri
new file mode 100644
index 0000000000..1f84904474
--- /dev/null
+++ b/tests/arthur/common/common.pri
@@ -0,0 +1,18 @@
+VPATH+=$$PWD
+INCLUDEPATH += $$PWD
+
+contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2):DEFINES += BUILD_OPENGL
+
+SOURCES += \
+ xmldata.cpp \
+ paintcommands.cpp \
+ qengines.cpp \
+ framework.cpp
+
+HEADERS += \
+ xmldata.h \
+ paintcommands.h \
+ qengines.h \
+ framework.h
+
+RESOURCES += images.qrc
diff --git a/tests/arthur/common/common.pro b/tests/arthur/common/common.pro
new file mode 100644
index 0000000000..9510f87f06
--- /dev/null
+++ b/tests/arthur/common/common.pro
@@ -0,0 +1,20 @@
+# -*- Mode: makefile -*-
+#
+# not used as a library all binaries include common.pri anyway
+#
+#COMMON_FOLDER = ../common
+#include(../arthurtester.pri)
+#TEMPLATE = lib
+#CONFIG += static
+#QT += xml opengl svg qt3support
+
+#build_all:!build_pass {
+# CONFIG -= build_all
+# CONFIG += release
+#}
+
+#TARGET = testcommon
+
+#include(common.pri)
+
+
diff --git a/tests/arthur/common/framework.cpp b/tests/arthur/common/framework.cpp
new file mode 100644
index 0000000000..1271e59cde
--- /dev/null
+++ b/tests/arthur/common/framework.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "framework.h"
+
+#include <QFile>
+#include <QFileInfo>
+#include <QSettings>
+#include <QStringList>
+#include <QtDebug>
+
+Framework::Framework()
+ : qsettings(0)
+{
+}
+
+Framework::Framework(const QString &file)
+ : qsettings(0)
+{
+ load(file);
+}
+
+Framework::~Framework()
+{
+ delete qsettings;
+ qsettings = 0;
+}
+
+QString Framework::basePath() const
+{
+ if (!qsettings)
+ return QString();
+
+ QFileInfo fi(qsettings->fileName());
+ return fi.absolutePath();
+}
+
+
+QStringList Framework::suites() const
+{
+ if (!qsettings)
+ return QStringList();
+
+ QStringList tests = qsettings->childGroups();
+ qDebug()<<"here suites "<<tests;
+ tests.removeAll("General");
+ tests.removeAll("Blacklist");
+ return tests;
+}
+
+
+bool Framework::isTestBlacklisted(const QString &engineName,
+ const QString &testcase) const
+{
+ return m_blacklist[engineName].contains(testcase);
+}
+
+bool Framework::isValid() const
+{
+ return qsettings;
+}
+
+void Framework::load(const QString &file)
+{
+ if (qsettings) {
+ delete qsettings;
+ qsettings = 0;
+ }
+ if (QFile::exists(file)) {
+ qsettings = new QSettings(file, QSettings::IniFormat);
+ qsettings->beginGroup(QString("Blacklist"));
+ QStringList engines = qsettings->childKeys();
+ foreach(QString engineName, engines) {
+ QStringList testcases = qsettings->value(engineName).toStringList();
+ m_blacklist.insert(engineName, testcases);
+ qDebug()<<"Blacklists for "<<testcases;
+ }
+ qsettings->endGroup();
+ }
+}
+
+QString Framework::outputDir() const
+{
+ qsettings->beginGroup("General");
+ QString outputDirName = qsettings->value("outputDir").toString();
+ qsettings->endGroup();
+ return outputDirName;
+}
+
+QSettings * Framework::settings() const
+{
+ return qsettings;
+}
diff --git a/tests/arthur/common/framework.h b/tests/arthur/common/framework.h
new file mode 100644
index 0000000000..e25c9a1a37
--- /dev/null
+++ b/tests/arthur/common/framework.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+#ifndef FRAMEWORK_H
+#define FRAMEWORK_H
+
+#include <QMap>
+#include <QStringList>
+#include <QString>
+
+QT_FORWARD_DECLARE_CLASS(QSettings)
+
+class Framework
+{
+public:
+ Framework();
+ Framework(const QString &file);
+ ~Framework();
+
+ bool isValid() const;
+
+ void load(const QString &file);
+
+ QSettings *settings() const;
+
+
+ QString basePath() const;
+ QString outputDir() const;
+
+ QStringList suites() const;
+
+ bool isTestBlacklisted(const QString &engineName,
+ const QString &testcase) const;
+private:
+ QSettings *qsettings;
+ QMap<QString, QStringList> m_blacklist;
+};
+
+#endif
diff --git a/tests/arthur/common/images.qrc b/tests/arthur/common/images.qrc
new file mode 100644
index 0000000000..060b52c85a
--- /dev/null
+++ b/tests/arthur/common/images.qrc
@@ -0,0 +1,34 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+<qresource>
+ <file>images/alpha.png</file>
+ <file>images/border.png</file>
+ <file>images/borderimage.png</file>
+ <file>images/dome_argb32.png</file>
+ <file>images/dome_indexed.png</file>
+ <file>images/dome_mono_palette.png</file>
+ <file>images/dome_rgb32.png</file>
+ <file>images/face.png</file>
+ <file>images/gam045.png</file>
+ <file>images/gam100.png</file>
+ <file>images/image.png</file>
+ <file>images/masked.png</file>
+ <file>images/sign.png</file>
+ <file>images/struct-image-01.jpg</file>
+ <file>images/bitmap.png</file>
+ <file>images/dome_indexed_mask.png</file>
+ <file>images/dome_mono_128.png</file>
+ <file>images/dome_mono.png</file>
+ <file>images/dot.png</file>
+ <file>images/gam030.png</file>
+ <file>images/gam056.png</file>
+ <file>images/gam200.png</file>
+ <file>images/mask_100.png</file>
+ <file>images/mask.png</file>
+ <file>images/solid.png</file>
+ <file>images/struct-image-01.png</file>
+ <file>images/zebra.png</file>
+ <file>images/alpha2x2.png</file>
+ <file>images/solid2x2.png</file>
+</qresource>
+</RCC>
diff --git a/tests/arthur/common/images/alpha.png b/tests/arthur/common/images/alpha.png
new file mode 100644
index 0000000000..e465b2586d
--- /dev/null
+++ b/tests/arthur/common/images/alpha.png
Binary files differ
diff --git a/tests/arthur/common/images/alpha2x2.png b/tests/arthur/common/images/alpha2x2.png
new file mode 100644
index 0000000000..67ecc04286
--- /dev/null
+++ b/tests/arthur/common/images/alpha2x2.png
Binary files differ
diff --git a/tests/arthur/common/images/bitmap.png b/tests/arthur/common/images/bitmap.png
new file mode 100644
index 0000000000..d21f8f51bb
--- /dev/null
+++ b/tests/arthur/common/images/bitmap.png
Binary files differ
diff --git a/tests/arthur/common/images/border.png b/tests/arthur/common/images/border.png
new file mode 100644
index 0000000000..a3d2fed0a3
--- /dev/null
+++ b/tests/arthur/common/images/border.png
Binary files differ
diff --git a/tests/arthur/common/images/borderimage.png b/tests/arthur/common/images/borderimage.png
new file mode 100644
index 0000000000..f7f6b66227
--- /dev/null
+++ b/tests/arthur/common/images/borderimage.png
Binary files differ
diff --git a/tests/arthur/common/images/dome_argb32.png b/tests/arthur/common/images/dome_argb32.png
new file mode 100644
index 0000000000..e3ccba0c13
--- /dev/null
+++ b/tests/arthur/common/images/dome_argb32.png
Binary files differ
diff --git a/tests/arthur/common/images/dome_indexed.png b/tests/arthur/common/images/dome_indexed.png
new file mode 100644
index 0000000000..beefcd514e
--- /dev/null
+++ b/tests/arthur/common/images/dome_indexed.png
Binary files differ
diff --git a/tests/arthur/common/images/dome_indexed_mask.png b/tests/arthur/common/images/dome_indexed_mask.png
new file mode 100644
index 0000000000..a62f29f40e
--- /dev/null
+++ b/tests/arthur/common/images/dome_indexed_mask.png
Binary files differ
diff --git a/tests/arthur/common/images/dome_mono.png b/tests/arthur/common/images/dome_mono.png
new file mode 100644
index 0000000000..950c2a7494
--- /dev/null
+++ b/tests/arthur/common/images/dome_mono.png
Binary files differ
diff --git a/tests/arthur/common/images/dome_mono_128.png b/tests/arthur/common/images/dome_mono_128.png
new file mode 100644
index 0000000000..77e48aaab7
--- /dev/null
+++ b/tests/arthur/common/images/dome_mono_128.png
Binary files differ
diff --git a/tests/arthur/common/images/dome_mono_palette.png b/tests/arthur/common/images/dome_mono_palette.png
new file mode 100644
index 0000000000..dca3f59245
--- /dev/null
+++ b/tests/arthur/common/images/dome_mono_palette.png
Binary files differ
diff --git a/tests/arthur/common/images/dome_rgb32.png b/tests/arthur/common/images/dome_rgb32.png
new file mode 100644
index 0000000000..27bc02a545
--- /dev/null
+++ b/tests/arthur/common/images/dome_rgb32.png
Binary files differ
diff --git a/tests/arthur/common/images/dot.png b/tests/arthur/common/images/dot.png
new file mode 100644
index 0000000000..17a7b6a0ba
--- /dev/null
+++ b/tests/arthur/common/images/dot.png
Binary files differ
diff --git a/tests/arthur/common/images/face.png b/tests/arthur/common/images/face.png
new file mode 100644
index 0000000000..4f6172d83b
--- /dev/null
+++ b/tests/arthur/common/images/face.png
Binary files differ
diff --git a/tests/arthur/common/images/gam030.png b/tests/arthur/common/images/gam030.png
new file mode 100644
index 0000000000..904c9721bd
--- /dev/null
+++ b/tests/arthur/common/images/gam030.png
Binary files differ
diff --git a/tests/arthur/common/images/gam045.png b/tests/arthur/common/images/gam045.png
new file mode 100644
index 0000000000..b649a8a54f
--- /dev/null
+++ b/tests/arthur/common/images/gam045.png
Binary files differ
diff --git a/tests/arthur/common/images/gam056.png b/tests/arthur/common/images/gam056.png
new file mode 100644
index 0000000000..e5f959dc96
--- /dev/null
+++ b/tests/arthur/common/images/gam056.png
Binary files differ
diff --git a/tests/arthur/common/images/gam100.png b/tests/arthur/common/images/gam100.png
new file mode 100644
index 0000000000..6c7ba5f1ed
--- /dev/null
+++ b/tests/arthur/common/images/gam100.png
Binary files differ
diff --git a/tests/arthur/common/images/gam200.png b/tests/arthur/common/images/gam200.png
new file mode 100644
index 0000000000..daa20fcbc4
--- /dev/null
+++ b/tests/arthur/common/images/gam200.png
Binary files differ
diff --git a/tests/arthur/common/images/image.png b/tests/arthur/common/images/image.png
new file mode 100644
index 0000000000..85d486a790
--- /dev/null
+++ b/tests/arthur/common/images/image.png
Binary files differ
diff --git a/tests/arthur/common/images/mask.png b/tests/arthur/common/images/mask.png
new file mode 100644
index 0000000000..c3f3b1b6ca
--- /dev/null
+++ b/tests/arthur/common/images/mask.png
Binary files differ
diff --git a/tests/arthur/common/images/mask_100.png b/tests/arthur/common/images/mask_100.png
new file mode 100644
index 0000000000..fc950dc7ed
--- /dev/null
+++ b/tests/arthur/common/images/mask_100.png
Binary files differ
diff --git a/tests/arthur/common/images/masked.png b/tests/arthur/common/images/masked.png
new file mode 100644
index 0000000000..6debec534d
--- /dev/null
+++ b/tests/arthur/common/images/masked.png
Binary files differ
diff --git a/tests/arthur/common/images/sign.png b/tests/arthur/common/images/sign.png
new file mode 100644
index 0000000000..6aac7e150a
--- /dev/null
+++ b/tests/arthur/common/images/sign.png
Binary files differ
diff --git a/tests/arthur/common/images/solid.png b/tests/arthur/common/images/solid.png
new file mode 100644
index 0000000000..371e9c1aee
--- /dev/null
+++ b/tests/arthur/common/images/solid.png
Binary files differ
diff --git a/tests/arthur/common/images/solid2x2.png b/tests/arthur/common/images/solid2x2.png
new file mode 100644
index 0000000000..ad67cd3e12
--- /dev/null
+++ b/tests/arthur/common/images/solid2x2.png
Binary files differ
diff --git a/tests/arthur/common/images/struct-image-01.jpg b/tests/arthur/common/images/struct-image-01.jpg
new file mode 100644
index 0000000000..a74e07223b
--- /dev/null
+++ b/tests/arthur/common/images/struct-image-01.jpg
Binary files differ
diff --git a/tests/arthur/common/images/struct-image-01.png b/tests/arthur/common/images/struct-image-01.png
new file mode 100644
index 0000000000..4ed08406dc
--- /dev/null
+++ b/tests/arthur/common/images/struct-image-01.png
Binary files differ
diff --git a/tests/arthur/common/images/zebra.png b/tests/arthur/common/images/zebra.png
new file mode 100644
index 0000000000..ef35f20785
--- /dev/null
+++ b/tests/arthur/common/images/zebra.png
Binary files differ
diff --git a/tests/arthur/common/lookup3.cpp b/tests/arthur/common/lookup3.cpp
new file mode 100644
index 0000000000..1aa501fa4f
--- /dev/null
+++ b/tests/arthur/common/lookup3.cpp
@@ -0,0 +1,786 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+
+/*
+These functions are based on:
+
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions. Routines to test the hash are included
+if SELF_TEST is defined. You can use this free for any purpose. It's in
+the public domain. It has no warranty.
+
+You probably want to use hashlittle(). hashlittle() and hashbig()
+hash byte arrays. hashlittle() is is faster than hashbig() on
+little-endian machines. Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+ a = i1; b = i2; c = i3;
+ mix(a,b,c);
+ a += i4; b += i5; c += i6;
+ mix(a,b,c);
+ a += i7;
+ final(a,b,c);
+then use c as the hash value. If you have a variable length array of
+4-byte integers to hash, use hashword(). If you have a byte array (like
+a character string), use hashlittle(). If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers. This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+
+#include <QtGlobal>
+
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((quint32)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta. I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche. There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a. The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism. Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism. I did what I could. Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different. This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+/*
+--------------------------------------------------------------------
+ This works on all machines. To be useful, it requires
+ -- that the key be an array of quint32's, and
+ -- that the length be the number of quint32's in the key
+
+ The function hashword() is identical to hashlittle() on little-endian
+ machines, and identical to hashbig() on big-endian machines,
+ except that the length has to be measured in quint32s rather than in
+ bytes. hashlittle() is more complicated than hashword() only because
+ hashlittle() has to dance around fitting the key bytes into registers.
+--------------------------------------------------------------------
+*/
+quint32 hashword(
+const quint32 *k, /* the key, an array of quint32 values */
+size_t length, /* the length of the key, in quint32s */
+quint32 initval) /* the previous hash, or an arbitrary value */
+{
+ quint32 a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + (((quint32)length)<<2) + initval;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 quint32's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ return c;
+}
+
+
+/*
+--------------------------------------------------------------------
+hashword2() -- same as hashword(), but take two seeds and return two
+32-bit values. pc and pb must both be nonnull, and *pc and *pb must
+both be initialized with seeds. If you pass in (*pb)==0, the output
+(*pc) will be the same as the return value from hashword().
+--------------------------------------------------------------------
+*/
+void hashword2 (
+const quint32 *k, /* the key, an array of quint32 values */
+size_t length, /* the length of the key, in quint32s */
+quint32 *pc, /* IN: seed OUT: primary hash value */
+quint32 *pb) /* IN: more seed OUT: secondary hash value */
+{
+ quint32 a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((quint32)(length<<2)) + *pc;
+ c += *pb;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 quint32's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ *pc=c; *pb=b;
+}
+
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (quint8 **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+quint32 hashlittle( const void *key, size_t length, quint32 initval)
+{
+ quint32 a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((quint32)length) + initval;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const quint32 *k = (const quint32 *)key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ const quint8 *k8 = (const quint8 *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((quint32)k8[10])<<16; /* fall through */
+ case 10: c+=((quint32)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((quint32)k8[6])<<16; /* fall through */
+ case 6 : b+=((quint32)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((quint32)k8[2])<<16; /* fall through */
+ case 2 : a+=((quint32)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const quint16 *k = (const quint16 *)key; /* read 16-bit chunks */
+ const quint8 *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((quint32)k[1])<<16);
+ b += k[2] + (((quint32)k[3])<<16);
+ c += k[4] + (((quint32)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const quint8 *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((quint32)k[5])<<16);
+ b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 11: c+=((quint32)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 7 : b+=((quint32)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 3 : a+=((quint32)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const quint8 *k = (const quint8 *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((quint32)k[1])<<8;
+ a += ((quint32)k[2])<<16;
+ a += ((quint32)k[3])<<24;
+ b += k[4];
+ b += ((quint32)k[5])<<8;
+ b += ((quint32)k[6])<<16;
+ b += ((quint32)k[7])<<24;
+ c += k[8];
+ c += ((quint32)k[9])<<8;
+ c += ((quint32)k[10])<<16;
+ c += ((quint32)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((quint32)k[11])<<24;
+ case 11: c+=((quint32)k[10])<<16;
+ case 10: c+=((quint32)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((quint32)k[7])<<24;
+ case 7 : b+=((quint32)k[6])<<16;
+ case 6 : b+=((quint32)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((quint32)k[3])<<24;
+ case 3 : a+=((quint32)k[2])<<16;
+ case 2 : a+=((quint32)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+
+/*
+ * hashlittle2: return 2 32-bit hash values
+ *
+ * This is identical to hashlittle(), except it returns two 32-bit hash
+ * values instead of just one. This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key. *pc is better mixed than *pb, so use *pc first. If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ */
+void hashlittle2(
+ const void *key, /* the key to hash */
+ size_t length, /* length of the key */
+ quint32 *pc, /* IN: primary initval, OUT: primary hash */
+ quint32 *pb) /* IN: secondary initval, OUT: secondary hash */
+{
+ quint32 a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((quint32)length) + *pc;
+ c += *pb;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const quint32 *k = (const quint32 *)key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ const quint8 *k8 = (const quint8 *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((quint32)k8[10])<<16; /* fall through */
+ case 10: c+=((quint32)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((quint32)k8[6])<<16; /* fall through */
+ case 6 : b+=((quint32)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((quint32)k8[2])<<16; /* fall through */
+ case 2 : a+=((quint32)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const quint16 *k = (const quint16 *)key; /* read 16-bit chunks */
+ const quint8 *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((quint32)k[1])<<16);
+ b += k[2] + (((quint32)k[3])<<16);
+ c += k[4] + (((quint32)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const quint8 *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((quint32)k[5])<<16);
+ b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 11: c+=((quint32)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((quint32)k[3])<<16);
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 7 : b+=((quint32)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((quint32)k[1])<<16);
+ break;
+ case 3 : a+=((quint32)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const quint8 *k = (const quint8 *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((quint32)k[1])<<8;
+ a += ((quint32)k[2])<<16;
+ a += ((quint32)k[3])<<24;
+ b += k[4];
+ b += ((quint32)k[5])<<8;
+ b += ((quint32)k[6])<<16;
+ b += ((quint32)k[7])<<24;
+ c += k[8];
+ c += ((quint32)k[9])<<8;
+ c += ((quint32)k[10])<<16;
+ c += ((quint32)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((quint32)k[11])<<24;
+ case 11: c+=((quint32)k[10])<<16;
+ case 10: c+=((quint32)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((quint32)k[7])<<24;
+ case 7 : b+=((quint32)k[6])<<16;
+ case 6 : b+=((quint32)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((quint32)k[3])<<24;
+ case 3 : a+=((quint32)k[2])<<16;
+ case 2 : a+=((quint32)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+ }
+
+ final(a,b,c);
+ *pc=c; *pb=b;
+}
+
+
+
+/*
+ * hashbig():
+ * This is the same as hashword() on big-endian machines. It is different
+ * from hashlittle() on all machines. hashbig() takes advantage of
+ * big-endian byte ordering.
+ */
+quint32 hashbig( const void *key, size_t length, quint32 initval)
+{
+ quint32 a,b,c;
+ union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((quint32)length) + initval;
+
+ u.ptr = key;
+ if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+ const quint32 *k = (const quint32 *)key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]<<8" actually reads beyond the end of the string, but
+ * then shifts out the part it's not allowed to read. Because the
+ * string is aligned, the illegal read is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff00; break;
+ case 2 : a+=k[0]&0xffff0000; break;
+ case 1 : a+=k[0]&0xff000000; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ const quint8 *k8 = (const quint8 *)k;
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((quint32)k8[10])<<8; /* fall through */
+ case 10: c+=((quint32)k8[9])<<16; /* fall through */
+ case 9 : c+=((quint32)k8[8])<<24; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((quint32)k8[6])<<8; /* fall through */
+ case 6 : b+=((quint32)k8[5])<<16; /* fall through */
+ case 5 : b+=((quint32)k8[4])<<24; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((quint32)k8[2])<<8; /* fall through */
+ case 2 : a+=((quint32)k8[1])<<16; /* fall through */
+ case 1 : a+=((quint32)k8[0])<<24; break;
+ case 0 : return c;
+ }
+
+#endif /* !VALGRIND */
+
+ } else { /* need to read the key one byte at a time */
+ const quint8 *k = (const quint8 *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += ((quint32)k[0])<<24;
+ a += ((quint32)k[1])<<16;
+ a += ((quint32)k[2])<<8;
+ a += ((quint32)k[3]);
+ b += ((quint32)k[4])<<24;
+ b += ((quint32)k[5])<<16;
+ b += ((quint32)k[6])<<8;
+ b += ((quint32)k[7]);
+ c += ((quint32)k[8])<<24;
+ c += ((quint32)k[9])<<16;
+ c += ((quint32)k[10])<<8;
+ c += ((quint32)k[11]);
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[11];
+ case 11: c+=((quint32)k[10])<<8;
+ case 10: c+=((quint32)k[9])<<16;
+ case 9 : c+=((quint32)k[8])<<24;
+ case 8 : b+=k[7];
+ case 7 : b+=((quint32)k[6])<<8;
+ case 6 : b+=((quint32)k[5])<<16;
+ case 5 : b+=((quint32)k[4])<<24;
+ case 4 : a+=k[3];
+ case 3 : a+=((quint32)k[2])<<8;
+ case 2 : a+=((quint32)k[1])<<16;
+ case 1 : a+=((quint32)k[0])<<24;
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
diff --git a/tests/arthur/common/paintcommands.cpp b/tests/arthur/common/paintcommands.cpp
new file mode 100644
index 0000000000..7a018e3ce6
--- /dev/null
+++ b/tests/arthur/common/paintcommands.cpp
@@ -0,0 +1,2684 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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::fontHintingTable[] = {
+ "Default",
+ "None",
+ "Vertical",
+ "Full"
+};
+
+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)
+{
+ QByteArray p = pattern.toLatin1().toLower();
+ for (int i=0; i<limit; ++i)
+ if (p == QByteArray::fromRawData(table[i], qstrlen(table[i])).toLower())
+ return i;
+ return -1;
+}
+
+QList<PaintCommands::PaintCommandInfos> PaintCommands::s_commandInfoTable = QList<PaintCommands::PaintCommandInfos>();
+QList<QPair<QString,QStringList> > PaintCommands::s_enumsTable = QList<QPair<QString,QStringList> >();
+QMultiHash<QString, int> PaintCommands::s_commandHash;
+
+#define DECL_PAINTCOMMAND(identifier, method, regexp, syntax, sample) \
+ s_commandInfoTable << PaintCommandInfos(QLatin1String(identifier), &PaintCommands::method, 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*)\\s*(\\w*)$",
+ "setFont <fontFace> [size] [font weight|font weight enum] [italic] [hinting enum]\n - font weight is an integer between 0 and 99",
+ "setFont \"times\" 12");
+ DECL_PAINTCOMMAND("setPen", command_setPen,
+ "^setPen\\s+#?(\\w*)$",
+ "setPen <color>\nsetPen <pen style enum>\nsetPen brush",
+ "setPen black");
+ DECL_PAINTCOMMAND("setPen", command_setPen2,
+ "^setPen\\s+(#?\\w*)\\s+([\\w.]+)\\s*(\\w*)\\s*(\\w*)\\s*(\\w*)$",
+ "setPen brush|<color> [width] [pen style enum] [FlatCap|SquareCap|RoundCap] [MiterJoin|BevelJoin|RoundJoin]",
+ "setPen black 1 FlatCap MiterJoin");
+ DECL_PAINTCOMMAND("pen_setDashOffset", command_pen_setDashOffset,
+ "^pen_setDashOffset\\s+(-?[\\w.]+)$",
+ "pen_setDashOffset <offset>\n",
+ "pen_setDashOffset 1.0");
+ DECL_PAINTCOMMAND("pen_setDashPattern", command_pen_setDashPattern,
+ "^pen_setDashPattern\\s+\\[([\\w\\s.]*)\\]$",
+ "pen_setDashPattern <[ <dash_1> <space_1> ... <dash_n> <space_n> ]>",
+ "pen_setDashPattern [ 2 1 4 1 3 3 ]");
+ DECL_PAINTCOMMAND("pen_setCosmetic", command_pen_setCosmetic,
+ "^pen_setCosmetic\\s+(\\w*)$",
+ "pen_setCosmetic <true|false>",
+ "pen_setCosmetic true");
+ DECL_PAINTCOMMAND("setRenderHint", command_setRenderHint,
+ "^setRenderHint\\s+([\\w_0-9]*)\\s*(\\w*)$",
+ "setRenderHint <Antialiasing|SmoothPixmapTransform> <true|false>",
+ "setRenderHint Antialiasing true");
+ DECL_PAINTCOMMAND("clearRenderHint", command_clearRenderHint,
+ "^clearRenderHint$",
+ "clearRenderHint",
+ "clearRenderHint");
+
+ DECL_PAINTCOMMANDSECTION("gradients");
+ DECL_PAINTCOMMAND("gradient_appendStop", command_gradient_appendStop,
+ "^gradient_appendStop\\s+([\\w.]*)\\s+#?(\\w*)$",
+ "gradient_appendStop <pos> <color>",
+ "gradient_appendStop 1.0 red");
+ DECL_PAINTCOMMAND("gradient_clearStops", command_gradient_clearStops,
+ "^gradient_clearStops$",
+ "gradient_clearStops",
+ "gradient_clearStops");
+ DECL_PAINTCOMMAND("gradient_setConical", command_gradient_setConical,
+ "^gradient_setConical\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)$",
+ "gradient_setConical <cx> <cy> <angle>\n - angle in degrees",
+ "gradient_setConical 5.0 5.0 45.0");
+ DECL_PAINTCOMMAND("gradient_setLinear", command_gradient_setLinear,
+ "^gradient_setLinear\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)$",
+ "gradient_setLinear <x1> <y1> <x2> <y2>",
+ "gradient_setLinear 1.0 1.0 2.0 2.0");
+ DECL_PAINTCOMMAND("gradient_setRadial", command_gradient_setRadial,
+ "^gradient_setRadial\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$",
+ "gradient_setRadial <cx> <cy> <rad> <fx> <fy>\n - C is the center\n - rad is the 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_setColorCount", command_image_setColorCount,
+ "^image_setColorCount\\s+([\\w.:\\/]*)\\s+([0-9]*)$",
+ "image_setColorCount <imageName> <nbColors>",
+ "image_setColorCount 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 command lookup hash
+ for (int i=0; i<s_commandInfoTable.size(); i++) {
+ if (s_commandInfoTable.at(i).isSectionHeader() ||
+ s_commandInfoTable.at(i).identifier == QLatin1String("comment") ||
+ s_commandInfoTable.at(i).identifier == QLatin1String("noop"))
+ continue;
+ s_commandHash.insert(s_commandInfoTable.at(i).identifier, i);
+ }
+
+ // populate the enums list
+ ADD_ENUMLIST("brush styles", brushStyleTable);
+ ADD_ENUMLIST("pen styles", penStyleTable);
+ ADD_ENUMLIST("font weights", fontWeightTable);
+ ADD_ENUMLIST("font hintings", fontHintingTable);
+ ADD_ENUMLIST("clip operations", clipOperationTable);
+ ADD_ENUMLIST("spread methods", spreadMethodTable);
+ ADD_ENUMLIST("composition modes", compositionModeTable);
+ ADD_ENUMLIST("image formats", imageFormatTable);
+ ADD_ENUMLIST("coordinate modes", coordinateMethodTable);
+ ADD_ENUMLIST("size modes", sizeModeTable);
+}
+
+#undef DECL_PAINTCOMMAND
+#undef ADD_ENUMLIST
+/*********************************************************************************
+** utility
+**********************************************************************************/
+template <typename T> T PaintCommands::image_load(const QString &filepath)
+{
+ T t(filepath);
+
+ if (t.isNull())
+ t = T(":images/" + filepath);
+
+ if (t.isNull())
+ t = T("images/" + filepath);
+
+ if (t.isNull()) {
+ QFileInfo fi(filepath);
+ QDir dir = fi.absoluteDir();
+ dir.cdUp();
+ dir.cd("images");
+ QString fileName = 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)
+{
+ if (scriptLine.isEmpty()) {
+ command_noop(QRegExp());
+ return;
+ }
+ if (scriptLine.startsWith('#')) {
+ command_comment(QRegExp());
+ return;
+ }
+ QString firstWord = scriptLine.section(QRegExp("\\s"), 0, 0);
+ QList<int> indices = s_commandHash.values(firstWord);
+ foreach(int idx, indices) {
+ const PaintCommandInfos &command = s_commandInfoTable.at(idx);
+ if (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));
+ pt.end();
+ m_painter->drawTiledPixmap(0, 0, width, height, pm);
+ } else {
+ m_painter->fillRect(0, 0, width, height, Qt::white);
+ }
+
+ // run each command
+ m_abort = false;
+ for (int i=0; i<m_commands.size() && !m_abort; ++i) {
+ const QString &commandNow = m_commands.at(i);
+ m_currentCommand = commandNow;
+ m_currentCommandIndex = i;
+ runCommand(commandNow.trimmed());
+ }
+}
+
+/*********************************************************************************
+** conversions
+**********************************************************************************/
+int PaintCommands::convertToInt(const QString &str)
+{
+ return qRound(convertToDouble(str));
+}
+
+float PaintCommands::convertToFloat(const QString &str)
+{
+ return float(convertToDouble(str));
+}
+
+double PaintCommands::convertToDouble(const QString &str)
+{
+ static 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, (%f, %f, %f, %f), (%f, %f, %f, %f)\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), (%f, %f, %f, %f), (%f, %f, %f, %f)\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)
+{
+ if (!m_shouldDrawText)
+ return;
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ QString txt = caps.at(3);
+
+ if (m_verboseMode)
+ printf(" -(lance) drawText(%d, %d, %s)\n", x, y, qPrintable(txt));
+
+ m_painter->drawText(x, y, txt);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_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";
+
+ QFont font(family, size, weight, italic);
+
+#if QT_VERSION >= 0x040800
+ int hinting = translateEnum(fontHintingTable, caps.at(5), 4);
+ if (hinting == -1)
+ hinting = 0;
+ else
+ font.setHintingPreference(QFont::HintingPreference(hinting));
+#else
+ int hinting = 1;
+#endif
+ if (m_verboseMode)
+ printf(" -(lance) setFont(family=%s, size=%d, weight=%d, italic=%d hinting=%s\n",
+ qPrintable(family), size, weight, italic, fontHintingTable[hinting]);
+
+ m_painter->setFont(font);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_setPen(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_setColorCount(QRegExp re)
+{
+ QStringList caps = re.capturedTexts();
+
+ QString name = caps.at(1);
+ int count = convertToInt(caps.at(2));
+
+ if (m_verboseMode)
+ printf(" -(lance) image_setColorCount(%s), %d -> %d\n",
+ qPrintable(name), m_imageMap[name].colorCount(), count);
+
+ m_imageMap[name].setColorCount(count);
+}
+
+/***************************************************************************************************/
+void PaintCommands::command_image_setColor(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);
+}
diff --git a/tests/arthur/common/paintcommands.h b/tests/arthur/common/paintcommands.h
new file mode 100644
index 0000000000..2740412654
--- /dev/null
+++ b/tests/arthur/common/paintcommands.h
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+#ifndef PAINTCOMMANDS_H
+#define PAINTCOMMANDS_H
+
+#include <qcolor.h>
+#include <qmap.h>
+#include <qpainterpath.h>
+#include <qregion.h>
+#include <qstringlist.h>
+#include <qpixmap.h>
+#include <qbrush.h>
+#include <qhash.h>
+
+QT_FORWARD_DECLARE_CLASS(QPainter)
+QT_FORWARD_DECLARE_CLASS(QRegExp)
+#ifndef QT_NO_OPENGL
+QT_FORWARD_DECLARE_CLASS(QGLPixelBuffer)
+#endif
+
+enum DeviceType {
+ WidgetType,
+ BitmapType,
+ PixmapType,
+ ImageType,
+ ImageMonoType,
+ OpenGLType,
+ OpenGLPBufferType,
+ PictureType,
+ PrinterType,
+ PdfType,
+ PsType,
+ GrabType,
+ CustomDeviceType,
+ CustomWidgetType,
+ ImageWidgetType
+};
+
+/************************************************************************/
+class PaintCommands
+{
+public:
+ // construction / initialization
+ PaintCommands(const QStringList &cmds, int w, int h)
+ : m_painter(0)
+ , m_surface_painter(0)
+ , m_commands(cmds)
+ , m_gradientSpread(QGradient::PadSpread)
+ , m_gradientCoordinate(QGradient::LogicalMode)
+ , m_width(w)
+ , m_height(h)
+ , m_verboseMode(false)
+ , m_type(WidgetType)
+ , m_checkers_background(true)
+ , m_shouldDrawText(true)
+ { staticInit(); }
+
+public:
+ void setCheckersBackground(bool b) { staticInit(); m_checkers_background = b; }
+ void setContents(const QStringList &cmds) {
+ staticInit();
+ m_blockMap.clear();
+ m_pathMap.clear();
+ m_pixmapMap.clear();
+ m_imageMap.clear();
+ m_regionMap.clear();
+ m_gradientStops.clear();
+ m_controlPoints.clear();
+ m_gradientSpread = QGradient::PadSpread;
+ m_gradientCoordinate = QGradient::LogicalMode;
+ m_commands = cmds;
+
+
+ }
+ void setPainter(QPainter *pt) { staticInit(); m_painter = pt; }
+ void setType(DeviceType t) { staticInit(); m_type = t; }
+ void setFilePath(const QString &path) { staticInit(); m_filepath = path; }
+ void setControlPoints(const QVector<QPointF> &points) { staticInit(); m_controlPoints = points; }
+ void setVerboseMode(bool v) { staticInit(); m_verboseMode = v; }
+ void insertAt(int commandIndex, const QStringList &newCommands);
+ void setShouldDrawText(bool drawText) { m_shouldDrawText = drawText; }
+
+ // run
+ void runCommands();
+
+private:
+ // run
+ void runCommand(const QString &scriptLine);
+
+ // conversion methods
+ int convertToInt(const QString &str);
+ double convertToDouble(const QString &str);
+ float convertToFloat(const QString &str);
+ QColor convertToColor(const QString &str);
+
+ // commands: comments
+ void command_comment(QRegExp re);
+
+ // commands: importer
+ void command_import(QRegExp re);
+
+ // commands: blocks
+ void command_begin_block(QRegExp re);
+ void command_end_block(QRegExp re);
+ void command_repeat_block(QRegExp re);
+
+ // commands: misc
+ void command_textlayout_draw(QRegExp re);
+ void command_abort(QRegExp re);
+
+ // commands: noops
+ void command_noop(QRegExp re);
+
+ // commands: setters
+ void command_setBgMode(QRegExp re);
+ void command_setBackground(QRegExp re);
+ void command_setOpacity(QRegExp re);
+ void command_path_setFillRule(QRegExp re);
+ void command_setBrush(QRegExp re);
+ void command_setBrushOrigin(QRegExp re);
+ void command_brushTranslate(QRegExp re);
+ void command_brushRotate(QRegExp re);
+ void command_brushScale(QRegExp re);
+ void command_brushShear(QRegExp re);
+ void command_setClipPath(QRegExp re);
+ void command_setClipRect(QRegExp re);
+ void command_setClipRectangle(QRegExp re);
+ void command_setClipRegion(QRegExp re);
+ void command_setClipping(QRegExp re);
+ void command_setCompositionMode(QRegExp re);
+ void command_setFont(QRegExp re);
+ void command_setPen(QRegExp re);
+ void command_setPen2(QRegExp re);
+ void command_pen_setDashOffset(QRegExp re);
+ void command_pen_setDashPattern(QRegExp re);
+ void command_pen_setCosmetic(QRegExp re);
+ void command_setRenderHint(QRegExp re);
+ void command_clearRenderHint(QRegExp re);
+ void command_gradient_appendStop(QRegExp re);
+ void command_gradient_clearStops(QRegExp re);
+ void command_gradient_setConical(QRegExp re);
+ void command_gradient_setLinear(QRegExp re);
+ void command_gradient_setRadial(QRegExp re);
+ void command_gradient_setLinearPen(QRegExp re);
+ void command_gradient_setSpread(QRegExp re);
+ void command_gradient_setCoordinateMode(QRegExp re);
+
+ // commands: drawing ops
+#ifdef QT3_SUPPORT
+ void command_qt3_drawArc(QRegExp re);
+ void command_qt3_drawChord(QRegExp re);
+ void command_qt3_drawEllipse(QRegExp re);
+ void command_qt3_drawPie(QRegExp re);
+ void command_qt3_drawRect(QRegExp re);
+ void command_qt3_drawRoundRect(QRegExp re);
+#endif
+ void command_drawArc(QRegExp re);
+ void command_drawChord(QRegExp re);
+ void command_drawConvexPolygon(QRegExp re);
+ void command_drawEllipse(QRegExp re);
+ void command_drawImage(QRegExp re);
+ void command_drawLine(QRegExp re);
+ void command_drawPath(QRegExp re);
+ void command_drawPie(QRegExp re);
+ void command_drawPixmap(QRegExp re);
+ void command_drawPoint(QRegExp re);
+ void command_drawPolygon(QRegExp re);
+ void command_drawPolyline(QRegExp re);
+ void command_drawRect(QRegExp re);
+ void command_drawRoundedRect(QRegExp re);
+ void command_drawRoundRect(QRegExp re);
+ void command_drawText(QRegExp re);
+ void command_drawTiledPixmap(QRegExp re);
+ void command_path_addEllipse(QRegExp re);
+ void command_path_addPolygon(QRegExp re);
+ void command_path_addRect(QRegExp re);
+ void command_path_addText(QRegExp re);
+ void command_path_arcTo(QRegExp re);
+ void command_path_closeSubpath(QRegExp re);
+ void command_path_createOutline(QRegExp re);
+ void command_path_cubicTo(QRegExp re);
+ void command_path_debugPrint(QRegExp re);
+ void command_path_lineTo(QRegExp re);
+ void command_path_moveTo(QRegExp re);
+ void command_region_addEllipse(QRegExp re);
+ void command_region_addRect(QRegExp re);
+
+ // getters
+ void command_region_getClipRegion(QRegExp re);
+ void command_path_getClipPath(QRegExp re);
+
+ // commands: surface begin/end
+ void command_surface_begin(QRegExp re);
+ void command_surface_end(QRegExp re);
+
+ // commands: save/restore painter state
+ void command_restore(QRegExp re);
+ void command_save(QRegExp re);
+
+ // commands: pixmap/image
+ void command_pixmap_load(QRegExp re);
+ void command_pixmap_setMask(QRegExp re);
+ void command_bitmap_load(QRegExp re);
+ void command_image_convertToFormat(QRegExp re);
+ void command_image_load(QRegExp re);
+ void command_image_setColor(QRegExp re);
+ void command_image_setColorCount(QRegExp re);
+
+ // commands: transformation
+ void command_resetMatrix(QRegExp re);
+ void command_translate(QRegExp re);
+ void command_rotate(QRegExp re);
+ void command_rotate_x(QRegExp re);
+ void command_rotate_y(QRegExp re);
+ void command_scale(QRegExp re);
+ void command_mapQuadToQuad(QRegExp re);
+ void command_setMatrix(QRegExp re);
+
+ // attributes
+ QPainter *m_painter;
+ QPainter *m_surface_painter;
+ QImage m_surface_image;
+ QPixmap m_surface_pixmap;
+#ifndef QT_NO_OPENGL
+ QGLPixelBuffer *m_surface_pbuffer;
+#endif
+ QRectF m_surface_rect;
+ QStringList m_commands;
+ QString m_currentCommand;
+ int m_currentCommandIndex;
+ QString m_filepath;
+ QMap<QString, QStringList> m_blockMap;
+ QMap<QString, QPainterPath> m_pathMap;
+ QMap<QString, QPixmap> m_pixmapMap;
+ QMap<QString, QImage> m_imageMap;
+ QMap<QString, QRegion> m_regionMap;
+ QGradientStops m_gradientStops;
+ QGradient::Spread m_gradientSpread;
+ QGradient::CoordinateMode m_gradientCoordinate;
+ bool m_abort;
+ int m_width;
+ int m_height;
+
+ bool m_verboseMode;
+ DeviceType m_type;
+ bool m_checkers_background;
+ bool m_shouldDrawText;
+
+ QVector<QPointF> m_controlPoints;
+
+ // painter functionalities string tables
+ static const char *brushStyleTable[];
+ static const char *penStyleTable[];
+ static const char *fontWeightTable[];
+ static const char *fontHintingTable[];
+ static const char *clipOperationTable[];
+ static const char *spreadMethodTable[];
+ static const char *coordinateMethodTable[];
+ static const char *compositionModeTable[];
+ static const char *imageFormatTable[];
+ static const char *sizeModeTable[];
+ static int translateEnum(const char *table[], const QString &pattern, int limit);
+
+ // utility
+ template <typename T> T image_load(const QString &filepath);
+
+ // commands dictionary management
+ static void staticInit();
+
+public:
+ struct PaintCommandInfos
+ {
+ PaintCommandInfos(QString id, void (PaintCommands::*p)(QRegExp), QRegExp r, QString sy, QString sa)
+ : identifier(id)
+ , regExp(r)
+ , syntax(sy)
+ , sample(sa)
+ , paintMethod(p)
+ {}
+ PaintCommandInfos(QString title)
+ : identifier(title), paintMethod(0) {}
+ bool isSectionHeader() const { return paintMethod == 0; }
+ QString identifier;
+ QRegExp regExp;
+ QString syntax;
+ QString sample;
+ void (PaintCommands::*paintMethod)(QRegExp);
+ };
+
+ static PaintCommandInfos *findCommandById(const QString &identifier) {
+ for (int i=0; i<s_commandInfoTable.size(); i++)
+ if (s_commandInfoTable[i].identifier == identifier)
+ return &s_commandInfoTable[i];
+ return 0;
+ }
+
+ static QList<PaintCommandInfos> s_commandInfoTable;
+ static QList<QPair<QString,QStringList> > s_enumsTable;
+ static QMultiHash<QString, int> s_commandHash;
+};
+
+#endif // PAINTCOMMANDS_H
diff --git a/tests/arthur/common/qbaselinetest.cpp b/tests/arthur/common/qbaselinetest.cpp
new file mode 100644
index 0000000000..1d028f8b23
--- /dev/null
+++ b/tests/arthur/common/qbaselinetest.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qbaselinetest.h"
+#include "baselineprotocol.h"
+
+namespace QBaselineTest {
+
+BaselineProtocol proto;
+bool connected = false;
+bool triedConnecting = false;
+
+QByteArray curFunction;
+ImageItemList itemList;
+bool gotBaselines;
+
+
+bool connect(QByteArray *msg, bool *error)
+{
+ if (!triedConnecting) {
+ triedConnecting = true;
+ if (!proto.connect(QTest::testObject()->metaObject()->className())) {
+ *msg += "Failed to connect to baseline server: " + proto.errorMessage().toLatin1();
+ *error = true;
+ return false;
+ }
+ connected = true;
+ }
+ if (!connected) {
+ *msg = "Not connected to baseline server.";
+ *error = true;
+ return false;
+ }
+ return true;
+}
+
+
+bool compareItem(const ImageItem &baseline, const QImage &img, QByteArray *msg, bool *error)
+{
+ ImageItem item = baseline;
+ item.image = img;
+ item.imageChecksums.clear();
+ item.imageChecksums.prepend(ImageItem::computeChecksum(img));
+ QByteArray srvMsg;
+ switch (baseline.status) {
+ case ImageItem::Ok:
+ break;
+ case ImageItem::IgnoreItem :
+ qDebug() << msg->constData() << "Ignored, blacklisted on server.";
+ return true;
+ break;
+ case ImageItem::BaselineNotFound:
+ if (proto.submitNewBaseline(item, &srvMsg))
+ qDebug() << msg->constData() << "Baseline not found on server. New baseline uploaded.";
+ else
+ qDebug() << msg->constData() << "Baseline not found on server. Uploading of new baseline failed:" << srvMsg;
+ return true;
+ break;
+ default:
+ qWarning() << "Unexpected reply from baseline server.";
+ return true;
+ break;
+ }
+ *error = false;
+ // The actual comparison of the given image with the baseline:
+ if (baseline.imageChecksums.contains(item.imageChecksums.at(0)))
+ return true;
+ proto.submitMismatch(item, &srvMsg);
+ *msg += "Mismatch. See report:\n " + srvMsg;
+ return false;
+}
+
+bool checkImage(const QImage &img, const char *name, quint16 checksum, QByteArray *msg, bool *error)
+{
+ if (!connected && !connect(msg, error))
+ return true;
+
+ QByteArray itemName;
+ bool hasName = qstrlen(name);
+ const char *tag = QTest::currentDataTag();
+ if (qstrlen(tag)) {
+ itemName = tag;
+ if (hasName)
+ itemName.append('_').append(name);
+ } else {
+ itemName = hasName ? name : "default_name";
+ }
+
+ *msg = "Baseline check of image '" + itemName + "': ";
+
+
+ ImageItem item;
+ item.itemName = QString::fromLatin1(itemName);
+ item.itemChecksum = checksum;
+ item.testFunction = QString::fromLatin1(QTest::currentTestFunction());
+ ImageItemList list;
+ list.append(item);
+ if (!proto.requestBaselineChecksums(QLatin1String(QTest::currentTestFunction()), &list) || list.isEmpty()) {
+ *msg = "Communication with baseline server failed: " + proto.errorMessage().toLatin1();
+ *error = true;
+ return true;
+ }
+
+ return compareItem(list.at(0), img, msg, error);
+}
+
+
+QTestData &newRow(const char *dataTag, quint16 checksum)
+{
+ if (QTest::currentTestFunction() != curFunction) {
+ curFunction = QTest::currentTestFunction();
+ itemList.clear();
+ gotBaselines = false;
+ }
+ ImageItem item;
+ item.itemName = QString::fromLatin1(dataTag);
+ item.itemChecksum = checksum;
+ item.testFunction = QString::fromLatin1(QTest::currentTestFunction());
+ itemList.append(item);
+
+ return QTest::newRow(dataTag);
+}
+
+
+bool testImage(const QImage& img, QByteArray *msg, bool *error)
+{
+ if (!connected && !connect(msg, error))
+ return true;
+
+ if (QTest::currentTestFunction() != curFunction || itemList.isEmpty()) {
+ qWarning() << "Usage error: QBASELINE_TEST used without corresponding QBaselineTest::newRow()";
+ return true;
+ }
+
+ if (!gotBaselines) {
+ if (!proto.requestBaselineChecksums(QString::fromLatin1(QTest::currentTestFunction()), &itemList) || itemList.isEmpty()) {
+ *msg = "Communication with baseline server failed: " + proto.errorMessage().toLatin1();
+ *error = true;
+ return true;
+ }
+ gotBaselines = true;
+ }
+
+ QString curTag = QString::fromLatin1(QTest::currentDataTag());
+ ImageItemList::const_iterator it = itemList.constBegin();
+ while (it != itemList.constEnd() && it->itemName != curTag)
+ ++it;
+ if (it == itemList.constEnd()) {
+ qWarning() << "Usage error: QBASELINE_TEST used without corresponding QBaselineTest::newRow() for row" << curTag;
+ return true;
+ }
+ return compareItem(*it, img, msg, error);
+}
+
+}
diff --git a/tests/arthur/common/qbaselinetest.h b/tests/arthur/common/qbaselinetest.h
new file mode 100644
index 0000000000..dc32109979
--- /dev/null
+++ b/tests/arthur/common/qbaselinetest.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef BASELINETEST_H
+#define BASELINETEST_H
+
+#include <QTest>
+
+namespace QBaselineTest {
+bool checkImage(const QImage& img, const char *name, quint16 checksum, QByteArray *msg, bool *error);
+bool testImage(const QImage& img, QByteArray *msg, bool *error);
+QTestData &newRow(const char *dataTag, quint16 checksum = 0);
+}
+
+#define QBASELINE_CHECK_SUM(image, name, checksum)\
+do {\
+ QByteArray _msg;\
+ bool _err = false;\
+ if (!QBaselineTest::checkImage((image), (name), (checksum), &_msg, &_err)) {\
+ QFAIL(_msg.constData());\
+ } else if (_err) {\
+ QSKIP(_msg.constData(), SkipSingle);\
+ }\
+} while (0)
+
+#define QBASELINE_CHECK(image, name) QBASELINE_CHECK_SUM(image, name, 0)
+
+#define QBASELINE_TEST(image)\
+do {\
+ QByteArray _msg;\
+ bool _err = false;\
+ if (!QBaselineTest::testImage((image), &_msg, &_err)) {\
+ QFAIL(_msg.constData());\
+ } else if (_err) {\
+ QSKIP(_msg.constData(), SkipSingle);\
+ }\
+} while (0)
+
+#endif // BASELINETEST_H
diff --git a/tests/arthur/common/qbaselinetest.pri b/tests/arthur/common/qbaselinetest.pri
new file mode 100644
index 0000000000..5420c6ed1c
--- /dev/null
+++ b/tests/arthur/common/qbaselinetest.pri
@@ -0,0 +1,13 @@
+QT *= testlib
+
+SOURCES += \
+ $$PWD/qbaselinetest.cpp
+
+HEADERS += \
+ $$PWD/qbaselinetest.h
+
+win32|symbian*:MKSPEC=$$replace(QMAKESPEC, \\\\, /)
+else:MKSPEC=$$QMAKESPEC
+DEFINES += QMAKESPEC=\\\"$$MKSPEC\\\"
+
+include($$PWD/baselineprotocol.pri)
diff --git a/tests/arthur/common/qengines.cpp b/tests/arthur/common/qengines.cpp
new file mode 100644
index 0000000000..8eff2219b5
--- /dev/null
+++ b/tests/arthur/common/qengines.cpp
@@ -0,0 +1,733 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qengines.h"
+#include "paintcommands.h"
+
+#include <QApplication>
+#include <QProcess>
+#include <QPainter>
+#include <QSvgRenderer>
+#include <QStringList>
+#include <QDir>
+#include <QDebug>
+#include <QPrintEngine>
+#include <QWidget>
+
+// For QApplicationPrivate::graphics_system_name
+#include <private/qapplication_p.h>
+
+QEngine::~QEngine()
+{
+}
+
+Q_GLOBAL_STATIC(QtEngines, qtengines_global)
+QtEngines * QtEngines::self()
+{
+ return qtengines_global();
+}
+
+
+QList<QEngine*> QtEngines::engines() const
+{
+ return m_engines;
+}
+
+
+QList<QEngine*> QtEngines::foreignEngines() const
+{
+ return m_foreignEngines;
+}
+
+
+QEngine * QtEngines::defaultEngine() const
+{
+ return m_defaultEngine;
+}
+
+
+QtEngines::QtEngines()
+{
+ init();
+}
+
+
+void QtEngines::init()
+{
+ m_defaultEngine = new RasterEngine;
+ m_engines << m_defaultEngine
+ << new NativeEngine
+ << new WidgetEngine;
+
+#if defined(BUILD_OPENGL)
+ if (QGLFormat::hasOpenGL())
+ m_engines << new GLEngine;
+#endif
+
+#ifndef QT_NO_PRINTER
+ m_engines << new PDFEngine
+#ifdef Q_WS_X11
+ << new PSEngine
+#endif
+#ifdef Q_WS_WIN
+ << new WinPrintEngine
+#endif
+ ;
+#endif //QT_NO_PRINTER
+
+ m_foreignEngines << new RSVGEngine;
+}
+
+RasterEngine::RasterEngine()
+{
+
+}
+
+QString RasterEngine::name() const
+{
+ return QLatin1String("Raster");
+}
+
+
+void RasterEngine::prepare(const QSize &size, const QColor &fillColor)
+{
+ image = QImage(size, QImage::Format_ARGB32_Premultiplied);
+ QPainter p(&image);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.fillRect(image.rect(), fillColor);
+}
+
+
+void RasterEngine::render(QSvgRenderer *r, const QString &)
+{
+ QPainter p(&image);
+ r->render(&p);
+ p.end();
+}
+
+
+void RasterEngine::render(const QStringList &qpsScript,
+ const QString &absFilePath)
+{
+ QPainter pt(&image);
+ PaintCommands pcmd(qpsScript, 800, 800);
+ pcmd.setPainter(&pt);
+ pcmd.setFilePath(absFilePath);
+ pcmd.runCommands();
+ pt.end();
+}
+
+bool RasterEngine::drawOnPainter(QPainter *p)
+{
+ p->drawImage(0, 0, image);
+ return true;
+}
+
+void RasterEngine::save(const QString &file)
+{
+ image.save(file, "PNG");
+}
+
+
+NativeEngine::NativeEngine()
+{
+
+}
+
+
+QString NativeEngine::name() const
+{
+#ifdef Q_WS_X11
+#ifndef QT_NO_XRENDER
+ return QLatin1String("NativeXRender");
+#else
+ return QLatin1String("NativeXLib");
+#endif
+#elif (defined Q_WS_WIN32)
+ return QLatin1String("NativeWin32");
+#elif (defined Q_WS_MAC)
+ return QLatin1String("NativeMac");
+#elif defined(Q_WS_QWS)
+ return QLatin1String("NativeEmbedded");
+#endif
+}
+
+
+void NativeEngine::prepare(const QSize &size, const QColor &fillColor)
+{
+ pixmap = QPixmap(size);
+ pixmap.fill(fillColor);
+}
+
+
+void NativeEngine::render(QSvgRenderer *r, const QString &)
+{
+ QPainter p(&pixmap);
+ r->render(&p);
+ p.end();
+}
+
+
+void NativeEngine::render(const QStringList &qpsScript,
+ const QString &absFilePath)
+{
+ QPainter pt(&pixmap);
+ PaintCommands pcmd(qpsScript, 800, 800);
+ pcmd.setPainter(&pt);
+ pcmd.setFilePath(absFilePath);
+ pcmd.runCommands();
+ pt.end();
+}
+
+bool NativeEngine::drawOnPainter(QPainter *p)
+{
+ p->drawPixmap(0, 0, pixmap);
+ return true;
+}
+
+void NativeEngine::save(const QString &file)
+{
+ pixmap.save(file, "PNG");
+}
+
+
+#if defined(BUILD_OPENGL)
+GLEngine::GLEngine()
+ : pbuffer(0), widget(0)
+{
+ usePixelBuffers = QGLPixelBuffer::hasOpenGLPbuffers();
+}
+
+
+QString GLEngine::name() const
+{
+ return QLatin1String("OpenGL");
+}
+
+void GLEngine::prepare(const QSize &_size, const QColor &color)
+{
+ size = _size;
+ fillColor = color;
+ if (usePixelBuffers) {
+ pbuffer = new QGLPixelBuffer(size, QGLFormat(QGL::SampleBuffers));
+ } else {
+ widget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
+ widget->setAutoFillBackground(false);
+ widget->resize(size);
+ widget->show();
+ QApplication::flush();
+ QApplication::syncX();
+ }
+}
+
+void GLEngine::render(QSvgRenderer *r, const QString &)
+{
+ QPainter *p;
+ if (usePixelBuffers)
+ p = new QPainter(pbuffer);
+ else
+ p = new QPainter(widget);
+ p->fillRect(0, 0, size.width(), size.height(), fillColor);
+ r->render(p);
+ p->end();
+ delete p;
+}
+
+void GLEngine::render(const QStringList &qpsScript,
+ const QString &absFilePath)
+{
+ QPainter *p;
+ if (usePixelBuffers)
+ p = new QPainter(pbuffer);
+ else
+ p = new QPainter(widget);
+
+ PaintCommands pcmd(qpsScript, 800, 800);
+ pcmd.setPainter(p);
+ pcmd.setFilePath(absFilePath);
+ pcmd.runCommands();
+ p->end();
+ delete p;
+}
+
+bool GLEngine::drawOnPainter(QPainter *p)
+{
+ if (usePixelBuffers) {
+ QImage img = pbuffer->toImage();
+ p->drawImage(0, 0, img);
+ } else {
+ QImage img = widget->grabFrameBuffer();
+ p->drawImage(0, 0, img);
+ }
+ return true;
+}
+
+
+void GLEngine::save(const QString &file)
+{
+ if (usePixelBuffers) {
+ QImage img = pbuffer->toImage();
+ img.save(file, "PNG");
+ } else {
+ QImage img = widget->grabFrameBuffer();
+ img.save(file, "PNG");
+ }
+}
+
+void GLEngine::cleanup()
+{
+ delete pbuffer;
+ delete widget;
+}
+
+#endif
+
+class WidgetEngineWidget : public QWidget
+{
+public:
+ WidgetEngineWidget(QWidget* =0);
+
+ void paintEvent(QPaintEvent*);
+ void render(QSvgRenderer*);
+ void render(QStringList const&,QString const&);
+
+ QSize m_size;
+ QColor m_fillColor;
+
+private:
+ QSvgRenderer* m_svgr;
+ QStringList m_qpsScript;
+ QString m_absFilePath;
+};
+
+WidgetEngineWidget::WidgetEngineWidget(QWidget* parent)
+ : QWidget(parent)
+ , m_size()
+ , m_fillColor()
+ , m_svgr(0)
+ , m_qpsScript()
+ , m_absFilePath()
+{}
+
+void WidgetEngineWidget::render(QSvgRenderer* r)
+{
+ m_svgr = r;
+ repaint();
+ m_svgr = 0;
+}
+
+void WidgetEngineWidget::render(QStringList const& qpsScript, QString const& absFilePath)
+{
+ m_qpsScript = qpsScript;
+ m_absFilePath = absFilePath;
+ repaint();
+ m_qpsScript = QStringList();
+ m_absFilePath = QString();
+}
+
+void WidgetEngineWidget::paintEvent(QPaintEvent*)
+{
+ if (m_svgr) {
+ QPainter p(this);
+ p.fillRect(0, 0, m_size.width(), m_size.height(), m_fillColor);
+ m_svgr->render(&p);
+ p.end();
+ }
+ else {
+ QPainter p(this);
+
+ PaintCommands pcmd(m_qpsScript, 800, 800);
+ pcmd.setPainter(&p);
+ pcmd.setFilePath(m_absFilePath);
+ pcmd.runCommands();
+ p.end();
+ }
+}
+
+WidgetEngine::WidgetEngine()
+ : m_widget(0)
+{
+}
+
+
+QString WidgetEngine::name() const
+{
+ QString gs = QApplicationPrivate::graphics_system_name;
+ if (!gs.isEmpty()) gs[0] = gs[0].toUpper();
+ return QString::fromLatin1("Widget") + gs;
+}
+
+void WidgetEngine::prepare(const QSize &size, const QColor &color)
+{
+ m_widget = new WidgetEngineWidget;
+ m_widget->m_size = size;
+ m_widget->m_fillColor = color;
+ m_widget->setAutoFillBackground(false);
+ m_widget->resize(size);
+ m_widget->show();
+ QApplication::flush();
+ QApplication::syncX();
+}
+
+void WidgetEngine::render(QSvgRenderer *r, const QString &)
+{
+ m_widget->render(r);
+}
+
+void WidgetEngine::render(const QStringList &qpsScript,
+ const QString &absFilePath)
+{
+ m_widget->render(qpsScript, absFilePath);
+}
+
+bool WidgetEngine::drawOnPainter(QPainter *p)
+{
+ p->drawPixmap(0, 0, QPixmap::grabWindow(m_widget->winId()));
+ return true;
+}
+
+
+void WidgetEngine::save(const QString &file)
+{
+ QImage img = QPixmap::grabWindow(m_widget->winId()).toImage();
+ img.save(file, "PNG");
+}
+
+void WidgetEngine::cleanup()
+{
+ delete m_widget;
+}
+
+#ifndef QT_NO_PRINTER
+PDFEngine::PDFEngine()
+{
+}
+
+
+QString PDFEngine::name() const
+{
+ return QLatin1String("PDF");
+}
+
+void PDFEngine::prepare(const QSize &size, const QColor &fillColor)
+{
+ Q_UNUSED(fillColor);
+
+ static int i = 1;
+
+ m_size = size;
+ printer = new QPrinter(QPrinter::ScreenResolution);
+ printer->setOutputFormat(QPrinter::PdfFormat);
+ printer->setFullPage(true);
+ //printer->setOrientation(QPrinter::Landscape);
+ m_tempFile = QDir::tempPath() + QString("temp%1.pdf").arg(i++);
+ printer->setOutputFileName(m_tempFile);
+}
+
+void PDFEngine::render(QSvgRenderer *r, const QString &)
+{
+ QPainter p(printer);
+ r->render(&p);
+ p.end();
+}
+
+
+void PDFEngine::render(const QStringList &qpsScript,
+ const QString &absFilePath)
+{
+ QPainter pt(printer);
+ PaintCommands pcmd(qpsScript, 800, 800);
+ pcmd.setPainter(&pt);
+ pcmd.setFilePath(absFilePath);
+ pcmd.runCommands();
+ pt.end();
+}
+
+bool PDFEngine::drawOnPainter(QPainter *)
+{
+ return false;
+}
+
+void PDFEngine::save(const QString &file)
+{
+#ifdef USE_ACROBAT
+ QString psFile = m_tempFile;
+ psFile.replace(".pdf", ".ps");
+ QProcess toPs;
+ QStringList args1;
+ args1 << "-toPostScript"
+ << "-level3"
+ << "-transQuality"
+ << "1";
+ args1 << m_tempFile;
+ toPs.start("acroread", args1);
+ toPs.waitForFinished();
+
+ QProcess convert;
+ QStringList args;
+ args << psFile;
+ args << QString("-resize")
+ << QString("%1x%2")
+ .arg(m_size.width())
+ .arg(m_size.height());
+ args << file;
+
+ convert.start("convert", args);
+ convert.waitForFinished();
+ QFile::remove(psFile);
+#else
+ QProcess toPng;
+ QStringList args1;
+ args1 << "-sDEVICE=png16m"
+ << QString("-sOutputFile=") + file
+ << "-r97x69"
+ << "-dBATCH"
+ << "-dNOPAUSE";
+ args1 << m_tempFile;
+ toPng.start("gs", args1);
+ toPng.waitForFinished();
+#endif
+
+ QString pfile = file;
+ pfile.replace(".png", ".pdf");
+ QFile::rename(m_tempFile, pfile);
+// QFile::remove(m_tempFile);
+}
+
+void PDFEngine::cleanup()
+{
+ delete printer; printer = 0;
+}
+
+#ifdef Q_WS_X11
+PSEngine::PSEngine()
+{
+}
+
+
+QString PSEngine::name() const
+{
+ return QLatin1String("PS");
+}
+
+void PSEngine::prepare(const QSize &size, const QColor &fillColor)
+{
+ Q_UNUSED(fillColor);
+
+ static int i = 1;
+
+ m_size = size;
+ printer = new QPrinter(QPrinter::ScreenResolution);
+ printer->setOutputFormat(QPrinter::PostScriptFormat);
+ printer->setFullPage(true);
+ m_tempFile = QDir::tempPath() + QString("temp%1.ps").arg(i++);
+ printer->setOutputFileName(m_tempFile);
+}
+
+void PSEngine::render(QSvgRenderer *r, const QString &)
+{
+ QPainter p(printer);
+ r->render(&p);
+ p.end();
+}
+
+
+void PSEngine::render(const QStringList &qpsScript,
+ const QString &absFilePath)
+{
+ QPainter pt(printer);
+ PaintCommands pcmd(qpsScript, 800, 800);
+ pcmd.setPainter(&pt);
+ pcmd.setFilePath(absFilePath);
+ pcmd.runCommands();
+ pt.end();
+}
+
+bool PSEngine::drawOnPainter(QPainter *)
+{
+ return false;
+}
+
+void PSEngine::save(const QString &file)
+{
+ QProcess toPng;
+ QStringList args1;
+ args1 << "-sDEVICE=png16m"
+ << QString("-sOutputFile=") + file
+ << "-r97x69"
+ << "-dBATCH"
+ << "-dNOPAUSE";
+ args1 << m_tempFile;
+ toPng.start("gs", args1);
+ toPng.waitForFinished();
+
+ QString pfile = file;
+ pfile.replace(".png", ".ps");
+ QFile::rename(m_tempFile, pfile);
+}
+
+void PSEngine::cleanup()
+{
+ delete printer; printer = 0;
+}
+#endif
+#endif //QT_NO_PRINTER
+
+RSVGEngine::RSVGEngine()
+{
+
+}
+
+QString RSVGEngine::name() const
+{
+ return QLatin1String("RSVG");
+}
+
+void RSVGEngine::prepare(const QSize &size, const QColor &fillColor)
+{
+ Q_UNUSED(fillColor);
+
+ m_size = size;
+}
+
+void RSVGEngine::render(QSvgRenderer *, const QString &fileName)
+{
+ m_fileName = fileName;
+}
+
+void RSVGEngine::render(const QStringList &, const QString &)
+{
+}
+
+bool RSVGEngine::drawOnPainter(QPainter *)
+{
+ return false;
+}
+
+
+void RSVGEngine::save(const QString &file)
+{
+ QProcess rsvg;
+ QStringList args;
+ args << QString("-w %1").arg(m_size.width());
+ args << QString("-h %1").arg(m_size.height());
+ args << m_fileName;
+ args << file;
+ rsvg.start("rsvg", args);
+ rsvg.waitForFinished();
+}
+
+void QEngine::cleanup()
+{
+}
+
+#ifdef Q_WS_WIN
+WinPrintEngine::WinPrintEngine()
+{
+}
+
+
+QString WinPrintEngine::name() const
+{
+ return QLatin1String("WinPrint");
+}
+
+void WinPrintEngine::prepare(const QSize &size, const QColor &fillColor)
+{
+ Q_UNUSED(fillColor);
+
+ static int i = 1;
+
+ m_size = size;
+ printer = new QPrinter(QPrinter::ScreenResolution);
+ printer->setFullPage(true);
+ printer->setPrinterName("HP 2500C Series PS3");
+ m_tempFile = QDir::tempPath() + QString("temp%1.ps").arg(i++);
+ printer->setOutputFileName(m_tempFile);
+}
+
+void WinPrintEngine::render(QSvgRenderer *r, const QString &)
+{
+ QPainter p(printer);
+ r->render(&p);
+ p.end();
+}
+
+
+void WinPrintEngine::render(const QStringList &qpsScript,
+ const QString &absFilePath)
+{
+ QPainter pt(printer);
+ PaintCommands pcmd(qpsScript, 800, 800);
+ pcmd.setPainter(&pt);
+ pcmd.setFilePath(absFilePath);
+ pcmd.runCommands();
+ pt.end();
+}
+
+bool WinPrintEngine::drawOnPainter(QPainter *)
+{
+ return false;
+}
+
+void WinPrintEngine::save(const QString &file)
+{
+ QProcess toPng;
+ QStringList args1;
+ args1 << "-sDEVICE=png16m"
+ << QString("-sOutputFile=") + file
+ << "-r97x69"
+ << "-dBATCH"
+ << "-dNOPAUSE";
+ args1 << m_tempFile;
+ toPng.start("gswin32", args1);
+ toPng.waitForFinished();
+
+ QString pfile = file;
+ pfile.replace(".png", ".ps");
+ QFile::rename(m_tempFile, pfile);
+}
+
+void WinPrintEngine::cleanup()
+{
+ delete printer; printer = 0;
+}
+
+#endif
diff --git a/tests/arthur/common/qengines.h b/tests/arthur/common/qengines.h
new file mode 100644
index 0000000000..b731cfe419
--- /dev/null
+++ b/tests/arthur/common/qengines.h
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+#ifndef QENGINES_H
+#define QENGINES_H
+
+#if defined(BUILD_OPENGL)
+#include <QGLPixelBuffer>
+#endif
+#include <QPrinter>
+#include <QPixmap>
+#include <QImage>
+#include <QMap>
+#include <QList>
+#include <QColor>
+
+QT_FORWARD_DECLARE_CLASS(QSvgRenderer)
+QT_FORWARD_DECLARE_CLASS(QGLWidget)
+
+class QEngine
+{
+public:
+ virtual ~QEngine();
+ virtual QString name() const =0;
+ virtual void prepare(const QSize &size, const QColor &fillColor = Qt::white) =0;
+ virtual void render(QSvgRenderer *r, const QString &) =0;
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath) =0;
+ virtual bool drawOnPainter(QPainter *p) =0;
+ virtual void save(const QString &file) =0;
+ virtual void cleanup();
+};
+
+class QtEngines
+{
+public:
+ static QtEngines *self();
+ QtEngines();
+
+ QList<QEngine*> engines() const;
+ QList<QEngine*> foreignEngines() const;
+
+ QEngine *defaultEngine() const;
+private:
+ void init();
+private:
+ QList<QEngine*> m_engines;
+ QList<QEngine*> m_foreignEngines;
+ QEngine *m_defaultEngine;
+};
+
+class RasterEngine : public QEngine
+{
+public:
+ RasterEngine();
+
+ virtual QString name() const;
+ virtual void prepare(const QSize &size, const QColor &fillColor = Qt::white);
+ virtual void render(QSvgRenderer *r, const QString &);
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath);
+ virtual bool drawOnPainter(QPainter *p);
+ virtual void save(const QString &file);
+private:
+ QImage image;
+};
+
+class NativeEngine : public QEngine
+{
+public:
+ NativeEngine();
+
+ virtual QString name() const;
+ virtual void prepare(const QSize &size, const QColor &fillColor = Qt::white);
+ virtual void render(QSvgRenderer *r, const QString &);
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath);
+ virtual bool drawOnPainter(QPainter *p);
+ virtual void save(const QString &file);
+private:
+ QPixmap pixmap;
+};
+
+
+#if defined(BUILD_OPENGL)
+class GLEngine : public QEngine
+{
+public:
+ GLEngine();
+ virtual QString name() const;
+ virtual void prepare(const QSize &_size, const QColor &fillColor = Qt::white);
+ virtual void render(QSvgRenderer *r, const QString &);
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath);
+ virtual bool drawOnPainter(QPainter *p);
+ virtual void save(const QString &file);
+ virtual void cleanup();
+private:
+ QGLPixelBuffer *pbuffer;
+ QGLWidget *widget;
+ bool usePixelBuffers;
+ QSize size;
+ QColor fillColor;
+};
+#endif
+
+class WidgetEngineWidget;
+class WidgetEngine : public QEngine
+{
+public:
+ WidgetEngine();
+ virtual QString name() const;
+ virtual void prepare(const QSize &_size, const QColor &fillColor = Qt::white);
+ virtual void render(QSvgRenderer *r, const QString &);
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath);
+ virtual bool drawOnPainter(QPainter *p);
+ virtual void save(const QString &file);
+ virtual void cleanup();
+private:
+ WidgetEngineWidget *m_widget;
+};
+
+#ifndef QT_NO_PRINTER
+class PDFEngine : public QEngine
+{
+public:
+ PDFEngine();
+
+ virtual QString name() const;
+ virtual void prepare(const QSize &size, const QColor &fillColor = Qt::white);
+ virtual void render(QSvgRenderer *r, const QString &);
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath);
+ virtual bool drawOnPainter(QPainter *p);
+ virtual void save(const QString &file);
+ virtual void cleanup();
+private:
+ QPrinter *printer;
+ QSize m_size;
+ QString m_tempFile;
+};
+
+#ifdef Q_WS_X11
+class PSEngine : public QEngine
+{
+public:
+ PSEngine();
+
+ virtual QString name() const;
+ virtual void prepare(const QSize &size, const QColor &fillColor = Qt::white);
+ virtual void render(QSvgRenderer *r, const QString &);
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath);
+ virtual bool drawOnPainter(QPainter *p);
+ virtual void save(const QString &file);
+ virtual void cleanup();
+private:
+ QPrinter *printer;
+ QSize m_size;
+ QString m_tempFile;
+};
+#endif
+
+#ifdef Q_WS_WIN
+class WinPrintEngine : public QEngine
+{
+public:
+ WinPrintEngine();
+
+ virtual QString name() const;
+ virtual void prepare(const QSize &size, const QColor &fillColor = Qt::white);
+ virtual void render(QSvgRenderer *r, const QString &);
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath);
+ virtual bool drawOnPainter(QPainter *p);
+ virtual void save(const QString &file);
+ virtual void cleanup();
+private:
+ QPrinter *printer;
+ QSize m_size;
+ QString m_tempFile;
+};
+#endif
+#endif //QT_NO_PRINTER
+
+class RSVGEngine : public QEngine
+{
+public:
+ RSVGEngine();
+
+ virtual QString name() const;
+ virtual void prepare(const QSize &size, const QColor &fillColor = Qt::white);
+ virtual void render(QSvgRenderer *r, const QString &);
+ virtual void render(const QStringList &qpsScript,
+ const QString &absFilePath);
+ virtual bool drawOnPainter(QPainter *p);
+ virtual void save(const QString &file);
+private:
+ QString m_fileName;
+ QSize m_size;
+};
+
+#endif
diff --git a/tests/arthur/common/xmldata.cpp b/tests/arthur/common/xmldata.cpp
new file mode 100644
index 0000000000..5b6e1fdf49
--- /dev/null
+++ b/tests/arthur/common/xmldata.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "xmldata.h"
+
+
+bool XMLReader::startElement(const QString &, const QString &localName,
+ const QString &, const QXmlAttributes &attributes)
+{
+ if (localName == "arthur" ) {
+ QString engineName = attributes.value("engine");
+ QString defaultStr = attributes.value("default");
+ QString foreignStr = attributes.value("foreign");
+ QString referenceStr = attributes.value("reference");
+ QString genDate = attributes.value("generationDate");
+ engine = new XMLEngine(engineName, defaultStr == "true");
+ engine->foreignEngine = (foreignStr == "true");
+ engine->referenceEngine = (referenceStr == "true");
+ if (!genDate.isEmpty())
+ engine->generationDate = QDateTime::fromString(genDate);
+ else
+ engine->generationDate = QDateTime::currentDateTime();
+ } else if (localName == "suite") {
+ QString suiteName = attributes.value("dir");
+ suite = new XMLSuite(suiteName);
+ } else if (localName == "file") {
+ QString testName = attributes.value("name");
+ QString outputName = attributes.value("output");
+ file = new XMLFile(testName, outputName);
+ } else if (localName == "data") {
+ QString dateStr = attributes.value("date");
+ QString timeStr = attributes.value("time_to_render");
+ QString itrStr = attributes.value("iterations");
+ QString detailsStr = attributes.value("details");
+ QString maxElapsedStr = attributes.value("maxElapsed");
+ QString minElapsedStr = attributes.value("minElapsed");
+ XMLData data(dateStr, timeStr.toInt(),
+ (!itrStr.isEmpty())?itrStr.toInt():1);
+ data.details = detailsStr;
+ if (maxElapsedStr.isEmpty())
+ data.maxElapsed = data.timeToRender;
+ else
+ data.maxElapsed = maxElapsedStr.toInt();
+ if (minElapsedStr.isEmpty())
+ data.minElapsed = data.timeToRender;
+ else
+ data.minElapsed = minElapsedStr.toInt();
+
+ file->data.append(data);
+ } else {
+ qDebug()<<"Error while parsing element :"<<localName;
+ return false;
+ }
+ return true;
+}
+
+bool XMLReader::endElement(const QString &, const QString &localName,
+ const QString &)
+{
+ if (localName == "arthur" ) {
+ //qDebug()<<"done";
+ } else if (localName == "suite") {
+ engine->suites.insert(suite->name, suite);
+ } else if (localName == "file") {
+ suite->files.insert(file->name, file);
+ }
+ return true;
+}
+
+bool XMLReader::fatalError(const QXmlParseException &)
+{
+ return true;
+}
diff --git a/tests/arthur/common/xmldata.h b/tests/arthur/common/xmldata.h
new file mode 100644
index 0000000000..17d14051d7
--- /dev/null
+++ b/tests/arthur/common/xmldata.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+#ifndef XMLDATA_H
+#define XMLDATA_H
+
+#include <QtXml>
+
+#include <QMap>
+#include <QDateTime>
+
+enum GeneratorFlag {
+ Normal = 0x1 << 0,
+ Default = 0x1 << 1,
+ Foreign = 0x1 << 2,
+ Reference = 0x1 << 3
+};
+Q_DECLARE_FLAGS(GeneratorFlags, GeneratorFlag);
+
+struct XMLData
+{
+ XMLData()
+ : date(QDateTime::currentDateTime()),
+ timeToRender(0), iterations(0), maxElapsed(0),
+ minElapsed(0)
+ {}
+ XMLData(const QDateTime &dt, int ttr, int itrs = 1)
+ : date(dt), timeToRender(ttr),
+ iterations(itrs), maxElapsed(0), minElapsed(0)
+ {}
+ XMLData(const QString &dt, int ttr, int itrs = 1)
+ : timeToRender(ttr), iterations(itrs),
+ maxElapsed(0), minElapsed(0)
+ {
+ date = QDateTime::fromString(dt);
+ }
+ QDateTime date;
+ int timeToRender;
+ int iterations;
+ QString details;
+ int maxElapsed;
+ int minElapsed;
+};
+
+struct XMLFile
+{
+ XMLFile()
+ {}
+ XMLFile(const QString &testcase)
+ : name(testcase)
+ {}
+ XMLFile(const QString &testcase, const QString &img)
+ : name(testcase), output(img)
+ {}
+
+ QString name;
+ QString output;
+ QList<XMLData> data;
+};
+
+struct XMLSuite
+{
+ XMLSuite()
+ {}
+ XMLSuite(const QString &n)
+ : name(n)
+ {}
+
+ QString name;
+ QMap<QString, XMLFile*> files;
+};
+
+struct XMLEngine
+{
+ XMLEngine()
+ : defaultEngine(false), foreignEngine(false),
+ referenceEngine(false)
+ {}
+ XMLEngine(const QString &engine, bool def)
+ : name(engine), defaultEngine(def), foreignEngine(false),
+ referenceEngine(false)
+ {}
+
+ QString name;
+ bool defaultEngine;
+ bool foreignEngine;
+ bool referenceEngine;
+ QMap<QString, XMLSuite*> suites;
+ QDateTime generationDate;
+};
+
+
+
+class XMLReader : public QXmlDefaultHandler
+{
+public:
+ XMLEngine *xmlEngine() const
+ {
+ return engine;
+ }
+
+ bool startElement(const QString &namespaceURI,
+ const QString &localName,
+ const QString &qName,
+ const QXmlAttributes &attributes);
+ bool endElement(const QString &namespaceURI,
+ const QString &localName,
+ const QString &qName);
+ bool fatalError(const QXmlParseException &exception);
+private:
+ XMLEngine *engine;
+ XMLSuite *suite;
+ XMLFile *file;
+};
+
+#endif