diff options
author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2011-09-13 08:54:45 +0200 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2011-09-13 08:54:45 +0200 |
commit | b62bd0584a7872b6917917009b707785b3abd077 (patch) | |
tree | 9981f274712c098cabbff0c4667672a3934e5393 /tests/auto/gui | |
parent | 5e10745dca1d10025404a9f268f03ae697fb10cc (diff) | |
parent | 97baad65f65783d2b5ff938f6217aec9434f2e5f (diff) |
Merge branch 'refactor'
Conflicts:
mkspecs/qws/linux-lsb-g++/qmake.conf
src/gui/image/qpixmap_mac.cpp
src/gui/painting/qpaintengine_x11.cpp
src/gui/painting/qtessellator.cpp
src/gui/text/qfontengine_qws.cpp
src/gui/text/qfontengine_x11.cpp
src/gui/widgets/qlinecontrol.cpp
src/opengl/qgl.h
src/opengl/qgl_x11egl.cpp
src/plugins/plugins.pro
Change-Id: If52dcd55cd55f2983a756c2f843967702b60a310
Diffstat (limited to 'tests/auto/gui')
635 files changed, 66905 insertions, 0 deletions
diff --git a/tests/auto/gui/gui.pro b/tests/auto/gui/gui.pro new file mode 100644 index 0000000000..d54198467d --- /dev/null +++ b/tests/auto/gui/gui.pro @@ -0,0 +1,9 @@ +TEMPLATE=subdirs +SUBDIRS=\ + image \ + kernel \ + math3d \ + painting \ + text \ + util \ + diff --git a/tests/auto/gui/image/image.pro b/tests/auto/gui/image/image.pro new file mode 100644 index 0000000000..fe089f5e75 --- /dev/null +++ b/tests/auto/gui/image/image.pro @@ -0,0 +1,18 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qimagereader \ + qicoimageformat \ + qpixmap \ + qpixmapcache \ + qimage \ + qpixmapfilter \ + qimageiohandler \ + qimagewriter \ + qmovie \ + qvolatileimage \ + qicon \ + qpicture \ + +!contains(QT_CONFIG, private_tests): SUBDIRS -= \ + qpixmapcache \ + diff --git a/tests/auto/gui/image/qicoimageformat/.gitignore b/tests/auto/gui/image/qicoimageformat/.gitignore new file mode 100644 index 0000000000..9f673c5635 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/.gitignore @@ -0,0 +1 @@ +tst_qicoimageformat diff --git a/tests/auto/gui/image/qicoimageformat/icons/invalid/35floppy.ico b/tests/auto/gui/image/qicoimageformat/icons/invalid/35floppy.ico Binary files differnew file mode 100644 index 0000000000..96087612fb --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/invalid/35floppy.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/35FLOPPY.ICO b/tests/auto/gui/image/qicoimageformat/icons/valid/35FLOPPY.ICO Binary files differnew file mode 100644 index 0000000000..e9551d6390 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/35FLOPPY.ICO diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/AddPerfMon.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/AddPerfMon.ico Binary files differnew file mode 100644 index 0000000000..3368d3634a --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/AddPerfMon.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/App.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/App.ico Binary files differnew file mode 100644 index 0000000000..03b80a68f8 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/App.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/Obj_N2_Internal_Mem.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/Obj_N2_Internal_Mem.ico Binary files differnew file mode 100644 index 0000000000..8da119efdd --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/Obj_N2_Internal_Mem.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/Qt.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/Qt.ico Binary files differnew file mode 100644 index 0000000000..fef1dee146 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/Qt.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/Status_Play.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/Status_Play.ico Binary files differnew file mode 100644 index 0000000000..d05782cce9 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/Status_Play.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/TIMER01.ICO b/tests/auto/gui/image/qicoimageformat/icons/valid/TIMER01.ICO Binary files differnew file mode 100644 index 0000000000..5563beec8c --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/TIMER01.ICO diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/WORLD.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/WORLD.ico Binary files differnew file mode 100644 index 0000000000..7a8ab39f56 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/WORLD.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/WORLDH.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/WORLDH.ico Binary files differnew file mode 100644 index 0000000000..c2b48f8d99 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/WORLDH.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/abcardWindow.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/abcardWindow.ico Binary files differnew file mode 100644 index 0000000000..e78a15c42b --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/abcardWindow.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/semitransparent.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/semitransparent.ico Binary files differnew file mode 100644 index 0000000000..893ceb254c --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/semitransparent.ico diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/trolltechlogo_tiny.ico b/tests/auto/gui/image/qicoimageformat/icons/valid/trolltechlogo_tiny.ico Binary files differnew file mode 100644 index 0000000000..3e02a53e58 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/trolltechlogo_tiny.ico diff --git a/tests/auto/gui/image/qicoimageformat/qicoimageformat.pro b/tests/auto/gui/image/qicoimageformat/qicoimageformat.pro new file mode 100644 index 0000000000..c150c9af9f --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/qicoimageformat.pro @@ -0,0 +1,28 @@ +load(qttest_p4) +SOURCES+= tst_qicoimageformat.cpp + +wince*: { + DEFINES += SRCDIR=\\\".\\\" + addFiles.files = icons + addFiles.path = . + CONFIG(debug, debug|release):{ + addPlugins.files = $$QT_BUILD_TREE/plugins/imageformats/qico4d.dll + } else { + addPlugins.files = $$QT_BUILD_TREE/plugins/imageformats/qico4.dll + } + addPlugins.path = imageformats + DEPLOYMENT += addFiles addPlugins +} else:symbian { + addFiles.files = icons + addFiles.path = . + DEPLOYMENT += addFiles + qt_not_deployed { + addPlugins.files = qico.dll + addPlugins.path = imageformats + DEPLOYMENT += addPlugins + } + TARGET.UID3 = 0xE0340004 + DEFINES += SYMBIAN_SRCDIR_UID=$$lower($$replace(TARGET.UID3,"0x","")) +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} diff --git a/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp b/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp new file mode 100644 index 0000000000..3aace12fdb --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp @@ -0,0 +1,338 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtTest/QtTest> +#include <QtGui> +#include <QtCore> + +#if defined(Q_OS_SYMBIAN) +# define STRINGIFY(x) #x +# define TOSTRING(x) STRINGIFY(x) +# define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID) "/" +#endif + +class tst_QIcoImageFormat : public QObject +{ + Q_OBJECT + +public: + tst_QIcoImageFormat(); + virtual ~tst_QIcoImageFormat(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void format(); + void canRead_data(); + void canRead(); + void SequentialFile_data(); + void SequentialFile(); + void imageCount_data(); + void imageCount(); + void jumpToNextImage_data(); + void jumpToNextImage(); + void loopCount_data(); + void loopCount(); + void nextImageDelay_data(); + void nextImageDelay(); + void pngCompression_data(); + void pngCompression(); + +private: + QString m_IconPath; +}; + + +tst_QIcoImageFormat::tst_QIcoImageFormat() +{ + m_IconPath = QLatin1String(SRCDIR) + "/icons"; + qDebug() << m_IconPath; +} + +tst_QIcoImageFormat::~tst_QIcoImageFormat() +{ + +} + +void tst_QIcoImageFormat::init() +{ + +} + +void tst_QIcoImageFormat::cleanup() +{ + +} + +void tst_QIcoImageFormat::initTestCase() +{ + +} + +void tst_QIcoImageFormat::cleanupTestCase() +{ + +} + +void tst_QIcoImageFormat::format() +{ + QImageReader reader(m_IconPath + "/valid/35FLOPPY.ICO", "ico"); + QByteArray fmt = reader.format(); + QCOMPARE(const_cast<const char*>(fmt.data()), "ico" ); +} + +void tst_QIcoImageFormat::canRead_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("isValid"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 1; + QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 1; + QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; + QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 1; + QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 1; + QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 1; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 1; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 1; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; + QTest::newRow("103x16px, 24BPP") << "valid/trolltechlogo_tiny.ico" << 1; + QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 1; + QTest::newRow("PNG compression") << "valid/Qt.ico" << 1; +} + +void tst_QIcoImageFormat::canRead() +{ + QFETCH(QString, fileName); + QFETCH(int, isValid); + + QImageReader reader(m_IconPath + "/" + fileName); + QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); +} + +class QSequentialFile : public QFile +{ +public: + QSequentialFile(const QString &name) : QFile(name) {} + + virtual ~QSequentialFile() {} + + virtual bool isSequential() const { + return true; + } + +}; + +void tst_QIcoImageFormat::SequentialFile_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("isValid"); + + QTest::newRow("floppy (16,32 pixels - 16 colors)") << "valid/35FLOPPY.ICO" << 1; + + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; + + +} + +void tst_QIcoImageFormat::SequentialFile() +{ + QFETCH(QString, fileName); + QFETCH(int, isValid); + + QSequentialFile *file = new QSequentialFile(m_IconPath + "/" + fileName); + QVERIFY(file); + QVERIFY(file->open(QFile::ReadOnly)); + QImageReader reader(file); + + // Perform the check twice. If canRead() does not restore the sequential device back to its original state, + // it will fail on the second try. + QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); + QCOMPARE(reader.canRead(), (isValid == 0 ? false : true)); + file->close(); +} + + +void tst_QIcoImageFormat::imageCount_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("count"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; + QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; + QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; + QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; + QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; + QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; + QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; + QTest::newRow("PNG compression") << "valid/Qt.ico" << 4; + +} + +void tst_QIcoImageFormat::imageCount() +{ + QFETCH(QString, fileName); + QFETCH(int, count); + + QImageReader reader(m_IconPath + "/" + fileName); + QCOMPARE(reader.imageCount(), count); + +} + +void tst_QIcoImageFormat::jumpToNextImage_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("count"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; + QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; + QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; + QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; + QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; + QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; + QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; + QTest::newRow("PNG compression") << "valid/Qt.ico" << 4; +} + +void tst_QIcoImageFormat::jumpToNextImage() +{ + QFETCH(QString, fileName); + QFETCH(int, count); + + QImageReader reader(m_IconPath + "/" + fileName); + bool bJumped = reader.jumpToImage(0); + while (bJumped) { + count--; + bJumped = reader.jumpToNextImage(); + } + QCOMPARE(count, 0); +} + +void tst_QIcoImageFormat::loopCount_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("count"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 0; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; +} + +void tst_QIcoImageFormat::loopCount() +{ + QFETCH(QString, fileName); + QFETCH(int, count); + + QImageReader reader(m_IconPath + "/" + fileName); + QCOMPARE(reader.loopCount(), count); +} + +void tst_QIcoImageFormat::nextImageDelay_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("count"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "valid/35FLOPPY.ICO" << 2; + QTest::newRow("16px,32px,48px - 256,16M colors") << "valid/abcardWindow.ico" << 6; + QTest::newRow("16px - 16 colors") << "valid/App.ico" << 1; + QTest::newRow("16px,32px,48px - 16,256,16M colors") << "valid/Obj_N2_Internal_Mem.ico" << 9; + QTest::newRow("16px - 16,256,16M colors") << "valid/Status_Play.ico" << 3; + QTest::newRow("16px,32px - 16 colors") << "valid/TIMER01.ICO" << 2; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLD.ico" << 3; + QTest::newRow("16px16c, 32px32c, 32px256c") << "valid/WORLDH.ico" << 3; + QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << -1; + QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; + QTest::newRow("PNG compression") << "valid/Qt.ico" << 4; +} + +void tst_QIcoImageFormat::nextImageDelay() +{ + QFETCH(QString, fileName); + QFETCH(int, count); + + QImageReader reader(m_IconPath + "/" + fileName); + if (count == -1) { + QCOMPARE(reader.nextImageDelay(), 0); + } else { + int i; + for (i = 0; i < count; i++) { + QVERIFY(reader.jumpToImage(i)); + QCOMPARE(reader.nextImageDelay(), 0); + } + } +} + +void tst_QIcoImageFormat::pngCompression_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("index"); + QTest::addColumn<int>("width"); + QTest::addColumn<int>("height"); + + QTest::newRow("PNG compression") << "valid/Qt.ico" << 4 << 256 << 256; +} + +void tst_QIcoImageFormat::pngCompression() +{ + QFETCH(QString, fileName); + QFETCH(int, index); + QFETCH(int, width); + QFETCH(int, height); + + QImageReader reader(m_IconPath + "/" + fileName); + + QImage image; + reader.jumpToImage(index); + reader.read(&image); + + QCOMPARE(image.width(), width); + QCOMPARE(image.height(), height); +} + +QTEST_MAIN(tst_QIcoImageFormat) +#include "tst_qicoimageformat.moc" + diff --git a/tests/auto/gui/image/qicon/.gitignore b/tests/auto/gui/image/qicon/.gitignore new file mode 100644 index 0000000000..c101ef9d28 --- /dev/null +++ b/tests/auto/gui/image/qicon/.gitignore @@ -0,0 +1 @@ +tst_qicon diff --git a/tests/auto/gui/image/qicon/heart.svg b/tests/auto/gui/image/qicon/heart.svg new file mode 100644 index 0000000000..8c982cd93c --- /dev/null +++ b/tests/auto/gui/image/qicon/heart.svg @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --><svg viewBox="100 200 550 500" height="841.88976pt" id="svg1" inkscape:version="0.40+cvs" sodipodi:docbase="C:\Documents and Settings\Jon Phillips\My Documents\projects\clipart-project\submissions" sodipodi:docname="heart-left-highlight.svg" sodipodi:version="0.32" width="595.27559pt" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"> +<metadata> +<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> +<cc:Work rdf:about=""> +<dc:title>Heart Left-Highlight</dc:title> +<dc:description>This is a normal valentines day heart.</dc:description> +<dc:subject> +<rdf:Bag> +<rdf:li>holiday</rdf:li> +<rdf:li>valentines</rdf:li> +<rdf:li></rdf:li> +<rdf:li>valentine</rdf:li> +<rdf:li>hash(0x8a091c0)</rdf:li> +<rdf:li>hash(0x8a0916c)</rdf:li> +<rdf:li>signs_and_symbols</rdf:li> +<rdf:li>hash(0x8a091f0)</rdf:li> +<rdf:li>day</rdf:li> +</rdf:Bag> +</dc:subject> +<dc:publisher> +<cc:Agent rdf:about="http://www.openclipart.org"> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:publisher> +<dc:creator> +<cc:Agent> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:creator> +<dc:rights> +<cc:Agent> +<dc:title>Jon Phillips</dc:title> +</cc:Agent> +</dc:rights> +<dc:date></dc:date> +<dc:format>image/svg+xml</dc:format> +<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> +<cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/> +<dc:language>en</dc:language> +</cc:Work> +<cc:License rdf:about="http://web.resource.org/cc/PublicDomain"> +<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/> +<cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/> +<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/> +</cc:License> +</rdf:RDF> +</metadata> +<defs id="defs3"/> +<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" id="base" inkscape:current-layer="layer1" inkscape:cx="549.40674" inkscape:cy="596.00159" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:window-height="615" inkscape:window-width="866" inkscape:window-x="88" inkscape:window-y="116" inkscape:zoom="0.35000000" pagecolor="#ffffff" showguides="true"/> +<g id="layer1" inkscape:groupmode="layer" inkscape:label="Layer 1"> +<path d="M 263.41570,235.14588 C 197.17570,235.14588 143.41575,288.90587 143.41575,355.14588 C 143.41575,489.90139 279.34890,525.23318 371.97820,658.45392 C 459.55244,526.05056 600.54070,485.59932 600.54070,355.14588 C 600.54070,288.90588 546.78080,235.14587 480.54070,235.14588 C 432.49280,235.14588 391.13910,263.51631 371.97820,304.33338 C 352.81740,263.51630 311.46370,235.14587 263.41570,235.14588 z " id="path7" sodipodi:nodetypes="ccccccc" style="fill:#e60000;fill-opacity:1.0000000;stroke:#000000;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> +<path d="M 265.00000,253.59375 C 207.04033,253.59375 160.00000,300.63407 160.00000,358.59375 C 160.00000,476.50415 278.91857,507.43251 359.96875,624.00000 C 366.52868,614.08205 220.00000,478.47309 220.00000,378.59375 C 220.00000,320.63407 267.04033,273.59375 325.00000,273.59375 C 325.50453,273.59375 325.99718,273.64912 326.50000,273.65625 C 309.22436,261.07286 288.00557,253.59374 265.00000,253.59375 z " id="path220" sodipodi:nodetypes="ccccccc" style="fill:#e6e6e6;fill-opacity:0.64556962;stroke:none;stroke-width:18.700001;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> +</g> +</svg> diff --git a/tests/auto/gui/image/qicon/heart.svgz b/tests/auto/gui/image/qicon/heart.svgz Binary files differnew file mode 100644 index 0000000000..0f0913ffa7 --- /dev/null +++ b/tests/auto/gui/image/qicon/heart.svgz diff --git a/tests/auto/gui/image/qicon/icons/testtheme/16x16/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/testtheme/16x16/actions/appointment-new.png Binary files differnew file mode 100644 index 0000000000..18b7c6781e --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/testtheme/16x16/actions/appointment-new.png diff --git a/tests/auto/gui/image/qicon/icons/testtheme/22x22/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/testtheme/22x22/actions/appointment-new.png Binary files differnew file mode 100644 index 0000000000..d676ffd463 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/testtheme/22x22/actions/appointment-new.png diff --git a/tests/auto/gui/image/qicon/icons/testtheme/32x32/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/testtheme/32x32/actions/appointment-new.png Binary files differnew file mode 100644 index 0000000000..85daef3b0b --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/testtheme/32x32/actions/appointment-new.png diff --git a/tests/auto/gui/image/qicon/icons/testtheme/index.theme b/tests/auto/gui/image/qicon/icons/testtheme/index.theme new file mode 100644 index 0000000000..e18736ab43 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/testtheme/index.theme @@ -0,0 +1,492 @@ +[Icon Theme] +_Name=Test +_Comment=Test Theme +Inherits=crystalsvg, themeparent +Example=x-directory-normal + +# KDE Specific Stuff +DisplayDepth=32 +LinkOverlay=link_overlay +LockOverlay=lock_overlay +ZipOverlay=zip_overlay +DesktopDefault=48 +DesktopSizes=16,22,32,48,64,72,96,128 +ToolbarDefault=22 +ToolbarSizes=16,22,32,48 +MainToolbarDefault=22 +MainToolbarSizes=16,22,32,48 +SmallDefault=16 +SmallSizes=16 +PanelDefault=32 +PanelSizes=16,22,32,48,64,72,96,128 + +# Directory list +Directories=16x16/actions,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/mimetypes,16x16/places,16x16/status,22x22/actions,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/mimetypes,22x22/places,22x22/status,24x24/actions,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/mimetypes,24x24/places,24x24/status,32x32/actions,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/mimetypes,32x32/places,32x32/status,48x48/actions,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/mimetypes,48x48/places,48x48/status,64x64/actions,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/mimetypes,64x64/places,64x64/status,72x72/actions,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/mimetypes,72x72/places,72x72/status,96x96/actions,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/mimetypes,96x96/places,96x96/status,128x128/actions,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/mimetypes,128x128/places,128x128/status,scalable/actions,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/mimetypes,scalable/places,scalable/status + +[16x16/actions] +Size=16 +Context=Actions +Type=Fixed + +[16x16/apps] +Size=16 +Context=Applications +Type=Fixed + +[16x16/categories] +Size=16 +Context=Categories +Type=Fixed + +[16x16/devices] +Size=16 +Context=Devices +Type=Fixed + +[16x16/emblems] +Size=16 +Context=Emblems +Type=Fixed + +[16x16/emotes] +Size=16 +Context=Emotes +Type=Fixed + +[16x16/mimetypes] +Size=16 +Context=MimeTypes +Type=Fixed + +[16x16/places] +Size=16 +Context=Places +Type=Fixed + +[16x16/status] +Size=16 +Context=Status +Type=Fixed + +[22x22/actions] +Size=22 +Context=Actions +Type=Fixed + +[22x22/apps] +Size=22 +Context=Applications +Type=Fixed + +[22x22/categories] +Size=22 +Context=Categories +Type=Fixed + +[22x22/devices] +Size=22 +Context=Devices +Type=Fixed + +[22x22/emblems] +Size=22 +Context=Emblems +Type=Fixed + +[22x22/emotes] +Size=22 +Context=Emotes +Type=Fixed + +[22x22/mimetypes] +Size=22 +Context=MimeTypes +Type=Fixed + +[22x22/places] +Size=22 +Context=Places +Type=Fixed + +[22x22/status] +Size=22 +Context=Status +Type=Fixed + +[24x24/actions] +Size=24 +Context=Actions +Type=Fixed + +[24x24/apps] +Size=24 +Context=Applications +Type=Fixed + +[24x24/categories] +Size=24 +Context=Categories +Type=Fixed + +[24x24/devices] +Size=24 +Context=Devices +Type=Fixed + +[24x24/emblems] +Size=24 +Context=Emblems +Type=Fixed + +[24x24/emotes] +Size=24 +Context=Emotes +Type=Fixed + +[24x24/mimetypes] +Size=24 +Context=MimeTypes +Type=Fixed + +[24x24/places] +Size=24 +Context=Places +Type=Fixed + +[24x24/status] +Size=24 +Context=Status +Type=Fixed + +[32x32/actions] +Size=32 +Context=Actions +Type=Fixed + +[32x32/apps] +Size=32 +Context=Applications +Type=Fixed + +[32x32/categories] +Size=32 +Context=Categories +Type=Fixed + +[32x32/devices] +Size=32 +Context=Devices +Type=Fixed + +[32x32/emblems] +Size=32 +Context=Emblems +Type=Fixed + +[32x32/emotes] +Size=32 +Context=Emotes +Type=Fixed + +[32x32/mimetypes] +Size=32 +Context=MimeTypes +Type=Fixed + +[32x32/places] +Size=32 +Context=Places +Type=Fixed + +[32x32/status] +Size=32 +Context=Status +Type=Fixed + +[48x48/actions] +Size=48 +Context=Actions +Type=Fixed + +[48x48/apps] +Size=48 +Context=Applications +Type=Fixed + +[48x48/categories] +Size=48 +Context=Categories +Type=Fixed + +[48x48/devices] +Size=48 +Context=Devices +Type=Fixed + +[48x48/emblems] +Size=48 +Context=Emblems +Type=Fixed + +[48x48/emotes] +Size=48 +Context=Emotes +Type=Fixed + +[48x48/mimetypes] +Size=48 +Context=MimeTypes +Type=Fixed + +[48x48/places] +Size=48 +Context=Places +Type=Fixed + +[48x48/status] +Size=48 +Context=Status +Type=Fixed + +[64x64/actions] +Size=64 +Context=Actions +Type=Fixed + +[64x64/apps] +Size=64 +Context=Applications +Type=Fixed + +[64x64/categories] +Size=64 +Context=Categories +Type=Fixed + +[64x64/devices] +Size=64 +Context=Devices +Type=Fixed + +[64x64/emblems] +Size=64 +Context=Emblems +Type=Fixed + +[64x64/emotes] +Size=64 +Context=Emotes +Type=Fixed + +[64x64/mimetypes] +Size=64 +Context=MimeTypes +Type=Fixed + +[64x64/places] +Size=64 +Context=Places +Type=Fixed + +[64x64/status] +Size=64 +Context=Status +Type=Fixed + +[72x72/actions] +Size=72 +Context=Actions +Type=Fixed + +[72x72/apps] +Size=72 +Context=Applications +Type=Fixed + +[72x72/categories] +Size=72 +Context=Categories +Type=Fixed + +[72x72/devices] +Size=72 +Context=Devices +Type=Fixed + +[72x72/emblems] +Size=72 +Context=Emblems +Type=Fixed + +[72x72/emotes] +Size=72 +Context=Emotes +Type=Fixed + +[72x72/mimetypes] +Size=72 +Context=MimeTypes +Type=Fixed + +[72x72/places] +Size=72 +Context=Places +Type=Fixed + +[72x72/status] +Size=72 +Context=Status +Type=Fixed + +[96x96/actions] +Size=96 +Context=Actions +Type=Fixed + +[96x96/apps] +Size=96 +Context=Applications +Type=Fixed + +[96x96/categories] +Size=96 +Context=Categories +Type=Fixed + +[96x96/devices] +Size=96 +Context=Devices +Type=Fixed + +[96x96/emblems] +Size=96 +Context=Emblems +Type=Fixed + +[96x96/emotes] +Size=96 +Context=Emotes +Type=Fixed + +[96x96/mimetypes] +Size=96 +Context=MimeTypes +Type=Fixed + +[96x96/places] +Size=96 +Context=Places +Type=Fixed + +[96x96/status] +Size=96 +Context=Status +Type=Fixed + +[128x128/actions] +Size=128 +Context=Actions +Type=Fixed + +[128x128/apps] +Size=128 +Context=Applications +Type=Fixed + +[128x128/categories] +Size=128 +Context=Categories +Type=Fixed + +[128x128/devices] +Size=128 +Context=Devices +Type=Fixed + +[128x128/emblems] +Size=128 +Context=Emblems +Type=Fixed + +[128x128/emotes] +Size=128 +Context=Emotes +Type=Fixed + +[128x128/mimetypes] +Size=128 +Context=MimeTypes +Type=Fixed + +[128x128/places] +Size=128 +Context=Places +Type=Fixed + +[128x128/status] +Size=128 +Context=Status +Type=Fixed + +[scalable/actions] +Size=48 +Context=Actions +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/apps] +Size=48 +Context=Applications +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/categories] +Size=48 +Context=Categories +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/devices] +Size=48 +Context=Devices +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emblems] +Size=48 +Context=Emblems +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emotes] +Size=48 +Context=Emotes +Type=Scalable +Minsize=32 +MaxSize=256 + +[scalable/mimetypes] +Size=48 +Context=MimeTypes +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/places] +Size=48 +Context=Places +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/status] +Size=48 +Context=Status +Type=Scalable +MinSize=32 +MaxSize=256 diff --git a/tests/auto/gui/image/qicon/icons/testtheme/scalable/actions/svg-only.svg b/tests/auto/gui/image/qicon/icons/testtheme/scalable/actions/svg-only.svg new file mode 100644 index 0000000000..4cb14f82f0 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/testtheme/scalable/actions/svg-only.svg @@ -0,0 +1,425 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + inkscape:export-ydpi="90.000000" + inkscape:export-xdpi="90.000000" + inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png" + width="48px" + height="48px" + id="svg11300" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/actions" + sodipodi:docname="appointment-new.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs3"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 24 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="48 : 24 : 1" + inkscape:persp3d-origin="24 : 16 : 1" + id="perspective59" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5204"> + <stop + style="stop-color:#c4a000;stop-opacity:1;" + offset="0" + id="stop5206" /> + <stop + style="stop-color:#c4a000;stop-opacity:0;" + offset="1" + id="stop5208" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient5196"> + <stop + style="stop-color:#c4a000;stop-opacity:1;" + offset="0" + id="stop5198" /> + <stop + style="stop-color:#c4a000;stop-opacity:0;" + offset="1" + id="stop5200" /> + </linearGradient> + <linearGradient + id="linearGradient12512"> + <stop + style="stop-color:#ffffff;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop12513" /> + <stop + style="stop-color:#fff520;stop-opacity:0.89108908;" + offset="0.50000000" + id="stop12517" /> + <stop + style="stop-color:#fff300;stop-opacity:0.0000000;" + offset="1.0000000" + id="stop12514" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient12512" + id="radialGradient278" + gradientUnits="userSpaceOnUse" + cx="55.000000" + cy="125.00000" + fx="55.000000" + fy="125.00000" + r="14.375000" /> + <linearGradient + id="linearGradient10653"> + <stop + style="stop-color:#f3f4ff;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop10655" /> + <stop + style="stop-color:#9193af;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop10657" /> + </linearGradient> + <linearGradient + id="linearGradient42174"> + <stop + style="stop-color:#a0a0a0;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop42176" /> + <stop + style="stop-color:#ffffff;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop42178" /> + </linearGradient> + <linearGradient + id="linearGradient2145"> + <stop + style="stop-color:#fffffd;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop2147" /> + <stop + style="stop-color:#cbcbc9;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop2149" /> + </linearGradient> + <linearGradient + id="linearGradient37935"> + <stop + id="stop37937" + offset="0.0000000" + style="stop-color:#9497b3;stop-opacity:1.0000000;" /> + <stop + id="stop37939" + offset="1.0000000" + style="stop-color:#4c4059;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + id="linearGradient2152"> + <stop + id="stop2154" + offset="0.0000000" + style="stop-color:#9aa29a;stop-opacity:1.0000000;" /> + <stop + id="stop2156" + offset="1.0000000" + style="stop-color:#b5beb5;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3816"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop3818" /> + <stop + style="stop-color:#000000;stop-opacity:0;" + offset="1" + id="stop3820" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient3822" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2152" + id="linearGradient4307" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.123841,0.000000,0.000000,0.969691,-31.88758,-19.59492)" + x1="8.9156475" + y1="37.197018" + x2="9.8855033" + y2="52.090678" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient10653" + id="radialGradient4309" + gradientUnits="userSpaceOnUse" + cx="11.329200" + cy="10.583970" + fx="11.329200" + fy="10.583970" + r="15.532059" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2145" + id="radialGradient4311" + gradientUnits="userSpaceOnUse" + cx="11.901996" + cy="10.045444" + fx="11.901996" + fy="10.045444" + r="29.292715" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient42174" + id="linearGradient4313" + gradientUnits="userSpaceOnUse" + x1="6.3422160" + y1="7.7893324" + x2="22.218424" + y2="25.884274" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5196" + id="radialGradient5202" + cx="23.375" + cy="10.972863" + fx="23.375" + fy="10.972863" + r="3.3478092" + gradientTransform="matrix(3.630420,1.654030e-15,-1.608743e-15,3.742066,-61.48607,-29.18618)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5204" + id="linearGradient5210" + x1="19.667364" + y1="4.2570662" + x2="20.329933" + y2="5.2845874" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient37935" + id="radialGradient5212" + gradientUnits="userSpaceOnUse" + cx="8.7468252" + cy="6.8283234" + fx="8.7468252" + fy="6.8283234" + r="29.889715" /> + </defs> + <sodipodi:namedview + stroke="#c4a000" + fill="#babdb6" + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="0.25490196" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="11.313708" + inkscape:cx="13.2248" + inkscape:cy="25.106052" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:grid-bbox="true" + inkscape:document-units="px" + inkscape:showpageshadow="false" + inkscape:window-width="833" + inkscape:window-height="772" + inkscape:window-x="305" + inkscape:window-y="76" /> + <metadata + id="metadata4"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:creator> + <cc:Agent> + <dc:title>Jakub Steiner</dc:title> + </cc:Agent> + </dc:creator> + <dc:source>http://jimmac.musichall.cz</dc:source> + <cc:license + rdf:resource="http://creativecommons.org/licenses/publicdomain/" /> + <dc:title>New Appointment</dc:title> + <dc:subject> + <rdf:Bag> + <rdf:li>appointment</rdf:li> + <rdf:li>new</rdf:li> + <rdf:li>meeting</rdf:li> + <rdf:li>rvsp</rdf:li> + </rdf:Bag> + </dc:subject> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/licenses/publicdomain/"> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Reproduction" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Distribution" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> + </cc:License> + </rdf:RDF> + </metadata> + <g + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer"> + <path + d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" + sodipodi:ry="8.6620579" + sodipodi:rx="8.6620579" + sodipodi:cy="19.008621" + sodipodi:cx="31.112698" + id="path4318" + style="opacity:1;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + sodipodi:type="arc" + transform="matrix(2.563158,0.000000,0.000000,1.219602,-55.98414,14.04144)" /> + <path + sodipodi:nodetypes="cccc" + id="path14341" + d="M 18.587591,1.403729 L 4.226755,18.096665 L 5.4854717,19.339844 L 18.587591,1.403729 z " + style="color:#000000;fill:url(#linearGradient4307);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <path + sodipodi:nodetypes="cccc" + id="path18921" + d="M 18.467176,1.3138035 L 5.6605716,19.072612 L 7.4900985,20.687913 L 18.467176,1.3138035 z " + style="fill:#fefefe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" /> + <path + transform="matrix(1.431529,0.000000,0.000000,1.431529,0.569459,-1.654618)" + d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z" + sodipodi:ry="14.910714" + sodipodi:rx="14.910714" + sodipodi:cy="16.910715" + sodipodi:cx="16.25" + id="path27786" + style="fill:url(#radialGradient5212);fill-opacity:1;fill-rule:evenodd;stroke:#605773;stroke-width:0.69855404;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:type="arc" /> + <path + transform="matrix(1.163838,0.000000,0.000000,1.163838,4.824801,2.777556)" + d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z" + sodipodi:ry="14.910714" + sodipodi:rx="14.910714" + sodipodi:cy="16.910715" + sodipodi:cx="16.25" + id="path35549" + style="fill:url(#radialGradient4311);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4313);stroke-width:0.71139598;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:type="arc" /> + <path + sodipodi:type="arc" + style="opacity:1;color:#000000;fill:url(#radialGradient5202);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5210);stroke-width:0.56498736;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path4120" + sodipodi:cx="23.375" + sodipodi:cy="11.875" + sodipodi:rx="8.5" + sodipodi:ry="8.5" + d="M 16.679382,6.6387137 A 8.5,8.5 0 0 1 23.332691,3.3751053 L 23.375,11.875 z" + transform="matrix(1.769951,0.000000,0.000000,1.769951,-17.02424,1.610741)" + sodipodi:start="3.8052902" + sodipodi:end="4.7074114" /> + <path + transform="matrix(2.073295,0.000000,0.000000,2.073295,-7.310224,-13.13682)" + d="M 16.40625 17.28125 A 1.21875 1.21875 0 1 1 13.96875,17.28125 A 1.21875 1.21875 0 1 1 16.40625 17.28125 z" + sodipodi:ry="1.21875" + sodipodi:rx="1.21875" + sodipodi:cy="17.28125" + sodipodi:cx="15.1875" + id="path34778" + style="fill:#f3f3f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.48232403;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;stroke-dasharray:none" + sodipodi:type="arc" /> + <path + id="path35559" + d="M 22.176614,20.718014 L 13.155702,13.140282" + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + id="path35561" + d="M 19.408614,29.776506 L 22.368655,25.283228" + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + sodipodi:nodetypes="cc" /> + <path + transform="matrix(2.749493,0.000000,0.000000,2.749493,-22.30073,-12.40939)" + d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z" + sodipodi:ry="0.61871845" + sodipodi:rx="0.61871845" + sodipodi:cy="7.6932044" + sodipodi:cx="16.705399" + id="path35563" + style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" + sodipodi:type="arc" /> + <path + transform="matrix(2.749493,0.000000,0.000000,2.749493,-22.30073,14.80922)" + d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z" + sodipodi:ry="0.61871845" + sodipodi:rx="0.61871845" + sodipodi:cy="7.6932044" + sodipodi:cx="16.705399" + id="path35565" + style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" + sodipodi:type="arc" /> + <path + transform="matrix(2.749493,0.000000,0.000000,2.749493,-35.91004,1.199890)" + d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z" + sodipodi:ry="0.61871845" + sodipodi:rx="0.61871845" + sodipodi:cy="7.6932044" + sodipodi:cx="16.705399" + id="path35567" + style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" + sodipodi:type="arc" /> + <path + transform="matrix(2.749493,0.000000,0.000000,2.749493,-8.691448,1.199890)" + d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z" + sodipodi:ry="0.61871845" + sodipodi:rx="0.61871845" + sodipodi:cy="7.6932044" + sodipodi:cx="16.705399" + id="path35569" + style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" + sodipodi:type="arc" /> + <path + sodipodi:type="arc" + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient4309);stroke-width:0.73656511;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" + id="path10651" + sodipodi:cx="16.25" + sodipodi:cy="16.910715" + sodipodi:rx="14.910714" + sodipodi:ry="14.910714" + d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z" + transform="matrix(1.357654,0.000000,0.000000,1.357654,1.769896,-0.493735)" /> + <path + sodipodi:type="arc" + style="color:#000000;fill:url(#radialGradient278);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block" + id="path12511" + sodipodi:cx="55" + sodipodi:cy="125" + sodipodi:rx="14.375" + sodipodi:ry="14.375" + d="M 69.375 125 A 14.375 14.375 0 1 1 40.625,125 A 14.375 14.375 0 1 1 69.375 125 z" + transform="matrix(0.611127,0.000000,0.000000,0.611127,5.544052,-66.92818)" + inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/stock_new-16.png" + inkscape:export-xdpi="33.852203" + inkscape:export-ydpi="33.852203" /> + </g> +</svg> diff --git a/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/address-book-new.png b/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/address-book-new.png Binary files differnew file mode 100644 index 0000000000..2098cfdf36 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/address-book-new.png diff --git a/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/appointment-new.png Binary files differnew file mode 100644 index 0000000000..18b7c6781e --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/appointment-new.png diff --git a/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/address-book-new.png b/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/address-book-new.png Binary files differnew file mode 100644 index 0000000000..fad446cd92 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/address-book-new.png diff --git a/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/appointment-new.png Binary files differnew file mode 100644 index 0000000000..d676ffd463 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/appointment-new.png diff --git a/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/address-book-new.png b/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/address-book-new.png Binary files differnew file mode 100644 index 0000000000..420139d307 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/address-book-new.png diff --git a/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/appointment-new.png Binary files differnew file mode 100644 index 0000000000..85daef3b0b --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/appointment-new.png diff --git a/tests/auto/gui/image/qicon/icons/themeparent/index.theme b/tests/auto/gui/image/qicon/icons/themeparent/index.theme new file mode 100644 index 0000000000..e536a0bf2f --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/index.theme @@ -0,0 +1,492 @@ +[Icon Theme] +_Name=Test +_Comment=Test Theme +Inherits=gnome,crystalsvg +Example=x-directory-normal + +# KDE Specific Stuff +DisplayDepth=32 +LinkOverlay=link_overlay +LockOverlay=lock_overlay +ZipOverlay=zip_overlay +DesktopDefault=48 +DesktopSizes=16,22,32,48,64,72,96,128 +ToolbarDefault=22 +ToolbarSizes=16,22,32,48 +MainToolbarDefault=22 +MainToolbarSizes=16,22,32,48 +SmallDefault=16 +SmallSizes=16 +PanelDefault=32 +PanelSizes=16,22,32,48,64,72,96,128 + +# Directory list +Directories=16x16/actions,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/mimetypes,16x16/places,16x16/status,22x22/actions,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/mimetypes,22x22/places,22x22/status,24x24/actions,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/mimetypes,24x24/places,24x24/status,32x32/actions,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/mimetypes,32x32/places,32x32/status,48x48/actions,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/mimetypes,48x48/places,48x48/status,64x64/actions,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/mimetypes,64x64/places,64x64/status,72x72/actions,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/mimetypes,72x72/places,72x72/status,96x96/actions,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/mimetypes,96x96/places,96x96/status,128x128/actions,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/mimetypes,128x128/places,128x128/status,scalable/actions,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/mimetypes,scalable/places,scalable/status + +[16x16/actions] +Size=16 +Context=Actions +Type=Fixed + +[16x16/apps] +Size=16 +Context=Applications +Type=Fixed + +[16x16/categories] +Size=16 +Context=Categories +Type=Fixed + +[16x16/devices] +Size=16 +Context=Devices +Type=Fixed + +[16x16/emblems] +Size=16 +Context=Emblems +Type=Fixed + +[16x16/emotes] +Size=16 +Context=Emotes +Type=Fixed + +[16x16/mimetypes] +Size=16 +Context=MimeTypes +Type=Fixed + +[16x16/places] +Size=16 +Context=Places +Type=Fixed + +[16x16/status] +Size=16 +Context=Status +Type=Fixed + +[22x22/actions] +Size=22 +Context=Actions +Type=Fixed + +[22x22/apps] +Size=22 +Context=Applications +Type=Fixed + +[22x22/categories] +Size=22 +Context=Categories +Type=Fixed + +[22x22/devices] +Size=22 +Context=Devices +Type=Fixed + +[22x22/emblems] +Size=22 +Context=Emblems +Type=Fixed + +[22x22/emotes] +Size=22 +Context=Emotes +Type=Fixed + +[22x22/mimetypes] +Size=22 +Context=MimeTypes +Type=Fixed + +[22x22/places] +Size=22 +Context=Places +Type=Fixed + +[22x22/status] +Size=22 +Context=Status +Type=Fixed + +[24x24/actions] +Size=24 +Context=Actions +Type=Fixed + +[24x24/apps] +Size=24 +Context=Applications +Type=Fixed + +[24x24/categories] +Size=24 +Context=Categories +Type=Fixed + +[24x24/devices] +Size=24 +Context=Devices +Type=Fixed + +[24x24/emblems] +Size=24 +Context=Emblems +Type=Fixed + +[24x24/emotes] +Size=24 +Context=Emotes +Type=Fixed + +[24x24/mimetypes] +Size=24 +Context=MimeTypes +Type=Fixed + +[24x24/places] +Size=24 +Context=Places +Type=Fixed + +[24x24/status] +Size=24 +Context=Status +Type=Fixed + +[32x32/actions] +Size=32 +Context=Actions +Type=Fixed + +[32x32/apps] +Size=32 +Context=Applications +Type=Fixed + +[32x32/categories] +Size=32 +Context=Categories +Type=Fixed + +[32x32/devices] +Size=32 +Context=Devices +Type=Fixed + +[32x32/emblems] +Size=32 +Context=Emblems +Type=Fixed + +[32x32/emotes] +Size=32 +Context=Emotes +Type=Fixed + +[32x32/mimetypes] +Size=32 +Context=MimeTypes +Type=Fixed + +[32x32/places] +Size=32 +Context=Places +Type=Fixed + +[32x32/status] +Size=32 +Context=Status +Type=Fixed + +[48x48/actions] +Size=48 +Context=Actions +Type=Fixed + +[48x48/apps] +Size=48 +Context=Applications +Type=Fixed + +[48x48/categories] +Size=48 +Context=Categories +Type=Fixed + +[48x48/devices] +Size=48 +Context=Devices +Type=Fixed + +[48x48/emblems] +Size=48 +Context=Emblems +Type=Fixed + +[48x48/emotes] +Size=48 +Context=Emotes +Type=Fixed + +[48x48/mimetypes] +Size=48 +Context=MimeTypes +Type=Fixed + +[48x48/places] +Size=48 +Context=Places +Type=Fixed + +[48x48/status] +Size=48 +Context=Status +Type=Fixed + +[64x64/actions] +Size=64 +Context=Actions +Type=Fixed + +[64x64/apps] +Size=64 +Context=Applications +Type=Fixed + +[64x64/categories] +Size=64 +Context=Categories +Type=Fixed + +[64x64/devices] +Size=64 +Context=Devices +Type=Fixed + +[64x64/emblems] +Size=64 +Context=Emblems +Type=Fixed + +[64x64/emotes] +Size=64 +Context=Emotes +Type=Fixed + +[64x64/mimetypes] +Size=64 +Context=MimeTypes +Type=Fixed + +[64x64/places] +Size=64 +Context=Places +Type=Fixed + +[64x64/status] +Size=64 +Context=Status +Type=Fixed + +[72x72/actions] +Size=72 +Context=Actions +Type=Fixed + +[72x72/apps] +Size=72 +Context=Applications +Type=Fixed + +[72x72/categories] +Size=72 +Context=Categories +Type=Fixed + +[72x72/devices] +Size=72 +Context=Devices +Type=Fixed + +[72x72/emblems] +Size=72 +Context=Emblems +Type=Fixed + +[72x72/emotes] +Size=72 +Context=Emotes +Type=Fixed + +[72x72/mimetypes] +Size=72 +Context=MimeTypes +Type=Fixed + +[72x72/places] +Size=72 +Context=Places +Type=Fixed + +[72x72/status] +Size=72 +Context=Status +Type=Fixed + +[96x96/actions] +Size=96 +Context=Actions +Type=Fixed + +[96x96/apps] +Size=96 +Context=Applications +Type=Fixed + +[96x96/categories] +Size=96 +Context=Categories +Type=Fixed + +[96x96/devices] +Size=96 +Context=Devices +Type=Fixed + +[96x96/emblems] +Size=96 +Context=Emblems +Type=Fixed + +[96x96/emotes] +Size=96 +Context=Emotes +Type=Fixed + +[96x96/mimetypes] +Size=96 +Context=MimeTypes +Type=Fixed + +[96x96/places] +Size=96 +Context=Places +Type=Fixed + +[96x96/status] +Size=96 +Context=Status +Type=Fixed + +[128x128/actions] +Size=128 +Context=Actions +Type=Fixed + +[128x128/apps] +Size=128 +Context=Applications +Type=Fixed + +[128x128/categories] +Size=128 +Context=Categories +Type=Fixed + +[128x128/devices] +Size=128 +Context=Devices +Type=Fixed + +[128x128/emblems] +Size=128 +Context=Emblems +Type=Fixed + +[128x128/emotes] +Size=128 +Context=Emotes +Type=Fixed + +[128x128/mimetypes] +Size=128 +Context=MimeTypes +Type=Fixed + +[128x128/places] +Size=128 +Context=Places +Type=Fixed + +[128x128/status] +Size=128 +Context=Status +Type=Fixed + +[scalable/actions] +Size=48 +Context=Actions +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/apps] +Size=48 +Context=Applications +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/categories] +Size=48 +Context=Categories +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/devices] +Size=48 +Context=Devices +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emblems] +Size=48 +Context=Emblems +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emotes] +Size=48 +Context=Emotes +Type=Scalable +Minsize=32 +MaxSize=256 + +[scalable/mimetypes] +Size=48 +Context=MimeTypes +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/places] +Size=48 +Context=Places +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/status] +Size=48 +Context=Status +Type=Scalable +MinSize=32 +MaxSize=256 diff --git a/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/address-book-new.svg b/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/address-book-new.svg new file mode 100644 index 0000000000..600a82c1b0 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/address-book-new.svg @@ -0,0 +1,389 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="48px" + height="48px" + id="svg1256" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions" + sodipodi:docname="address-book-new.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs3"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 24 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="48 : 24 : 1" + inkscape:persp3d-origin="24 : 16 : 1" + id="perspective58" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5060"> + <stop + style="stop-color:black;stop-opacity:1;" + offset="0" + id="stop5062" /> + <stop + style="stop-color:black;stop-opacity:0;" + offset="1" + id="stop5064" /> + </linearGradient> + <linearGradient + id="linearGradient5048"> + <stop + style="stop-color:black;stop-opacity:0;" + offset="0" + id="stop5050" /> + <stop + id="stop5056" + offset="0.5" + style="stop-color:black;stop-opacity:1;" /> + <stop + style="stop-color:black;stop-opacity:0;" + offset="1" + id="stop5052" /> + </linearGradient> + <linearGradient + id="linearGradient12512"> + <stop + style="stop-color:#ffffff;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop12513" /> + <stop + style="stop-color:#fff520;stop-opacity:0.89108908;" + offset="0.50000000" + id="stop12517" /> + <stop + style="stop-color:#fff300;stop-opacity:0.0000000;" + offset="1.0000000" + id="stop12514" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient12512" + id="radialGradient278" + gradientUnits="userSpaceOnUse" + cx="55.000000" + cy="125.00000" + fx="55.000000" + fy="125.00000" + r="14.375000" /> + <linearGradient + inkscape:collect="always" + id="linearGradient2116"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop2118" /> + <stop + style="stop-color:#ffffff;stop-opacity:0;" + offset="1" + id="stop2120" /> + </linearGradient> + <linearGradient + id="linearGradient2094"> + <stop + style="stop-color:#d6e3f0;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop2096" /> + <stop + style="stop-color:#95b1cf;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop2098" /> + </linearGradient> + <linearGradient + id="linearGradient2803"> + <stop + id="stop2805" + offset="0" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + id="stop2807" + offset="1.0000000" + style="stop-color:#cbcbcb;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + id="linearGradient2795"> + <stop + id="stop2797" + offset="0.0000000" + style="stop-color:#000000;stop-opacity:0.068627454;" /> + <stop + id="stop2799" + offset="1.0000000" + style="stop-color:#ffffff;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="4.9530048" + x2="41.219128" + y1="4.9530050" + x1="35.433035" + gradientTransform="matrix(0.254000,0.000000,1.822151e-16,3.759813,0.788629,0.148567)" + id="linearGradient2801" + xlink:href="#linearGradient2795" + inkscape:collect="always" /> + <linearGradient + gradientUnits="userSpaceOnUse" + y2="84.287079" + x2="10.219901" + y1="93.338043" + x1="10.496115" + gradientTransform="matrix(2.262742,0.000000,0.000000,0.441942,1.000000,-0.875000)" + id="linearGradient2813" + xlink:href="#linearGradient2803" + inkscape:collect="always" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2094" + id="linearGradient2100" + gradientTransform="matrix(0.957750,0.000000,0.000000,1.027989,1.000000,-0.571911)" + x1="6.5871811" + y1="22.132999" + x2="14.511404" + y2="22.132999" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2116" + id="linearGradient2112" + gradientTransform="matrix(1.025428,0.000000,0.000000,0.957303,0.000000,-0.806758)" + x1="73.361984" + y1="26.652197" + x2="-2.7582901" + y2="21.270376" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060" + id="radialGradient5013" + gradientUnits="userSpaceOnUse" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5048" + id="linearGradient5016" + gradientUnits="userSpaceOnUse" + x1="302.85715" + y1="366.64789" + x2="302.85715" + y2="609.50507" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060" + id="radialGradient5020" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5048" + id="linearGradient5027" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x1="302.85715" + y1="366.64789" + x2="302.85715" + y2="609.50507" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060" + id="radialGradient5029" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060" + id="radialGradient5031" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="0.27843137" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1" + inkscape:cx="-111.52422" + inkscape:cy="10.167608" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:grid-bbox="true" + inkscape:document-units="px" + inkscape:window-width="872" + inkscape:window-height="688" + inkscape:window-x="562" + inkscape:window-y="160" + fill="#ef2929" + stroke="#cc0000" + inkscape:showpageshadow="false" /> + <metadata + id="metadata4"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title>Addess Book - New</dc:title> + <dc:date /> + <dc:creator> + <cc:Agent> + <dc:title>Jakub Steiner</dc:title> + </cc:Agent> + </dc:creator> + <dc:source>http://jimmac.musichall.cz</dc:source> + <dc:subject> + <rdf:Bag> + <rdf:li>address</rdf:li> + <rdf:li>contact</rdf:li> + <rdf:li>book</rdf:li> + </rdf:Bag> + </dc:subject> + <cc:license + rdf:resource="http://creativecommons.org/licenses/publicdomain/" /> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/licenses/publicdomain/"> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Reproduction" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Distribution" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> + </cc:License> + </rdf:RDF> + </metadata> + <g + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer"> + <path + style="opacity:1;color:#000000;fill:#edd400;fill-opacity:1;fill-rule:evenodd;stroke:#c4a000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + d="M 33.096456,4.6520202 L 40.521077,4.6520202 C 41.228184,4.6520202 41.758513,4.8287969 41.93529,5.71268 L 42.819174,12.606972 C 42.907562,13.667632 42.443523,14.021185 41.493349,14.021185 L 32.919679,14.021185 L 33.096456,4.6520202 z " + id="path21630" + sodipodi:nodetypes="ccccccc" /> + <path + sodipodi:nodetypes="ccccccc" + id="path21632" + d="M 34.10295,5.638875 L 40.463507,5.638875 C 40.771656,5.638875 40.940266,5.669037 40.986054,5.960473 L 41.777489,12.344449 C 41.847258,12.775421 41.959897,13.019804 41.637211,13.034341 L 33.963412,13.034341 L 34.10295,5.638875 z " + style="opacity:0.48538011;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000006;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <path + sodipodi:nodetypes="ccccccc" + id="path21634" + d="M 35.596456,12.40202 L 43.021077,12.40202 C 43.728184,12.40202 44.258513,12.578797 44.43529,13.46268 L 45.319174,20.356972 C 45.407562,21.417632 44.943523,21.771185 43.993349,21.771185 L 35.419679,21.771185 L 35.596456,12.40202 z " + style="opacity:1;color:#000000;fill:#9db029;fill-opacity:1;fill-rule:evenodd;stroke:#727e0a;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <path + style="opacity:0.48538011;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.0000006;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + d="M 36.60295,13.388875 L 42.963507,13.388875 C 43.271656,13.388875 43.440266,13.419037 43.486054,13.710473 L 44.277489,20.094449 C 44.347258,20.525421 44.459897,20.769804 44.137211,20.784341 L 36.463412,20.784341 L 36.60295,13.388875 z " + id="path21636" + sodipodi:nodetypes="ccccccc" /> + <path + style="opacity:1;color:#000000;fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:#cc0000;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + d="M 36.06451,20.776498 L 44.50992,20.776498 C 45.314245,20.776498 45.917487,20.995896 46.118569,22.092882 L 47.123975,30.649381 C 47.224515,31.965765 46.696677,32.40456 45.615866,32.40456 L 35.863428,32.40456 L 36.06451,20.776498 z " + id="path21638" + sodipodi:nodetypes="ccccccc" /> + <path + sodipodi:nodetypes="ccccccc" + id="path21640" + d="M 37.209384,21.763574 L 44.444435,21.763574 C 44.79495,21.763574 44.986742,21.801928 45.038825,22.172513 L 45.939072,30.290267 C 46.018433,30.838284 46.146559,31.149038 45.779508,31.167522 L 37.050661,31.167522 L 37.209384,21.763574 z " + style="opacity:0.48538011;color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.00000072;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <g + id="g5022" + transform="matrix(2.165152e-2,0,0,4.307902e-2,43.08625,34.04509)"> + <rect + y="-150.69685" + x="-1559.2523" + height="478.35718" + width="1339.6335" + id="rect4173" + style="opacity:0.40206185;color:black;fill:url(#linearGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <path + sodipodi:nodetypes="cccc" + id="path5058" + d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z " + style="opacity:0.40206185;color:black;fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <path + style="opacity:0.40206185;color:black;fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z " + id="path5018" + sodipodi:nodetypes="cccc" /> + </g> + <path + style="color:#000000;fill:#5b6b94;fill-opacity:1;fill-rule:nonzero;stroke:#364878;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + d="M 6.3643222,5.5185897 C 6.4551049,3.6036003 7.3719758,2.5542814 9.0788784,2.549044 L 38.405776,2.4590577 C 38.652361,2.4583011 38.974317,2.6592071 38.999012,2.9089888 L 42.257491,35.867228 L 40.942189,35.923862 L 41.571429,42.369516 C 41.632441,42.994499 41.390059,43.52882 40.5,43.533035 L 9.7893046,43.678474 C 7.25676,43.690468 4.6538454,41.59976 4.7759337,39.024403 L 6.3643222,5.5185897 z " + id="rect1408" + sodipodi:nodetypes="csssccsssss" /> + <path + id="path2489" + d="M 40.125,34.875 L 10.9375,35 C 9.3809819,35.177868 8.125,36.39612 8.125,38 C 8.125,39.60388 9.3809819,40.822132 10.9375,41 L 40.125,41.125 L 40.125,41.0625 C 38.469378,40.984348 37.125,39.674851 37.125,38 C 37.125,36.325149 38.469378,35.015652 40.125,34.9375 L 40.125,34.875 z " + style="color:#000000;fill:url(#linearGradient2813);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <path + sodipodi:nodetypes="ccccccssc" + id="path2784" + d="M 9.6875,2.8125 C 7.9805897,2.8125 7.050103,3.8215062 6.96875,5.6738658 L 5.3125,37.825772 C 5.22054,40.904199 7.1393732,42.654485 9.125,43.15625 C 4.875,41.525579 5.4375,34.164455 10.75,34.195222 L 41.648286,34.195222 L 38.335786,3.2432432 C 38.310025,3.0025304 37.987878,2.8125 37.742036,2.8125 L 9.6875,2.8125 z " + style="color:#000000;fill:url(#linearGradient2100);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <rect + y="3.968539" + x="9.7886267" + height="29.604792" + width="2" + id="rect2793" + style="opacity:0.48044691;color:#000000;fill:url(#linearGradient2801);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:0.60818715;visibility:visible;display:inline;overflow:visible" + transform="matrix(1.000000,0.000000,-3.582731e-2,0.999358,0.000000,0.000000)" /> + <path + style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2112);stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:20;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + d="M 9.8751008,3.3336831 C 8.1912014,3.3336831 7.5384236,4.0658459 7.4581673,5.887831 L 6.1592633,35.777198 C 7.0925916,34.170451 8.5988591,33.594437 11.011665,33.594437 L 40.963081,33.594437 L 38.137179,3.7573631 C 38.114727,3.5203092 37.793961,3.3336831 37.551434,3.3336831 L 9.8751008,3.3336831 z " + id="path2104" + sodipodi:nodetypes="cccscssc" /> + <path + style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000477%;writing-mode:lr-tb;text-anchor:start;fill:#ad7fa8;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + d="M 21.12553,18.381288 C 21.050283,19.50227 21.269376,20.384155 21.782812,21.026947 C 22.296751,21.661909 23.039741,21.979388 24.011788,21.979387 C 24.97597,21.979388 25.754005,21.65799 26.345892,21.01519 C 26.945589,20.372398 27.282799,19.49443 27.357529,18.381288 C 27.431173,17.283839 27.207372,16.413709 26.686123,15.770905 C 26.165371,15.120279 25.426826,14.794959 24.470482,14.79495 C 23.521952,14.794959 22.743917,15.11636 22.136378,15.759145 C 21.536656,16.401952 21.199707,17.275998 21.12553,18.381288 M 27.29793,21.897075 C 26.787062,22.500679 26.216183,22.947501 25.58529,23.237544 C 24.962734,23.519747 24.247754,23.66085 23.44035,23.660849 C 22.092032,23.66085 21.027197,23.174832 20.245835,22.202797 C 19.472826,21.222925 19.138938,19.949092 19.244172,18.381288 C 19.349395,16.813498 19.858197,15.539665 20.770584,14.559781 C 21.682954,13.579917 22.809375,13.089981 24.149854,13.089969 C 24.957257,13.089981 25.656689,13.238924 26.24815,13.536791 C 26.840107,13.826846 27.347352,14.269749 27.76988,14.865501 L 27.873267,13.325141 L 29.554732,13.325141 L 28.973868,21.979387 C 30.129917,21.806931 31.058551,21.285637 31.759769,20.415508 C 32.469312,19.537544 32.870659,18.404812 32.963808,17.017304 C 33.020082,16.178542 32.947536,15.390722 32.746168,14.653848 C 32.552597,13.916994 32.226018,13.235002 31.766435,12.607873 C 31.020085,11.580979 30.077151,10.79708 28.937625,10.256176 C 27.806428,9.707462 26.551007,9.433097 25.171361,9.433081 C 24.207151,9.433097 23.27347,9.56244 22.370314,9.821111 C 21.467662,10.071974 20.623234,10.448244 19.837027,10.949925 C 18.552629,11.749517 17.517932,12.79994 16.732929,14.101199 C 15.956279,15.394643 15.517185,16.797819 15.415642,18.310738 C 15.331983,19.557142 15.476998,20.725151 15.85069,21.814765 C 16.232213,22.904387 16.822316,23.864664 17.621,24.695594 C 18.389368,25.51085 19.300238,26.130129 20.353615,26.553435 C 21.406448,26.984578 22.54823,27.20015 23.778962,27.200153 C 24.790178,27.20015 25.793384,27.027692 26.788584,26.682781 C 27.791068,26.345701 28.72125,25.859684 29.579139,25.224728 L 30.549801,26.529919 C 29.518874,27.2903 28.409917,27.870384 27.222932,28.270174 C 26.043227,28.677799 24.857618,28.881612 23.666104,28.881616 C 22.215881,28.881612 20.865341,28.622926 19.614483,28.105557 C 18.36308,27.596019 17.268571,26.851316 16.330955,25.871444 C 15.393328,24.89157 14.705054,23.758838 14.266133,22.47324 C 13.827731,21.179813 13.658252,19.792311 13.757696,18.310738 C 13.853452,16.88405 14.211263,15.523986 14.831129,14.230542 C 15.450993,12.937121 16.287663,11.800469 17.34115,10.820582 C 18.419191,9.825045 19.638236,9.0646655 20.998287,8.5394366 C 22.358842,8.0064001 23.779908,7.7398759 25.261489,7.7398585 C 26.923341,7.7398759 28.440813,8.080872 29.813913,8.7628469 C 31.194815,9.444854 32.325282,10.41297 33.205316,11.667193 C 33.741656,12.435425 34.132443,13.270279 34.377679,14.171752 C 34.630708,15.073243 34.724877,16.006082 34.660187,16.970271 C 34.521787,19.031929 33.789414,20.658519 32.463064,21.850041 C 31.136671,23.04157 29.374449,23.66085 27.17639,23.707883 L 27.29793,21.897075" + id="text21625" /> + <path + sodipodi:type="arc" + style="color:#000000;fill:url(#radialGradient278);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block" + id="path12511" + sodipodi:cx="55" + sodipodi:cy="125" + sodipodi:rx="14.375" + sodipodi:ry="14.375" + d="M 69.375 125 A 14.375 14.375 0 1 1 40.625,125 A 14.375 14.375 0 1 1 69.375 125 z" + transform="matrix(0.611127,0.000000,0.000000,0.611127,-24.94992,-67.63529)" + inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/stock_new-16.png" + inkscape:export-xdpi="33.852203" + inkscape:export-ydpi="33.852203" /> + </g> +</svg> diff --git a/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/appointment-new.svg b/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/appointment-new.svg new file mode 100644 index 0000000000..4cb14f82f0 --- /dev/null +++ b/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/appointment-new.svg @@ -0,0 +1,425 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + inkscape:export-ydpi="90.000000" + inkscape:export-xdpi="90.000000" + inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png" + width="48px" + height="48px" + id="svg11300" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/actions" + sodipodi:docname="appointment-new.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs3"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 24 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="48 : 24 : 1" + inkscape:persp3d-origin="24 : 16 : 1" + id="perspective59" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5204"> + <stop + style="stop-color:#c4a000;stop-opacity:1;" + offset="0" + id="stop5206" /> + <stop + style="stop-color:#c4a000;stop-opacity:0;" + offset="1" + id="stop5208" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient5196"> + <stop + style="stop-color:#c4a000;stop-opacity:1;" + offset="0" + id="stop5198" /> + <stop + style="stop-color:#c4a000;stop-opacity:0;" + offset="1" + id="stop5200" /> + </linearGradient> + <linearGradient + id="linearGradient12512"> + <stop + style="stop-color:#ffffff;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop12513" /> + <stop + style="stop-color:#fff520;stop-opacity:0.89108908;" + offset="0.50000000" + id="stop12517" /> + <stop + style="stop-color:#fff300;stop-opacity:0.0000000;" + offset="1.0000000" + id="stop12514" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient12512" + id="radialGradient278" + gradientUnits="userSpaceOnUse" + cx="55.000000" + cy="125.00000" + fx="55.000000" + fy="125.00000" + r="14.375000" /> + <linearGradient + id="linearGradient10653"> + <stop + style="stop-color:#f3f4ff;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop10655" /> + <stop + style="stop-color:#9193af;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop10657" /> + </linearGradient> + <linearGradient + id="linearGradient42174"> + <stop + style="stop-color:#a0a0a0;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop42176" /> + <stop + style="stop-color:#ffffff;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop42178" /> + </linearGradient> + <linearGradient + id="linearGradient2145"> + <stop + style="stop-color:#fffffd;stop-opacity:1.0000000;" + offset="0.0000000" + id="stop2147" /> + <stop + style="stop-color:#cbcbc9;stop-opacity:1.0000000;" + offset="1.0000000" + id="stop2149" /> + </linearGradient> + <linearGradient + id="linearGradient37935"> + <stop + id="stop37937" + offset="0.0000000" + style="stop-color:#9497b3;stop-opacity:1.0000000;" /> + <stop + id="stop37939" + offset="1.0000000" + style="stop-color:#4c4059;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + id="linearGradient2152"> + <stop + id="stop2154" + offset="0.0000000" + style="stop-color:#9aa29a;stop-opacity:1.0000000;" /> + <stop + id="stop2156" + offset="1.0000000" + style="stop-color:#b5beb5;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3816"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop3818" /> + <stop + style="stop-color:#000000;stop-opacity:0;" + offset="1" + id="stop3820" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3816" + id="radialGradient3822" + cx="31.112698" + cy="19.008621" + fx="31.112698" + fy="19.008621" + r="8.6620579" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient2152" + id="linearGradient4307" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(3.123841,0.000000,0.000000,0.969691,-31.88758,-19.59492)" + x1="8.9156475" + y1="37.197018" + x2="9.8855033" + y2="52.090678" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient10653" + id="radialGradient4309" + gradientUnits="userSpaceOnUse" + cx="11.329200" + cy="10.583970" + fx="11.329200" + fy="10.583970" + r="15.532059" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient2145" + id="radialGradient4311" + gradientUnits="userSpaceOnUse" + cx="11.901996" + cy="10.045444" + fx="11.901996" + fy="10.045444" + r="29.292715" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient42174" + id="linearGradient4313" + gradientUnits="userSpaceOnUse" + x1="6.3422160" + y1="7.7893324" + x2="22.218424" + y2="25.884274" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5196" + id="radialGradient5202" + cx="23.375" + cy="10.972863" + fx="23.375" + fy="10.972863" + r="3.3478092" + gradientTransform="matrix(3.630420,1.654030e-15,-1.608743e-15,3.742066,-61.48607,-29.18618)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5204" + id="linearGradient5210" + x1="19.667364" + y1="4.2570662" + x2="20.329933" + y2="5.2845874" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient37935" + id="radialGradient5212" + gradientUnits="userSpaceOnUse" + cx="8.7468252" + cy="6.8283234" + fx="8.7468252" + fy="6.8283234" + r="29.889715" /> + </defs> + <sodipodi:namedview + stroke="#c4a000" + fill="#babdb6" + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="0.25490196" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="11.313708" + inkscape:cx="13.2248" + inkscape:cy="25.106052" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:grid-bbox="true" + inkscape:document-units="px" + inkscape:showpageshadow="false" + inkscape:window-width="833" + inkscape:window-height="772" + inkscape:window-x="305" + inkscape:window-y="76" /> + <metadata + id="metadata4"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:creator> + <cc:Agent> + <dc:title>Jakub Steiner</dc:title> + </cc:Agent> + </dc:creator> + <dc:source>http://jimmac.musichall.cz</dc:source> + <cc:license + rdf:resource="http://creativecommons.org/licenses/publicdomain/" /> + <dc:title>New Appointment</dc:title> + <dc:subject> + <rdf:Bag> + <rdf:li>appointment</rdf:li> + <rdf:li>new</rdf:li> + <rdf:li>meeting</rdf:li> + <rdf:li>rvsp</rdf:li> + </rdf:Bag> + </dc:subject> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/licenses/publicdomain/"> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Reproduction" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Distribution" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> + </cc:License> + </rdf:RDF> + </metadata> + <g + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer"> + <path + d="M 39.774755 19.008621 A 8.6620579 8.6620579 0 1 1 22.45064,19.008621 A 8.6620579 8.6620579 0 1 1 39.774755 19.008621 z" + sodipodi:ry="8.6620579" + sodipodi:rx="8.6620579" + sodipodi:cy="19.008621" + sodipodi:cx="31.112698" + id="path4318" + style="opacity:1;color:#000000;fill:url(#radialGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + sodipodi:type="arc" + transform="matrix(2.563158,0.000000,0.000000,1.219602,-55.98414,14.04144)" /> + <path + sodipodi:nodetypes="cccc" + id="path14341" + d="M 18.587591,1.403729 L 4.226755,18.096665 L 5.4854717,19.339844 L 18.587591,1.403729 z " + style="color:#000000;fill:url(#linearGradient4307);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <path + sodipodi:nodetypes="cccc" + id="path18921" + d="M 18.467176,1.3138035 L 5.6605716,19.072612 L 7.4900985,20.687913 L 18.467176,1.3138035 z " + style="fill:#fefefe;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" /> + <path + transform="matrix(1.431529,0.000000,0.000000,1.431529,0.569459,-1.654618)" + d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z" + sodipodi:ry="14.910714" + sodipodi:rx="14.910714" + sodipodi:cy="16.910715" + sodipodi:cx="16.25" + id="path27786" + style="fill:url(#radialGradient5212);fill-opacity:1;fill-rule:evenodd;stroke:#605773;stroke-width:0.69855404;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:type="arc" /> + <path + transform="matrix(1.163838,0.000000,0.000000,1.163838,4.824801,2.777556)" + d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z" + sodipodi:ry="14.910714" + sodipodi:rx="14.910714" + sodipodi:cy="16.910715" + sodipodi:cx="16.25" + id="path35549" + style="fill:url(#radialGradient4311);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4313);stroke-width:0.71139598;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" + sodipodi:type="arc" /> + <path + sodipodi:type="arc" + style="opacity:1;color:#000000;fill:url(#radialGradient5202);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5210);stroke-width:0.56498736;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path4120" + sodipodi:cx="23.375" + sodipodi:cy="11.875" + sodipodi:rx="8.5" + sodipodi:ry="8.5" + d="M 16.679382,6.6387137 A 8.5,8.5 0 0 1 23.332691,3.3751053 L 23.375,11.875 z" + transform="matrix(1.769951,0.000000,0.000000,1.769951,-17.02424,1.610741)" + sodipodi:start="3.8052902" + sodipodi:end="4.7074114" /> + <path + transform="matrix(2.073295,0.000000,0.000000,2.073295,-7.310224,-13.13682)" + d="M 16.40625 17.28125 A 1.21875 1.21875 0 1 1 13.96875,17.28125 A 1.21875 1.21875 0 1 1 16.40625 17.28125 z" + sodipodi:ry="1.21875" + sodipodi:rx="1.21875" + sodipodi:cy="17.28125" + sodipodi:cx="15.1875" + id="path34778" + style="fill:#f3f3f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.48232403;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;stroke-dasharray:none" + sodipodi:type="arc" /> + <path + id="path35559" + d="M 22.176614,20.718014 L 13.155702,13.140282" + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + id="path35561" + d="M 19.408614,29.776506 L 22.368655,25.283228" + style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + sodipodi:nodetypes="cc" /> + <path + transform="matrix(2.749493,0.000000,0.000000,2.749493,-22.30073,-12.40939)" + d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z" + sodipodi:ry="0.61871845" + sodipodi:rx="0.61871845" + sodipodi:cy="7.6932044" + sodipodi:cx="16.705399" + id="path35563" + style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" + sodipodi:type="arc" /> + <path + transform="matrix(2.749493,0.000000,0.000000,2.749493,-22.30073,14.80922)" + d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z" + sodipodi:ry="0.61871845" + sodipodi:rx="0.61871845" + sodipodi:cy="7.6932044" + sodipodi:cx="16.705399" + id="path35565" + style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" + sodipodi:type="arc" /> + <path + transform="matrix(2.749493,0.000000,0.000000,2.749493,-35.91004,1.199890)" + d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z" + sodipodi:ry="0.61871845" + sodipodi:rx="0.61871845" + sodipodi:cy="7.6932044" + sodipodi:cx="16.705399" + id="path35567" + style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" + sodipodi:type="arc" /> + <path + transform="matrix(2.749493,0.000000,0.000000,2.749493,-8.691448,1.199890)" + d="M 17.324117 7.6932044 A 0.61871845 0.61871845 0 1 1 16.08668,7.6932044 A 0.61871845 0.61871845 0 1 1 17.324117 7.6932044 z" + sodipodi:ry="0.61871845" + sodipodi:rx="0.61871845" + sodipodi:cy="7.6932044" + sodipodi:cx="16.705399" + id="path35569" + style="fill:#b6b9b1;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.36871839;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" + sodipodi:type="arc" /> + <path + sodipodi:type="arc" + style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient4309);stroke-width:0.73656511;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" + id="path10651" + sodipodi:cx="16.25" + sodipodi:cy="16.910715" + sodipodi:rx="14.910714" + sodipodi:ry="14.910714" + d="M 31.160714 16.910715 A 14.910714 14.910714 0 1 1 1.3392859,16.910715 A 14.910714 14.910714 0 1 1 31.160714 16.910715 z" + transform="matrix(1.357654,0.000000,0.000000,1.357654,1.769896,-0.493735)" /> + <path + sodipodi:type="arc" + style="color:#000000;fill:url(#radialGradient278);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.25000024;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block" + id="path12511" + sodipodi:cx="55" + sodipodi:cy="125" + sodipodi:rx="14.375" + sodipodi:ry="14.375" + d="M 69.375 125 A 14.375 14.375 0 1 1 40.625,125 A 14.375 14.375 0 1 1 69.375 125 z" + transform="matrix(0.611127,0.000000,0.000000,0.611127,5.544052,-66.92818)" + inkscape:export-filename="/home/jimmac/ximian_art/icons/nautilus/suse93/stock_new-16.png" + inkscape:export-xdpi="33.852203" + inkscape:export-ydpi="33.852203" /> + </g> +</svg> diff --git a/tests/auto/gui/image/qicon/image.png b/tests/auto/gui/image/qicon/image.png Binary files differnew file mode 100644 index 0000000000..8d703640c1 --- /dev/null +++ b/tests/auto/gui/image/qicon/image.png diff --git a/tests/auto/gui/image/qicon/qicon.pro b/tests/auto/gui/image/qicon/qicon.pro new file mode 100644 index 0000000000..5ce4fd4c2f --- /dev/null +++ b/tests/auto/gui/image/qicon/qicon.pro @@ -0,0 +1,32 @@ +load(qttest_p4) + +QT += widgets +SOURCES += tst_qicon.cpp +RESOURCES = tst_qicon.qrc + +wince* { + QT += xml svg + addFiles.files += $$_PRO_FILE_PWD_/*.png + addFiles.files += $$_PRO_FILE_PWD_/*.svg + addFiles.files += $$_PRO_FILE_PWD_/*.svgz + addFiles.files += $$_PRO_FILE_PWD_/tst_qicon.cpp + addFiles.path = . + DEPLOYMENT += addFiles + + DEPLOYMENT_PLUGIN += qsvg + DEFINES += SRCDIR=\\\".\\\" +} else:symbian { + QT += xml svg + addFiles.files = *.png tst_qicon.cpp *.svg *.svgz + addFiles.path = . + DEPLOYMENT += addFiles + qt_not_deployed { + plugins.files = qsvgicon.dll + plugins.path = iconengines + DEPLOYMENT += plugins + } +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/gui/image/qicon/rect.png b/tests/auto/gui/image/qicon/rect.png Binary files differnew file mode 100644 index 0000000000..b5d3ecbddf --- /dev/null +++ b/tests/auto/gui/image/qicon/rect.png diff --git a/tests/auto/gui/image/qicon/rect.svg b/tests/auto/gui/image/qicon/rect.svg new file mode 100644 index 0000000000..8eb24727be --- /dev/null +++ b/tests/auto/gui/image/qicon/rect.svg @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + width="40px" + height="5px" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docname="test.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + inkscape:window-height="1005" + inkscape:window-width="1280" + inkscape:pageshadow="2" + inkscape:pageopacity="0.0" + guidetolerance="10.0" + gridtolerance="10.0" + objecttolerance="10.0" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" + showgrid="false" + inkscape:zoom="13.6" + inkscape:cx="20" + inkscape:cy="2.5" + inkscape:window-x="-4" + inkscape:window-y="-4" + inkscape:current-layer="svg2" /> + <defs + id="defs4"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 2.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="40 : 2.5 : 1" + inkscape:persp3d-origin="20 : 1.6666667 : 1" + id="perspective9" /> + </defs> + <g + id="layer1"> + <rect + width="40px" + height="5px" + x="0px" + y="0px" + id="rect2393" + style="fill:#ff0000" /> + </g> + <rect + style="fill:#000000" + id="rect2382" + width="2" + height="2" + x="19" + y="1.5" /> +</svg> diff --git a/tests/auto/gui/image/qicon/trash.svg b/tests/auto/gui/image/qicon/trash.svg new file mode 100644 index 0000000000..c44e4c75a2 --- /dev/null +++ b/tests/auto/gui/image/qicon/trash.svg @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 10, SVG Export Plug-In . SVG Version: 3.0.0 Build 76) --><svg enable-background="new 0 0 347 348" height="348" i:pageBounds="0 792 612 0" i:rulerOrigin="0 0" i:viewOrigin="131 567" overflow="visible" space="preserve" viewBox="-20 -20 387 388" width="347" xmlns="http://www.w3.org/2000/svg" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" xmlns:graph="http://ns.adobe.com/Graphs/1.0/" xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/" xmlns:x="http://ns.adobe.com/Extensibility/1.0/" xmlns:xlink="http://www.w3.org/1999/xlink"> +<metadata> +<rdf:RDF xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> +<cc:Work rdf:about=""> +<dc:title>Keep Tidy Inside</dc:title> +<dc:description></dc:description> +<dc:subject> +<rdf:Bag> +<rdf:li></rdf:li> +<rdf:li>symbol</rdf:li> +<rdf:li>bin</rdf:li> +<rdf:li>signs_and_symbols</rdf:li> +<rdf:li>clean</rdf:li> +<rdf:li>rubish</rdf:li> +<rdf:li>trash</rdf:li> +<rdf:li>inside</rdf:li> +<rdf:li>garbage</rdf:li> +<rdf:li>sign</rdf:li> +</rdf:Bag> +</dc:subject> +<dc:publisher> +<cc:Agent rdf:about="http://www.openclipart.org"> +<dc:title>Martin Owens</dc:title> +</cc:Agent> +</dc:publisher> +<dc:creator> +<cc:Agent> +<dc:title>Martin Owens</dc:title> +</cc:Agent> +</dc:creator> +<dc:rights> +<cc:Agent> +<dc:title>Martin Owens</dc:title> +</cc:Agent> +</dc:rights> +<dc:date></dc:date> +<dc:format>image/svg+xml</dc:format> +<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> +<cc:license rdf:resource="http://web.resource.org/cc/PublicDomain"/> +<dc:language>en</dc:language> +</cc:Work> +<cc:License rdf:about="http://web.resource.org/cc/PublicDomain"> +<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/> +<cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/> +<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/> +</cc:License> +</rdf:RDF> +</metadata> +<g i:dimmedPercent="50" i:knockout="Off" i:layer="yes" i:rgbTrio="#4F008000FFFF" id="Layer_1"> +<path d="M347,174c0,96.098-77.679,174-173.5,174C77.679,348,0,270.098,0,174 C0,77.902,77.679,0,173.5,0C269.321,0,347,77.902,347,174z" fill="#10A040" i:knockout="Off"/> +<path d="M238,53c0,13.807-11.864,25-26.5,25S185,66.807,185,53s11.864-25,26.5-25 S238,39.193,238,53z" fill="#FFFFFF" i:knockout="Off"/> +<path d="M66,175c1.055,6.355,19.333,126.417,19.333,126.417h68.333 c0,0,14.105-122.524,14.333-126.417c6.224-0.622,6.667-13-2-13c-12.164,0-89.205-0.059-98,0S61.167,174.487,66,175z" fill="#FFFFFF" i:knockout="Off"/> +<path d="M78,141c17.292-5.325,24.179-23.532,27-31c14.513,6.596,40.333,12.265,59,8 c3.683,19.419-28.043,19.31-23,37C132.577,145.705,89.404,167.292,78,141z" fill="#FFFFFF" i:knockout="Off"/> +<path d="M103,82l139-1c-0.6,3.421,33.633,57.497,29,67c-4.089,0.418-67,5-67,5 c6.109-9.379-13-43-13-43L103,82z" fill="#FFFFFF" i:knockout="Off"/> +<path d="M270,156l-66-3c0,0-23.565,143.355-24,145s1.855,2.536,3,1s51-82,51-82 s19.754,80.701,20,82s3.721,1.209,4,0S270,156,270,156z" fill="#FFFFFF" i:knockout="Off"/> +</g> +</svg> diff --git a/tests/auto/gui/image/qicon/tst_qicon.cpp b/tests/auto/gui/image/qicon/tst_qicon.cpp new file mode 100644 index 0000000000..4c430f9435 --- /dev/null +++ b/tests/auto/gui/image/qicon/tst_qicon.cpp @@ -0,0 +1,781 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QImageReader> +#include <qicon.h> + +#if defined(Q_OS_SYMBIAN) +#define SRCDIR "." +#endif +#include <qiconengine.h> + +Q_DECLARE_METATYPE(QSize) + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QIcon : public QObject +{ + Q_OBJECT +public: + tst_QIcon(); + +private slots: + void init(); + void cleanup(); + + void actualSize_data(); // test with 1 pixmap + void actualSize(); + void actualSize2_data(); // test with 2 pixmaps with different aspect ratio + void actualSize2(); + void svgActualSize(); + void isNull(); + void swap(); + void bestMatch(); + void cacheKey(); + void detach(); + void svg(); + void addFile(); + void availableSizes(); + void name(); + void streamAvailableSizes_data(); + void streamAvailableSizes(); + void fromTheme(); + + void task184901_badCache(); + void task223279_inconsistentAddFile(); + void task239461_custom_iconengine_crash(); + +private: + bool haveImageFormat(QByteArray const&); + + QString oldCurrentDir; + + const static QIcon staticIcon; +}; + +// Creating an icon statically should not cause a crash. +// But we do not officially support this. See QTBUG-8666 +const QIcon tst_QIcon::staticIcon = QIcon::fromTheme("edit-find"); + +void tst_QIcon::init() +{ + QString srcdir(QLatin1String(SRCDIR)); + if (!srcdir.isEmpty()) { + oldCurrentDir = QDir::current().absolutePath(); + QDir::setCurrent(srcdir); + } +} + +void tst_QIcon::cleanup() +{ + if (!oldCurrentDir.isEmpty()) { + QDir::setCurrent(oldCurrentDir); + } +} + +bool tst_QIcon::haveImageFormat(QByteArray const& desiredFormat) +{ + return QImageReader::supportedImageFormats().contains(desiredFormat); +} + +tst_QIcon::tst_QIcon() +{ +} + +void tst_QIcon::actualSize_data() +{ + QTest::addColumn<QString>("source"); + QTest::addColumn<QSize>("argument"); + QTest::addColumn<QSize>("result"); + + // square image + QTest::newRow("resource0") << ":/image.png" << QSize(128, 128) << QSize(128, 128); + QTest::newRow("resource1") << ":/image.png" << QSize( 64, 64) << QSize( 64, 64); + QTest::newRow("resource2") << ":/image.png" << QSize( 32, 64) << QSize( 32, 32); + QTest::newRow("resource3") << ":/image.png" << QSize( 16, 64) << QSize( 16, 16); + QTest::newRow("resource4") << ":/image.png" << QSize( 16, 128) << QSize( 16, 16); + QTest::newRow("resource5") << ":/image.png" << QSize( 128, 16) << QSize( 16, 16); + QTest::newRow("resource6") << ":/image.png" << QSize( 150, 150) << QSize( 128, 128); + // rect image + QTest::newRow("resource7") << ":/rect.png" << QSize( 20, 40) << QSize( 20, 40); + QTest::newRow("resource8") << ":/rect.png" << QSize( 10, 20) << QSize( 10, 20); + QTest::newRow("resource9") << ":/rect.png" << QSize( 15, 50) << QSize( 15, 30); + QTest::newRow("resource10") << ":/rect.png" << QSize( 25, 50) << QSize( 20, 40); + + const QString prefix = QLatin1String(SRCDIR) + QLatin1String("/"); + QTest::newRow("external0") << prefix + "image.png" << QSize(128, 128) << QSize(128, 128); + QTest::newRow("external1") << prefix + "image.png" << QSize( 64, 64) << QSize( 64, 64); + QTest::newRow("external2") << prefix + "image.png" << QSize( 32, 64) << QSize( 32, 32); + QTest::newRow("external3") << prefix + "image.png" << QSize( 16, 64) << QSize( 16, 16); + QTest::newRow("external4") << prefix + "image.png" << QSize( 16, 128) << QSize( 16, 16); + QTest::newRow("external5") << prefix + "image.png" << QSize( 128, 16) << QSize( 16, 16); + QTest::newRow("external6") << prefix + "image.png" << QSize( 150, 150) << QSize( 128, 128); + // rect image + QTest::newRow("external7") << ":/rect.png" << QSize( 20, 40) << QSize( 20, 40); + QTest::newRow("external8") << ":/rect.png" << QSize( 10, 20) << QSize( 10, 20); + QTest::newRow("external9") << ":/rect.png" << QSize( 15, 50) << QSize( 15, 30); + QTest::newRow("external10") << ":/rect.png" << QSize( 25, 50) << QSize( 20, 40); +} + +void tst_QIcon::actualSize() +{ + QFETCH(QString, source); + QFETCH(QSize, argument); + QFETCH(QSize, result); + + { + QPixmap pixmap(source); + QIcon icon(pixmap); + QCOMPARE(icon.actualSize(argument), result); + QCOMPARE(icon.pixmap(argument).size(), result); + } + + { + QIcon icon(source); + QCOMPARE(icon.actualSize(argument), result); + QCOMPARE(icon.pixmap(argument).size(), result); + } +} + +void tst_QIcon::actualSize2_data() +{ + QTest::addColumn<QSize>("argument"); + QTest::addColumn<QSize>("result"); + + // two images - 128x128 and 20x40. Let the games begin + QTest::newRow("trivial1") << QSize( 128, 128) << QSize( 128, 128); + QTest::newRow("trivial2") << QSize( 20, 40) << QSize( 20, 40); + + // QIcon chooses the one with the smallest area to choose the pixmap + QTest::newRow("best1") << QSize( 100, 100) << QSize( 100, 100); + QTest::newRow("best2") << QSize( 20, 20) << QSize( 10, 20); + QTest::newRow("best3") << QSize( 15, 30) << QSize( 15, 30); + QTest::newRow("best4") << QSize( 5, 5) << QSize( 2, 5); + QTest::newRow("best5") << QSize( 10, 15) << QSize( 7, 15); +} + +void tst_QIcon::actualSize2() +{ + QIcon icon; + const QString prefix = QLatin1String(SRCDIR) + QLatin1String("/"); + + icon.addPixmap(QPixmap(prefix + "image.png")); + icon.addPixmap(QPixmap(prefix + "rect.png")); + + QFETCH(QSize, argument); + QFETCH(QSize, result); + + QCOMPARE(icon.actualSize(argument), result); + QCOMPARE(icon.pixmap(argument).size(), result); +} + +void tst_QIcon::svgActualSize() +{ + if (!haveImageFormat("svg")) { + QSKIP("SVG support is not available", SkipAll); + } + + const QString prefix = QLatin1String(SRCDIR) + QLatin1String("/"); + QIcon icon(prefix + "rect.svg"); + QCOMPARE(icon.actualSize(QSize(16, 16)), QSize(16, 2)); + QCOMPARE(icon.pixmap(QSize(16, 16)).size(), QSize(16, 2)); + + QPixmap p(16, 16); + p.fill(Qt::cyan); + icon.addPixmap(p); + + QCOMPARE(icon.actualSize(QSize(16, 16)), QSize(16, 16)); + QCOMPARE(icon.pixmap(QSize(16, 16)).size(), QSize(16, 16)); + + QCOMPARE(icon.actualSize(QSize(16, 14)), QSize(16, 2)); + QCOMPARE(icon.pixmap(QSize(16, 14)).size(), QSize(16, 2)); +} + +void tst_QIcon::isNull() { + // test default constructor + QIcon defaultConstructor; + QVERIFY(defaultConstructor.isNull()); + + // test copy constructor + QVERIFY(QIcon(defaultConstructor).isNull()); + + // test pixmap constructor + QPixmap nullPixmap; + QVERIFY(QIcon(nullPixmap).isNull()); + + // test string constructor with empty string + QIcon iconEmptyString = QIcon(QString()); + QVERIFY(iconEmptyString.isNull()); + QVERIFY(!iconEmptyString.actualSize(QSize(32, 32)).isValid());; + + // test string constructor with non-existing file + QIcon iconNoFile = QIcon("imagedoesnotexist"); + QVERIFY(!iconNoFile.isNull()); + QVERIFY(!iconNoFile.actualSize(QSize(32, 32)).isValid()); + + // test string constructor with non-existing file with suffix + QIcon iconNoFileSuffix = QIcon("imagedoesnotexist.png"); + QVERIFY(!iconNoFileSuffix.isNull()); + QVERIFY(!iconNoFileSuffix.actualSize(QSize(32, 32)).isValid()); + + const QString prefix = QLatin1String(SRCDIR) + QLatin1String("/"); + // test string constructor with existing file but unsupported format + QIcon iconUnsupportedFormat = QIcon(prefix + "tst_qicon.cpp"); + QVERIFY(!iconUnsupportedFormat.isNull()); + QVERIFY(!iconUnsupportedFormat.actualSize(QSize(32, 32)).isValid()); + + // test string constructor with existing file and supported format + QIcon iconSupportedFormat = QIcon(prefix + "image.png"); + QVERIFY(!iconSupportedFormat.isNull()); + QVERIFY(iconSupportedFormat.actualSize(QSize(32, 32)).isValid()); +} + +void tst_QIcon::swap() +{ + QPixmap p1(1, 1), p2(2, 2); + p1.fill(Qt::black); + p2.fill(Qt::black); + + QIcon i1(p1), i2(p2); + const qint64 i1k = i1.cacheKey(); + const qint64 i2k = i2.cacheKey(); + QVERIFY(i1k != i2k); + i1.swap(i2); + QCOMPARE(i1.cacheKey(), i2k); + QCOMPARE(i2.cacheKey(), i1k); +} + +void tst_QIcon::bestMatch() +{ + QPixmap p1(1, 1); + QPixmap p2(2, 2); + QPixmap p3(3, 3); + QPixmap p4(4, 4); + QPixmap p5(5, 5); + QPixmap p6(6, 6); + QPixmap p7(7, 7); + QPixmap p8(8, 8); + + p1.fill(Qt::black); + p2.fill(Qt::black); + p3.fill(Qt::black); + p4.fill(Qt::black); + p5.fill(Qt::black); + p6.fill(Qt::black); + p7.fill(Qt::black); + p8.fill(Qt::black); + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 2; ++j) { + QIcon::State state = (j == 0) ? QIcon::On : QIcon::Off; + QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off + : QIcon::On; + QIcon::Mode mode; + QIcon::Mode oppositeMode; + + QIcon icon; + + switch (i) { + case 0: + default: + mode = QIcon::Normal; + oppositeMode = QIcon::Active; + break; + case 1: + mode = QIcon::Active; + oppositeMode = QIcon::Normal; + break; + case 2: + mode = QIcon::Disabled; + oppositeMode = QIcon::Selected; + break; + case 3: + mode = QIcon::Selected; + oppositeMode = QIcon::Disabled; + } + + /* + The test mirrors the code in + QPixmapIconEngine::bestMatch(), to make sure that + nobody breaks QPixmapIconEngine by mistake. Before + you change this test or the code that it tests, + please talk to the maintainer if possible. + */ + if (mode == QIcon::Disabled || mode == QIcon::Selected) { + icon.addPixmap(p1, oppositeMode, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p1.size()); + + icon.addPixmap(p2, oppositeMode, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p2.size()); + + icon.addPixmap(p3, QIcon::Active, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p3.size()); + + icon.addPixmap(p4, QIcon::Normal, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p4.size()); + + icon.addPixmap(p5, mode, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p5.size()); + + icon.addPixmap(p6, QIcon::Active, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p6.size()); + + icon.addPixmap(p7, QIcon::Normal, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p7.size()); + + icon.addPixmap(p8, mode, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p8.size()); + } else { + icon.addPixmap(p1, QIcon::Selected, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p1.size()); + + icon.addPixmap(p2, QIcon::Disabled, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p2.size()); + + icon.addPixmap(p3, QIcon::Selected, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p3.size()); + + icon.addPixmap(p4, QIcon::Disabled, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p4.size()); + + icon.addPixmap(p5, oppositeMode, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p5.size()); + + icon.addPixmap(p6, mode, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p6.size()); + + icon.addPixmap(p7, oppositeMode, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p7.size()); + + icon.addPixmap(p8, mode, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p8.size()); + } + } + } +} + +void tst_QIcon::cacheKey() +{ + QIcon icon1("image.png"); + qint64 icon1_key = icon1.cacheKey(); + QIcon icon2 = icon1; + + QVERIFY(icon2.cacheKey() == icon1.cacheKey()); + icon2.detach(); + QVERIFY(icon2.cacheKey() != icon1.cacheKey()); + QVERIFY(icon1.cacheKey() == icon1_key); +} + +void tst_QIcon::detach() +{ + QImage img(32, 32, QImage::Format_ARGB32_Premultiplied); + img.fill(0xffff0000); + QIcon icon1(QPixmap::fromImage(img)); + QIcon icon2 = icon1; + icon2.addFile("image.png", QSize(64, 64)); + + QImage img1 = icon1.pixmap(64, 64).toImage(); + QImage img2 = icon2.pixmap(64, 64).toImage(); + QVERIFY(img1 != img2); + + img1 = icon1.pixmap(32, 32).toImage(); + img2 = icon2.pixmap(32, 32).toImage(); + QVERIFY(img1 == img2); +} + +void tst_QIcon::svg() +{ + if (!haveImageFormat("svg")) { + QSKIP("SVG support is not available", SkipAll); + } + QIcon icon1("heart.svg"); + + QVERIFY(!icon1.pixmap(32).isNull()); + QImage img1 = icon1.pixmap(32).toImage(); + QVERIFY(!icon1.pixmap(32, QIcon::Disabled).isNull()); + QImage img2 = icon1.pixmap(32, QIcon::Disabled).toImage(); + + icon1.addFile("trash.svg", QSize(), QIcon::Disabled); + QVERIFY(!icon1.pixmap(32, QIcon::Disabled).isNull()); + QImage img3 = icon1.pixmap(32, QIcon::Disabled).toImage(); + QVERIFY(img3 != img2); + QVERIFY(img3 != img1); + + QPixmap pm("image.png"); + icon1.addPixmap(pm, QIcon::Normal, QIcon::On); + QVERIFY(!icon1.pixmap(128, QIcon::Normal, QIcon::On).isNull()); + QImage img4 = icon1.pixmap(128, QIcon::Normal, QIcon::On).toImage(); + QVERIFY(img4 != img3); + QVERIFY(img4 != img2); + QVERIFY(img4 != img1); + + QIcon icon2; + icon2.addFile("heart.svg"); + QVERIFY(icon2.pixmap(57).toImage() == icon1.pixmap(57).toImage()); + + QIcon icon3("trash.svg"); + icon3.addFile("heart.svg"); + QVERIFY(icon3.pixmap(57).toImage() == icon1.pixmap(57).toImage()); + + QIcon icon4("heart.svg"); + icon4.addFile("image.png", QSize(), QIcon::Active); + QVERIFY(!icon4.pixmap(32).isNull()); + QVERIFY(!icon4.pixmap(32, QIcon::Active).isNull()); + QVERIFY(icon4.pixmap(32).toImage() == img1); + QIcon pmIcon(pm); + QVERIFY(icon4.pixmap(pm.size(), QIcon::Active).toImage() == pmIcon.pixmap(pm.size(), QIcon::Active).toImage()); + +#ifndef QT_NO_COMPRESS + QIcon icon5("heart.svgz"); + QVERIFY(!icon5.pixmap(32).isNull()); +#endif +} + +void tst_QIcon::addFile() +{ + QIcon icon; + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png"), QSize(), QIcon::Selected); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-32.png"), QSize(), QIcon::Selected); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-128.png"), QSize(), QIcon::Selected); + +#ifndef Q_OS_WINCE + QVERIFY(icon.pixmap(16, QIcon::Normal).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")).toImage()); + QVERIFY(icon.pixmap(32, QIcon::Normal).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-32.png")).toImage()); + QVERIFY(icon.pixmap(128, QIcon::Normal).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")).toImage()); + QVERIFY(icon.pixmap(16, QIcon::Selected).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png")).toImage()); + QVERIFY(icon.pixmap(32, QIcon::Selected).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-32.png")).toImage()); + QVERIFY(icon.pixmap(128, QIcon::Selected).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-128.png")).toImage()); +#else + // WinCE only includes the 16x16 images for size reasons + QVERIFY(icon.pixmap(16, QIcon::Normal).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")).toImage()); + QVERIFY(icon.pixmap(16, QIcon::Selected).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png")).toImage()); +#endif +} + +static bool sizeLess(const QSize &a, const QSize &b) +{ + return a.width() < b.width(); +} + +void tst_QIcon::availableSizes() +{ + { + QIcon icon; + icon.addFile("image.png", QSize(32,32)); + icon.addFile("image.png", QSize(64,64)); + icon.addFile("image.png", QSize(128,128)); + icon.addFile("image.png", QSize(256,256), QIcon::Disabled); + icon.addFile("image.png", QSize(16,16), QIcon::Normal, QIcon::On); + + QList<QSize> availableSizes = icon.availableSizes(); + QCOMPARE(availableSizes.size(), 3); + qSort(availableSizes.begin(), availableSizes.end(), sizeLess); + QCOMPARE(availableSizes.at(0), QSize(32,32)); + QCOMPARE(availableSizes.at(1), QSize(64,64)); + QCOMPARE(availableSizes.at(2), QSize(128,128)); + + availableSizes = icon.availableSizes(QIcon::Disabled); + QCOMPARE(availableSizes.size(), 1); + QCOMPARE(availableSizes.at(0), QSize(256,256)); + + availableSizes = icon.availableSizes(QIcon::Normal, QIcon::On); + QCOMPARE(availableSizes.size(), 1); + QCOMPARE(availableSizes.at(0), QSize(16,16)); + } + + if (haveImageFormat("svg")) { + // checks that there are no availableSizes for scalable images. + QIcon icon("heart.svg"); + QList<QSize> availableSizes = icon.availableSizes(); + QVERIFY(availableSizes.isEmpty()); + } + + if (haveImageFormat("svg")) { + // even if an a scalable image contain added pixmaps, + // availableSizes still should be empty. + QIcon icon("heart.svg"); + icon.addFile("image.png", QSize(32,32)); + QList<QSize> availableSizes = icon.availableSizes(); + QVERIFY(availableSizes.isEmpty()); + } + + { + // we try to load an icon from resources + QIcon icon(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + QList<QSize> availableSizes = icon.availableSizes(); + QCOMPARE(availableSizes.size(), 1); + QCOMPARE(availableSizes.at(0), QSize(16, 16)); + } + + { + // load an icon from binary data. + QPixmap pix; + QFile file(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + QVERIFY(file.open(QIODevice::ReadOnly)); + uchar *data = file.map(0, file.size()); + QVERIFY(data != 0); + pix.loadFromData(data, file.size()); + QIcon icon(pix); + + QList<QSize> availableSizes = icon.availableSizes(); + QCOMPARE(availableSizes.size(), 1); + QCOMPARE(availableSizes.at(0), QSize(16,16)); + } + + { + // there shouldn't be available sizes for invalid images! + QVERIFY(QIcon(QLatin1String("")).availableSizes().isEmpty()); + QVERIFY(QIcon(QLatin1String("non-existing.png")).availableSizes().isEmpty()); + } +} + +void tst_QIcon::name() +{ + { + // No name if icon does not come from a theme + QIcon icon(":/image.png"); + QString name = icon.name(); + QVERIFY(name.isEmpty()); + } + + { + // Getting the name of an icon coming from a theme should work + QString searchPath = QLatin1String(":/icons"); + QIcon::setThemeSearchPaths(QStringList() << searchPath); + QString themeName("testtheme"); + QIcon::setThemeName(themeName); + + QIcon icon = QIcon::fromTheme("appointment-new"); + QString name = icon.name(); + QCOMPARE(name, QLatin1String("appointment-new")); + } +} + +void tst_QIcon::streamAvailableSizes_data() +{ + QTest::addColumn<QIcon>("icon"); + + QIcon icon; + icon.addFile(":/image.png", QSize(32,32)); + QTest::newRow( "32x32" ) << icon; + icon.addFile(":/image.png", QSize(64,64)); + QTest::newRow( "64x64" ) << icon; + icon.addFile(":/image.png", QSize(128,128)); + QTest::newRow( "128x128" ) << icon; + icon.addFile(":/image.png", QSize(256,256)); + QTest::newRow( "256x256" ) << icon; +} + +void tst_QIcon::streamAvailableSizes() +{ + QFETCH(QIcon, icon); + + QByteArray ba; + // write to QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + QDataStream stream(&buffer); + stream << icon; + } + + // read from QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadOnly); + QDataStream stream(&buffer); + QIcon i; + stream >> i; + QCOMPARE(i.isNull(), icon.isNull()); + QCOMPARE(i.availableSizes(), icon.availableSizes()); + } +} + + +static inline bool operator<(const QSize &lhs, const QSize &rhs) +{ + if (lhs.width() < rhs.width()) + return true; + else if (lhs.width() == lhs.width()) + return lhs.height() < lhs.height(); + return false; +} + +void tst_QIcon::task184901_badCache() +{ + QPixmap pm("image.png"); + QIcon icon(pm); + + //the disabled icon must have an effect (grayed) + QVERIFY(icon.pixmap(32, QIcon::Normal).toImage() != icon.pixmap(32, QIcon::Disabled).toImage()); + + icon.addPixmap(pm, QIcon::Disabled); + //the disabled icon must now be the same as the normal one. + QVERIFY( icon.pixmap(32, QIcon::Normal).toImage() == icon.pixmap(32, QIcon::Disabled).toImage() ); +} + +void tst_QIcon::fromTheme() +{ + QString searchPath = QLatin1String(":/icons"); + QIcon::setThemeSearchPaths(QStringList() << searchPath); + QVERIFY(QIcon::themeSearchPaths().size() == 1); + QCOMPARE(searchPath, QIcon::themeSearchPaths()[0]); + + QString themeName("testtheme"); + QIcon::setThemeName(themeName); + QCOMPARE(QIcon::themeName(), themeName); + + // Test normal icon + QIcon appointmentIcon = QIcon::fromTheme("appointment-new"); + QVERIFY(!appointmentIcon.isNull()); + QVERIFY(!appointmentIcon.availableSizes(QIcon::Normal, QIcon::Off).isEmpty()); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(16, 16))); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(32, 32))); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(22, 22))); + + // Test icon from parent theme + QIcon abIcon = QIcon::fromTheme("address-book-new"); + QVERIFY(!abIcon.isNull()); + QVERIFY(QIcon::hasThemeIcon("address-book-new")); + QVERIFY(!abIcon.availableSizes().isEmpty()); + + // Test non existing icon + QIcon noIcon = QIcon::fromTheme("broken-icon"); + QVERIFY(noIcon.isNull()); + QVERIFY(!QIcon::hasThemeIcon("broken-icon")); + + // Test non existing icon with fallback + noIcon = QIcon::fromTheme("broken-icon", abIcon); + QVERIFY(noIcon.cacheKey() == abIcon.cacheKey()); + + // Test svg-only icon + noIcon = QIcon::fromTheme("svg-icon", abIcon); + QVERIFY(!noIcon.availableSizes().isEmpty()); + + QByteArray ba; + // write to QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + QDataStream stream(&buffer); + stream << abIcon; + } + + // read from QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadOnly); + QDataStream stream(&buffer); + QIcon i; + stream >> i; + QCOMPARE(i.isNull(), abIcon.isNull()); + QCOMPARE(i.availableSizes(), abIcon.availableSizes()); + } + + // Make sure setting the theme name clears the state + QIcon::setThemeName(""); + abIcon = QIcon::fromTheme("address-book-new"); + QVERIFY(abIcon.isNull()); +} + + +void tst_QIcon::task223279_inconsistentAddFile() +{ + QIcon icon1; + icon1.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + icon1.addFile(QLatin1String("IconThatDoesntExist"), QSize(32, 32)); + QPixmap pm1 = icon1.pixmap(32, 32); + + QIcon icon2; + icon2.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + icon2.addFile(QLatin1String("IconThatDoesntExist")); + QPixmap pm2 = icon1.pixmap(32, 32); + + QCOMPARE(pm1.isNull(), false); + QCOMPARE(pm1.size(), QSize(16,16)); + QCOMPARE(pm1.isNull(), pm2.isNull()); + QCOMPARE(pm1.size(), pm2.size()); +} + + +// During detach, v2 engines are cloned, while v1 engines are only +// passed on, so v1 engines need to be referenced counted. This test +// verifies that the engine is destroyed once and only once. + +class IconEngine : public QIconEngine +{ +public: + ~IconEngine() { destructorCalled++; } + virtual void paint(QPainter *, const QRect &, QIcon::Mode, QIcon::State) { } + static int destructorCalled; +}; +int IconEngine::destructorCalled = 0; + +void tst_QIcon::task239461_custom_iconengine_crash() +{ + QIconEngine *engine = new IconEngine(); + { + QIcon icon(engine); + QIcon icon2 = icon; + + QPixmap pixmap(32, 32); + icon.addPixmap(pixmap); + } + QCOMPARE(IconEngine::destructorCalled, 1); +} + + +QTEST_MAIN(tst_QIcon) +#include "tst_qicon.moc" diff --git a/tests/auto/gui/image/qicon/tst_qicon.qrc b/tests/auto/gui/image/qicon/tst_qicon.qrc new file mode 100644 index 0000000000..7925a33c84 --- /dev/null +++ b/tests/auto/gui/image/qicon/tst_qicon.qrc @@ -0,0 +1,20 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/"> +<file>image.png</file> +<file>rect.png</file> +<file>./icons/testtheme/16x16/actions/appointment-new.png</file> +<file>./icons/testtheme/22x22/actions/appointment-new.png</file> +<file>./icons/testtheme/32x32/actions/appointment-new.png</file> +<file>./icons/testtheme/index.theme</file> +<file>./icons/testtheme/scalable/actions/svg-only.svg</file> +<file>./icons/themeparent/16x16/actions/address-book-new.png</file> +<file>./icons/themeparent/16x16/actions/appointment-new.png</file> +<file>./icons/themeparent/22x22/actions/address-book-new.png</file> +<file>./icons/themeparent/22x22/actions/appointment-new.png</file> +<file>./icons/themeparent/32x32/actions/address-book-new.png</file> +<file>./icons/themeparent/32x32/actions/appointment-new.png</file> +<file>./icons/themeparent/index.theme</file> +<file>./icons/themeparent/scalable/actions/address-book-new.svg</file> +<file>./icons/themeparent/scalable/actions/appointment-new.svg</file> +</qresource> +</RCC> diff --git a/tests/auto/gui/image/qimage/.gitignore b/tests/auto/gui/image/qimage/.gitignore new file mode 100644 index 0000000000..d8afbffa72 --- /dev/null +++ b/tests/auto/gui/image/qimage/.gitignore @@ -0,0 +1 @@ +tst_qimage diff --git a/tests/auto/gui/image/qimage/images/image.bmp b/tests/auto/gui/image/qimage/images/image.bmp Binary files differnew file mode 100644 index 0000000000..39640e43e9 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.bmp diff --git a/tests/auto/gui/image/qimage/images/image.gif b/tests/auto/gui/image/qimage/images/image.gif Binary files differnew file mode 100644 index 0000000000..2c5a7f87e9 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.gif diff --git a/tests/auto/gui/image/qimage/images/image.ico b/tests/auto/gui/image/qimage/images/image.ico Binary files differnew file mode 100644 index 0000000000..7312d20f87 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.ico diff --git a/tests/auto/gui/image/qimage/images/image.jpg b/tests/auto/gui/image/qimage/images/image.jpg Binary files differnew file mode 100644 index 0000000000..7611322b1b --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.jpg diff --git a/tests/auto/gui/image/qimage/images/image.pbm b/tests/auto/gui/image/qimage/images/image.pbm new file mode 100644 index 0000000000..67e5efa3e9 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.pbm @@ -0,0 +1,8 @@ +P1 +16 6 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 diff --git a/tests/auto/gui/image/qimage/images/image.pgm b/tests/auto/gui/image/qimage/images/image.pgm new file mode 100644 index 0000000000..443bf40964 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.pgm @@ -0,0 +1,10 @@ +P2 +24 7 +15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 +0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 +0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/tests/auto/gui/image/qimage/images/image.png b/tests/auto/gui/image/qimage/images/image.png Binary files differnew file mode 100644 index 0000000000..7d4890a7ff --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.png diff --git a/tests/auto/gui/image/qimage/images/image.ppm b/tests/auto/gui/image/qimage/images/image.ppm new file mode 100644 index 0000000000..2a5640e189 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.ppm @@ -0,0 +1,7 @@ +P3 +4 4 +15 + 0 0 0 0 0 0 0 0 0 15 0 15 + 0 0 0 0 15 7 0 0 0 0 0 0 + 0 0 0 0 0 0 0 15 7 0 0 0 +15 0 15 0 0 0 0 0 0 0 0 0
\ No newline at end of file diff --git a/tests/auto/gui/image/qimage/images/image.tif b/tests/auto/gui/image/qimage/images/image.tif Binary files differnew file mode 100644 index 0000000000..ee0637cf25 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.tif diff --git a/tests/auto/gui/image/qimage/images/image.xbm b/tests/auto/gui/image/qimage/images/image.xbm new file mode 100644 index 0000000000..d0e0fcf2c1 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.xbm @@ -0,0 +1,5 @@ +#define Cloverleaf_width 9 +#define Cloverleaf_height 9 +static unsigned char Cloverleaf_bits[] = { + 0xc6, 0x00, 0x29, 0x01, 0x29, 0x01, 0xfe, 0x00, 0x28, 0x00, 0xfe, 0x00, + 0x29, 0x01, 0x29, 0x01, 0xc6, 0x00, }; diff --git a/tests/auto/gui/image/qimage/images/image.xpm b/tests/auto/gui/image/qimage/images/image.xpm new file mode 100644 index 0000000000..264ba401e6 --- /dev/null +++ b/tests/auto/gui/image/qimage/images/image.xpm @@ -0,0 +1,261 @@ +/* XPM */ +static char * foo_xpm[] = { +"256 256 2 1", +" c None", +". c #E22626", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................", +"................................................................................................................................................................................................................................................................"}; diff --git a/tests/auto/gui/image/qimage/qimage.pro b/tests/auto/gui/image/qimage/qimage.pro new file mode 100644 index 0000000000..b517bc1237 --- /dev/null +++ b/tests/auto/gui/image/qimage/qimage.pro @@ -0,0 +1,23 @@ +load(qttest_p4) +SOURCES += tst_qimage.cpp + +QT += core-private gui-private + +wince*: { + addImages.files = images/* + addImages.path = images + DEPLOYMENT += addImages + DEFINES += SRCDIR=\\\".\\\" +} else:symbian { + TARGET.EPOCHEAPSIZE = 0x200000 0x800000 + addImages.files = images/* + addImages.path = images + DEPLOYMENT += addImages + qt_not_deployed { + imagePlugins.files = qjpeg.dll qgif.dll qmng.dll qtiff.dll qico.dll + imagePlugins.path = imageformats + DEPLOYMENT += imagePlugins + } +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp new file mode 100644 index 0000000000..dce2957ae4 --- /dev/null +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -0,0 +1,2014 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qimage.h> +#include <qimagereader.h> +#include <qlist.h> +#include <qmatrix.h> +#include <stdio.h> + +#include <qpainter.h> +#include <private/qdrawhelper_p.h> + + +//TESTED_CLASS= +//TESTED_FILES= +#if defined(Q_OS_SYMBIAN) +# define SRCDIR "" +#endif + +Q_DECLARE_METATYPE(QImage::Format) +Q_DECLARE_METATYPE(Qt::GlobalColor) + +class tst_QImage : public QObject +{ + Q_OBJECT + +public: + tst_QImage(); + +private slots: + void swap(); + void create(); + void createInvalidXPM(); + void createFromUChar(); + void formatHandlersInput_data(); + void formatHandlersInput(); + + void setAlphaChannel_data(); + void setAlphaChannel(); + + void alphaChannel(); + + void convertToFormat_data(); + void convertToFormat(); + + void convertToFormatRgb888ToRGB32(); + + void createAlphaMask_data(); + void createAlphaMask(); +#ifndef QT_NO_IMAGE_HEURISTIC_MASK + void createHeuristicMask(); +#endif + + void dotsPerMeterZero(); + + void convertToFormatPreserveDotsPrMeter(); +#ifndef QT_NO_IMAGE_TEXT + void convertToFormatPreserveText(); +#endif + + void rotate_data(); + void rotate(); + + void copy(); + + void setPixel_data(); + void setPixel(); + + void setColorCount(); + void setColor(); + + void rasterClipping(); + + void pointOverloads(); + void destructor(); + void cacheKey(); + + void smoothScale(); + void smoothScale2(); + void smoothScale3(); + + void smoothScaleBig(); + void smoothScaleAlpha(); + + void transformed_data(); + void transformed(); + void transformed2(); + + void scaled(); + + void paintEngine(); + void setAlphaChannelWhilePainting(); + + void smoothScaledSubImage(); + + void nullSize_data(); + void nullSize(); + + void premultipliedAlphaConsistency(); + + void compareIndexed(); + + void fillColor_data(); + void fillColor(); + + void fillColorWithAlpha(); + + void rgbSwapped_data(); + void rgbSwapped(); + + void deepCopyWhenPaintingActive(); + void scaled_QTBUG19157(); +}; + +tst_QImage::tst_QImage() + +{ +} + +void tst_QImage::swap() +{ + QImage i1( 16, 16, QImage::Format_RGB32 ), i2( 32, 32, QImage::Format_RGB32 ); + i1.fill( Qt::white ); + i2.fill( Qt::black ); + const qint64 i1k = i1.cacheKey(); + const qint64 i2k = i2.cacheKey(); + i1.swap(i2); + QCOMPARE(i1.cacheKey(), i2k); + QCOMPARE(i1.size(), QSize(32,32)); + QCOMPARE(i2.cacheKey(), i1k); + QCOMPARE(i2.size(), QSize(16,16)); +} + +// Test if QImage (or any functions called from QImage) throws an +// exception when creating an extremely large image. +// QImage::create() should return "false" in this case. +void tst_QImage::create() +{ + bool cr = true; +#if !defined(Q_WS_QWS) && !defined(Q_OS_WINCE) + QT_TRY { +#endif + //QImage image(7000000, 7000000, 8, 256, QImage::IgnoreEndian); + QImage image(7000000, 7000000, QImage::Format_Indexed8); + image.setColorCount(256); + cr = !image.isNull(); +#if !defined(Q_WS_QWS) && !defined(Q_OS_WINCE) + } QT_CATCH (...) { + } +#endif + QVERIFY( !cr ); +} + +void tst_QImage::createInvalidXPM() +{ + QTest::ignoreMessage(QtWarningMsg, "QImage::QImage(), XPM is not supported"); + const char *xpm[] = {""}; + QImage invalidXPM(xpm); + QVERIFY(invalidXPM.isNull()); +} + +void tst_QImage::createFromUChar() +{ + uchar data[] = { +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + 0xFF, +#endif + 1,1,1, 0xFF, 2,2,2, 0xFF, 3,3,3, 0xFF, 4,4,4, +#if Q_BYTE_ORDER != Q_BIG_ENDIAN + 0xFF, +#endif + }; + + // When the data is const, nothing you do to the image will change the source data. + QImage i1((const uchar*)data, 2, 2, 8, QImage::Format_RGB32); + QCOMPARE(i1.pixel(0,0), 0xFF010101U); + QCOMPARE(i1.pixel(1,0), 0xFF020202U); + QCOMPARE(i1.pixel(0,1), 0xFF030303U); + QCOMPARE(i1.pixel(1,1), 0xFF040404U); + { + QImage i(i1); + i.setPixel(0,0,5); + } + QCOMPARE(i1.pixel(0,0), 0xFF010101U); + QCOMPARE(*(QRgb*)data, 0xFF010101U); + *((QRgb*)i1.bits()) = 7U; + QCOMPARE(i1.pixel(0,0), 7U); + QCOMPARE(*(QRgb*)data, 0xFF010101U); + + // Changing copies should not change the original image or data. + { + QImage i(i1); + i.setPixel(0,0,5); + QCOMPARE(*(QRgb*)data, 0xFF010101U); + i1.setPixel(0,0,9); + QCOMPARE(i1.pixel(0,0), 0xFF000009U); + QCOMPARE(i.pixel(0,0), 0xFF000005U); + } + QCOMPARE(i1.pixel(0,0), 0xFF000009U); + + // When the data is non-const, nothing you do to copies of the image will change the source data, + // but changing the image (here via bits()) will change the source data. + QImage i2((uchar*)data, 2, 2, 8, QImage::Format_RGB32); + QCOMPARE(i2.pixel(0,0), 0xFF010101U); + QCOMPARE(i2.pixel(1,0), 0xFF020202U); + QCOMPARE(i2.pixel(0,1), 0xFF030303U); + QCOMPARE(i2.pixel(1,1), 0xFF040404U); + { + QImage i(i2); + i.setPixel(0,0,5); + } + QCOMPARE(i2.pixel(0,0), 0xFF010101U); + QCOMPARE(*(QRgb*)data, 0xFF010101U); + *((QRgb*)i2.bits()) = 7U; + QCOMPARE(i2.pixel(0,0), 7U); + QCOMPARE(*(QRgb*)data, 7U); + + // Changing the data will change the image in either case. + QImage i3((uchar*)data, 2, 2, 8, QImage::Format_RGB32); + QImage i4((const uchar*)data, 2, 2, 8, QImage::Format_RGB32); + *(QRgb*)data = 6U; + QCOMPARE(i3.pixel(0,0), 6U); + QCOMPARE(i4.pixel(0,0), 6U); +} + +void tst_QImage::formatHandlersInput_data() +{ + QTest::addColumn<QString>("testFormat"); + QTest::addColumn<QString>("testFile"); + #ifdef Q_OS_SYMBIAN + const QString prefix = QLatin1String(SRCDIR) + "images/"; + #else + const QString prefix = QLatin1String(SRCDIR) + "/images/"; + #endif + + // add a new line here when a file is added + QTest::newRow("ICO") << "ICO" << prefix + "image.ico"; + QTest::newRow("PNG") << "PNG" << prefix + "image.png"; + QTest::newRow("GIF") << "GIF" << prefix + "image.gif"; + QTest::newRow("BMP") << "BMP" << prefix + "image.bmp"; + QTest::newRow("JPEG") << "JPEG" << prefix + "image.jpg"; + QTest::newRow("PBM") << "PBM" << prefix + "image.pbm"; + QTest::newRow("PGM") << "PGM" << prefix + "image.pgm"; + QTest::newRow("PPM") << "PPM" << prefix + "image.ppm"; + QTest::newRow("XBM") << "XBM" << prefix + "image.xbm"; + QTest::newRow("XPM") << "XPM" << prefix + "image.xpm"; +#if defined QTEST_HAVE_TIFF + QTest::newRow("TIFF") << "TIFF" << prefix + "image.tif"; +#endif +} + +void tst_QImage::formatHandlersInput() +{ + QFETCH(QString, testFormat); + QFETCH(QString, testFile); + QList<QByteArray> formats = QImageReader::supportedImageFormats(); + // qDebug("Image input formats : %s", formats.join(" | ").latin1()); + + bool formatSupported = false; + for (QList<QByteArray>::Iterator it = formats.begin(); it != formats.end(); ++it) { + if (*it == testFormat.toLower()) { + formatSupported = true; + break; + } + } + if (formatSupported) { +// qDebug(QImage::imageFormat(testFile)); + QCOMPARE(testFormat.toLatin1().toLower(), QImageReader::imageFormat(testFile)); + } else { + QString msg = "Format not supported : "; + QSKIP(QString(msg + testFormat).toLatin1(), SkipSingle); + } +} + +void tst_QImage::setAlphaChannel_data() +{ + QTest::addColumn<int>("red"); + QTest::addColumn<int>("green"); + QTest::addColumn<int>("blue"); + QTest::addColumn<int>("alpha"); + QTest::addColumn<bool>("gray"); + + QTest::newRow("red at 0%, gray") << 255 << 0 << 0 << 0 << true; + QTest::newRow("red at 25%, gray") << 255 << 0 << 0 << 63 << true; + QTest::newRow("red at 50%, gray") << 255 << 0 << 0 << 127 << true; + QTest::newRow("red at 100%, gray") << 255 << 0 << 0 << 191 << true; + QTest::newRow("red at 0%, 32bit") << 255 << 0 << 0 << 0 << false; + QTest::newRow("red at 25%, 32bit") << 255 << 0 << 0 << 63 << false; + QTest::newRow("red at 50%, 32bit") << 255 << 0 << 0 << 127 << false; + QTest::newRow("red at 100%, 32bit") << 255 << 0 << 0 << 191 << false; + + QTest::newRow("green at 0%, gray") << 0 << 255 << 0 << 0 << true; + QTest::newRow("green at 25%, gray") << 0 << 255 << 0 << 63 << true; + QTest::newRow("green at 50%, gray") << 0 << 255 << 0 << 127 << true; + QTest::newRow("green at 100%, gray") << 0 << 255 << 0 << 191 << true; + QTest::newRow("green at 0%, 32bit") << 0 << 255 << 0 << 0 << false; + QTest::newRow("green at 25%, 32bit") << 0 << 255 << 0 << 63 << false; + QTest::newRow("green at 50%, 32bit") << 0 << 255 << 0 << 127 << false; + QTest::newRow("green at 100%, 32bit") << 0 << 255 << 0 << 191 << false; + + QTest::newRow("blue at 0%, gray") << 0 << 0 << 255 << 0 << true; + QTest::newRow("blue at 25%, gray") << 0 << 0 << 255 << 63 << true; + QTest::newRow("blue at 50%, gray") << 0 << 0 << 255 << 127 << true; + QTest::newRow("blue at 100%, gray") << 0 << 0 << 255 << 191 << true; + QTest::newRow("blue at 0%, 32bit") << 0 << 0 << 255 << 0 << false; + QTest::newRow("blue at 25%, 32bit") << 0 << 0 << 255 << 63 << false; + QTest::newRow("blue at 50%, 32bit") << 0 << 0 << 255 << 127 << false; + QTest::newRow("blue at 100%, 32bit") << 0 << 0 << 255 << 191 << false; +} + +void tst_QImage::setAlphaChannel() +{ + QFETCH(int, red); + QFETCH(int, green); + QFETCH(int, blue); + QFETCH(int, alpha); + QFETCH(bool, gray); + + int width = 100; + int height = 100; + + QImage image(width, height, QImage::Format_RGB32); + image.fill(qRgb(red, green, blue)); + + // Create the alpha channel + QImage alphaChannel; + if (gray) { + alphaChannel = QImage(width, height, QImage::Format_Indexed8); + alphaChannel.setColorCount(256); + for (int i=0; i<256; ++i) + alphaChannel.setColor(i, qRgb(i, i, i)); + alphaChannel.fill(alpha); + } else { + alphaChannel = QImage(width, height, QImage::Format_ARGB32); + alphaChannel.fill(qRgb(alpha, alpha, alpha)); + } + + image.setAlphaChannel(alphaChannel); + image = image.convertToFormat(QImage::Format_ARGB32); + QVERIFY(image.format() == QImage::Format_ARGB32); + + // alpha of 0 becomes black at a=0 due to premultiplication + QRgb pixel = alpha == 0 ? 0 : qRgba(red, green, blue, alpha); + bool allPixelsOK = true; + for (int y=0; y<height; ++y) { + for (int x=0; x<width; ++x) { + allPixelsOK &= image.pixel(x, y) == pixel; + } + } + QVERIFY(allPixelsOK); + + QImage outAlpha = image.alphaChannel(); + QCOMPARE(outAlpha.size(), image.size()); + + bool allAlphaOk = true; + for (int y=0; y<height; ++y) { + for (int x=0; x<width; ++x) { + allAlphaOk &= outAlpha.pixelIndex(x, y) == alpha; + } + } + QVERIFY(allAlphaOk); + +} + +void tst_QImage::alphaChannel() +{ + QImage img(10, 10, QImage::Format_Mono); + img.setColor(0, Qt::transparent); + img.setColor(1, Qt::black); + img.fill(0); + + QPainter p(&img); + p.fillRect(2, 2, 6, 6, Qt::black); + p.end(); + + QCOMPARE(img.alphaChannel(), img.convertToFormat(QImage::Format_ARGB32).alphaChannel()); +} + +void tst_QImage::convertToFormat_data() +{ + QTest::addColumn<int>("inFormat"); + QTest::addColumn<uint>("inPixel"); + QTest::addColumn<int>("resFormat"); + QTest::addColumn<uint>("resPixel"); + + QTest::newRow("red rgb32 -> argb32") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green rgb32 -> argb32") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue rgb32 -> argb32") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + + QTest::newRow("red rgb32 -> rgb16") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_RGB16) << 0xffff0000; + QTest::newRow("green rgb32 -> rgb16") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_RGB16) << 0xff00ff00; + QTest::newRow("blue rgb32 -> rgb16") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_RGB16) << 0xff0000ff; + QTest::newRow("funky rgb32 -> rgb16") << int(QImage::Format_RGB32) << 0xfff0c080 + << int(QImage::Format_RGB16) << 0xfff7c384; + + QTest::newRow("red rgb32 -> argb32_pm") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_ARGB32_Premultiplied) << 0xffff0000; + QTest::newRow("green rgb32 -> argb32_pm") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_ARGB32_Premultiplied) <<0xff00ff00; + QTest::newRow("blue rgb32 -> argb32_pm") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_ARGB32_Premultiplied) << 0xff0000ff; + + QTest::newRow("semired argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7fff0000u + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u; + QTest::newRow("semigreen argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7f00ff00u + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u; + QTest::newRow("semiblue argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7f0000ffu + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu; + QTest::newRow("semiwhite argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7fffffffu + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu; + QTest::newRow("semiblack argb32 -> pm") << int(QImage::Format_ARGB32) << 0x7f000000u + << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u; + + QTest::newRow("semired pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u + << int(QImage::Format_ARGB32) << 0x7fff0000u; + QTest::newRow("semigreen pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u + << int(QImage::Format_ARGB32) << 0x7f00ff00u; + QTest::newRow("semiblue pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu + << int(QImage::Format_ARGB32) << 0x7f0000ffu; + QTest::newRow("semiwhite pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu + << int(QImage::Format_ARGB32) << 0x7fffffffu; + QTest::newRow("semiblack pm -> argb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u + << int(QImage::Format_ARGB32) << 0x7f000000u; + + QTest::newRow("semired pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u + << int(QImage::Format_RGB32) << 0xffff0000u; + QTest::newRow("semigreen pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u + << int(QImage::Format_RGB32) << 0xff00ff00u; + QTest::newRow("semiblue pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu + << int(QImage::Format_RGB32) << 0xff0000ffu; + QTest::newRow("semiwhite pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu + << int(QImage::Format_RGB32) << 0xffffffffu; + QTest::newRow("semiblack pm -> rgb32") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u + << int(QImage::Format_RGB32) << 0xff000000u; + + QTest::newRow("semired argb32 -> rgb32") << int(QImage::Format_ARGB32) << 0x7fff0000u + << int(QImage::Format_RGB32) << 0xffff0000u; + QTest::newRow("semigreen argb32 -> rgb32") << int(QImage::Format_ARGB32) << 0x7f00ff00u + << int(QImage::Format_RGB32) << 0xff00ff00u; + QTest::newRow("semiblue argb32 -> rgb32") << int(QImage::Format_ARGB32) << 0x7f0000ffu + << int(QImage::Format_RGB32) << 0xff0000ffu; + QTest::newRow("semiwhite argb -> rgb32") << int(QImage::Format_ARGB32) << 0x7fffffffu + << int(QImage::Format_RGB32) << 0xffffffffu; + QTest::newRow("semiblack argb -> rgb32") << int(QImage::Format_ARGB32) << 0x7f000000u + << int(QImage::Format_RGB32) << 0xff000000u; + + QTest::newRow("black mono -> rgb32") << int(QImage::Format_Mono) << 0x00000000u + << int(QImage::Format_RGB32) << 0xff000000u; + + QTest::newRow("white mono -> rgb32") << int(QImage::Format_Mono) << 0x00000001u + << int(QImage::Format_RGB32) << 0xffffffffu; + QTest::newRow("red rgb16 -> argb32") << int(QImage::Format_RGB16) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green rgb16 -> argb32") << int(QImage::Format_RGB16) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue rgb16 -> argb32") << int(QImage::Format_RGB16) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + QTest::newRow("red rgb16 -> rgb16") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_RGB16) << 0xffff0000; + QTest::newRow("green rgb16 -> rgb16") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_RGB16) << 0xff00ff00; + QTest::newRow("blue rgb16 -> rgb16") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_RGB16) << 0xff0000ff; + QTest::newRow("semired argb32 -> rgb16") << int(QImage::Format_ARGB32) << 0x7fff0000u + << int(QImage::Format_RGB16) << 0xffff0000; + QTest::newRow("semigreen argb32 -> rgb16") << int(QImage::Format_ARGB32) << 0x7f00ff00u + << int(QImage::Format_RGB16) << 0xff00ff00; + QTest::newRow("semiblue argb32 -> rgb16") << int(QImage::Format_ARGB32) << 0x7f0000ffu + << int(QImage::Format_RGB16) << 0xff0000ff; + QTest::newRow("semired pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u + << int(QImage::Format_RGB16) << 0xffff0000u; + + QTest::newRow("semigreen pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u + << int(QImage::Format_RGB16) << 0xff00ff00u; + QTest::newRow("semiblue pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu + << int(QImage::Format_RGB16) << 0xff0000ffu; + QTest::newRow("semiwhite pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu + << int(QImage::Format_RGB16) << 0xffffffffu; + QTest::newRow("semiblack pm -> rgb16") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u + << int(QImage::Format_RGB16) << 0xff000000u; + + QTest::newRow("mono -> mono lsb") << int(QImage::Format_Mono) << 1u + << int(QImage::Format_MonoLSB) << 0xffffffffu; + QTest::newRow("mono lsb -> mono") << int(QImage::Format_MonoLSB) << 1u + << int(QImage::Format_Mono) << 0xffffffffu; + + QTest::newRow("red rgb32 -> rgb666") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_RGB666) << 0xffff0000; + QTest::newRow("green rgb32 -> rgb666") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_RGB666) << 0xff00ff00; + QTest::newRow("blue rgb32 -> rgb666") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_RGB666) << 0xff0000ff; + + QTest::newRow("red rgb16 -> rgb666") << int(QImage::Format_RGB16) << 0xffff0000 + << int(QImage::Format_RGB666) << 0xffff0000; + QTest::newRow("green rgb16 -> rgb666") << int(QImage::Format_RGB16) << 0xff00ff00 + << int(QImage::Format_RGB666) << 0xff00ff00; + QTest::newRow("blue rgb16 -> rgb666") << int(QImage::Format_RGB16) << 0xff0000ff + << int(QImage::Format_RGB666) << 0xff0000ff; + + QTest::newRow("red rgb32 -> rgb15") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_RGB555) << 0xffff0000; + QTest::newRow("green rgb32 -> rgb15") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_RGB555) << 0xff00ff00; + QTest::newRow("blue rgb32 -> rgb15") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_RGB555) << 0xff0000ff; + QTest::newRow("funky rgb32 -> rgb15") << int(QImage::Format_RGB32) << 0xfff0c080 + << int(QImage::Format_RGB555) << 0xfff7c684; + + QTest::newRow("red rgb16 -> rgb15") << int(QImage::Format_RGB16) << 0xffff0000 + << int(QImage::Format_RGB555) << 0xffff0000; + QTest::newRow("green rgb16 -> rgb15") << int(QImage::Format_RGB16) << 0xff00ff00 + << int(QImage::Format_RGB555) << 0xff00ff00; + QTest::newRow("blue rgb16 -> rgb15") << int(QImage::Format_RGB16) << 0xff0000ff + << int(QImage::Format_RGB555) << 0xff0000ff; + QTest::newRow("funky rgb16 -> rgb15") << int(QImage::Format_RGB16) << 0xfff0c080 + << int(QImage::Format_RGB555) << 0xfff7c684; + + QTest::newRow("red rgb32 -> argb8565") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_ARGB8565_Premultiplied) << 0xffff0000; + QTest::newRow("green rgb32 -> argb8565") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_ARGB8565_Premultiplied) << 0xff00ff00; + QTest::newRow("blue rgb32 -> argb8565") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_ARGB8565_Premultiplied) << 0xff0000ff; + + QTest::newRow("red rgb16 -> argb8565") << int(QImage::Format_RGB16) << 0xffff0000 + << int(QImage::Format_ARGB8565_Premultiplied) << 0xffff0000; + QTest::newRow("green rgb16 -> argb8565") << int(QImage::Format_RGB16) << 0xff00ff00 + << int(QImage::Format_ARGB8565_Premultiplied) << 0xff00ff00; + QTest::newRow("blue rgb16 -> argb8565") << int(QImage::Format_RGB16) << 0xff0000ff + << int(QImage::Format_ARGB8565_Premultiplied) << 0xff0000ff; + + QTest::newRow("red argb8565 -> argb32") << int(QImage::Format_ARGB8565_Premultiplied) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green argb8565 -> argb32") << int(QImage::Format_ARGB8565_Premultiplied) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue argb8565 -> argb32") << int(QImage::Format_ARGB8565_Premultiplied) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + + QTest::newRow("semired argb32 -> argb8565") << int(QImage::Format_ARGB32) << 0x7fff0000u + << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f7b0000u; + QTest::newRow("semigreen argb32 -> argb8565") << int(QImage::Format_ARGB32) << 0x7f00ff00u + << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f007d00u; + QTest::newRow("semiblue argb32 -> argb8565") << int(QImage::Format_ARGB32) << 0x7f0000ffu + << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f00007bu; + + QTest::newRow("semired pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u + << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f7b0000u; + QTest::newRow("semigreen pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u + << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f007d00u; + QTest::newRow("semiblue pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu + << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f00007bu; + QTest::newRow("semiwhite pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu + << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f7b7d7bu; + QTest::newRow("semiblack pm -> argb8565") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u + << int(QImage::Format_ARGB8565_Premultiplied) << 0x7f000000u; + + QTest::newRow("red rgb666 -> argb32") << int(QImage::Format_RGB666) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green rgb666 -> argb32") << int(QImage::Format_RGB666) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue rgb666 -> argb32") << int(QImage::Format_RGB666) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + + QTest::newRow("semired argb32 -> rgb666") << int(QImage::Format_ARGB32) << 0x7fff0000u + << int(QImage::Format_RGB666) << 0xffff0000; + QTest::newRow("semigreen argb32 -> rgb666") << int(QImage::Format_ARGB32) << 0x7f00ff00u + << int(QImage::Format_RGB666) << 0xff00ff00; + QTest::newRow("semiblue argb32 -> rgb666") << int(QImage::Format_ARGB32) << 0x7f0000ffu + << int(QImage::Format_RGB666) << 0xff0000ff; + + QTest::newRow("semired pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u + << int(QImage::Format_RGB666) << 0xffff0000u; + QTest::newRow("semigreen pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u + << int(QImage::Format_RGB666) << 0xff00ff00u; + QTest::newRow("semiblue pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu + << int(QImage::Format_RGB666) << 0xff0000ffu; + QTest::newRow("semiwhite pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu + << int(QImage::Format_RGB666) << 0xffffffffu; + QTest::newRow("semiblack pm -> rgb666") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u + << int(QImage::Format_RGB666) << 0xff000000u; + + QTest::newRow("red rgb15 -> argb32") << int(QImage::Format_RGB555) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green rgb15 -> argb32") << int(QImage::Format_RGB555) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue rgb15 -> argb32") << int(QImage::Format_RGB555) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + + QTest::newRow("semired argb32 -> rgb15") << int(QImage::Format_ARGB32) << 0x7fff0000u + << int(QImage::Format_RGB555) << 0xffff0000; + QTest::newRow("semigreen argb32 -> rgb15") << int(QImage::Format_ARGB32) << 0x7f00ff00u + << int(QImage::Format_RGB555) << 0xff00ff00; + QTest::newRow("semiblue argb32 -> rgb15") << int(QImage::Format_ARGB32) << 0x7f0000ffu + << int(QImage::Format_RGB555) << 0xff0000ff; + + QTest::newRow("semired pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u + << int(QImage::Format_RGB555) << 0xffff0000u; + QTest::newRow("semigreen pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u + << int(QImage::Format_RGB555) << 0xff00ff00u; + QTest::newRow("semiblue pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu + << int(QImage::Format_RGB555) << 0xff0000ffu; + QTest::newRow("semiwhite pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu + << int(QImage::Format_RGB555) << 0xffffffffu; + QTest::newRow("semiblack pm -> rgb15") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u + << int(QImage::Format_RGB555) << 0xff000000u; + + + QTest::newRow("red rgb32 -> argb8555") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_ARGB8555_Premultiplied) << 0xffff0000; + QTest::newRow("green rgb32 -> argb8555") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_ARGB8555_Premultiplied) << 0xff00ff00; + QTest::newRow("blue rgb32 -> argb8555") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_ARGB8555_Premultiplied) << 0xff0000ff; + + QTest::newRow("red rgb16 -> argb8555") << int(QImage::Format_RGB16) << 0xffff0000 + << int(QImage::Format_ARGB8555_Premultiplied) << 0xffff0000; + QTest::newRow("green rgb16 -> argb8555") << int(QImage::Format_RGB16) << 0xff00ff00 + << int(QImage::Format_ARGB8555_Premultiplied) << 0xff00ff00; + QTest::newRow("blue rgb16 -> argb8555") << int(QImage::Format_RGB16) << 0xff0000ff + << int(QImage::Format_ARGB8555_Premultiplied) << 0xff0000ff; + + QTest::newRow("red argb8555 -> argb32") << int(QImage::Format_ARGB8555_Premultiplied) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green argb8555 -> argb32") << int(QImage::Format_ARGB8555_Premultiplied) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue argb8555 -> argb32") << int(QImage::Format_ARGB8555_Premultiplied) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + + QTest::newRow("semired argb32 -> argb8555") << int(QImage::Format_ARGB32) << 0x7fff0000u + << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f7b0000u; + QTest::newRow("semigreen argb32 -> argb8555") << int(QImage::Format_ARGB32) << 0x7f00ff00u + << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f007b00u; + QTest::newRow("semiblue argb32 -> argb8555") << int(QImage::Format_ARGB32) << 0x7f0000ffu + << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f00007bu; + + QTest::newRow("semired pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u + << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f7b0000u; + QTest::newRow("semigreen pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u + << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f007b00u; + QTest::newRow("semiblue pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu + << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f00007bu; + QTest::newRow("semiwhite pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu + << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f7b7b7bu; + QTest::newRow("semiblack pm -> argb8555") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u + << int(QImage::Format_ARGB8555_Premultiplied) << 0x7f000000u; + + QTest::newRow("red rgb32 -> rgb888") << int(QImage::Format_RGB32) << 0xffff0000 + << int(QImage::Format_RGB888) << 0xffff0000; + QTest::newRow("green rgb32 -> rgb888") << int(QImage::Format_RGB32) << 0xff00ff00 + << int(QImage::Format_RGB888) << 0xff00ff00; + QTest::newRow("blue rgb32 -> rgb888") << int(QImage::Format_RGB32) << 0xff0000ff + << int(QImage::Format_RGB888) << 0xff0000ff; + + QTest::newRow("red rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xffff0000 + << int(QImage::Format_RGB888) << 0xffff0000; + QTest::newRow("green rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xff00ff00 + << int(QImage::Format_RGB888) << 0xff00ff00; + QTest::newRow("blue rgb16 -> rgb888") << int(QImage::Format_RGB16) << 0xff0000ff + << int(QImage::Format_RGB888) << 0xff0000ff; + + QTest::newRow("red rgb888 -> argb32") << int(QImage::Format_RGB888) << 0xffff0000 + << int(QImage::Format_ARGB32) << 0xffff0000; + QTest::newRow("green rgb888 -> argb32") << int(QImage::Format_RGB888) << 0xff00ff00 + << int(QImage::Format_ARGB32) << 0xff00ff00; + QTest::newRow("blue rgb888 -> argb32") << int(QImage::Format_RGB888) << 0xff0000ff + << int(QImage::Format_ARGB32) << 0xff0000ff; + + QTest::newRow("semired argb32 -> rgb888") << int(QImage::Format_ARGB32) << 0x7fff0000u + << int(QImage::Format_RGB888) << 0xffff0000; + QTest::newRow("semigreen argb32 -> rgb888") << int(QImage::Format_ARGB32) << 0x7f00ff00u + << int(QImage::Format_RGB888) << 0xff00ff00; + QTest::newRow("semiblue argb32 -> rgb888") << int(QImage::Format_ARGB32) << 0x7f0000ffu + << int(QImage::Format_RGB888) << 0xff0000ff; + + QTest::newRow("semired pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f0000u + << int(QImage::Format_RGB888) << 0xffff0000u; + QTest::newRow("semigreen pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f007f00u + << int(QImage::Format_RGB888) << 0xff00ff00u; + QTest::newRow("semiblue pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f00007fu + << int(QImage::Format_RGB888) << 0xff0000ffu; + QTest::newRow("semiwhite pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f7f7f7fu + << int(QImage::Format_RGB888) << 0xffffffffu; + QTest::newRow("semiblack pm -> rgb888") << int(QImage::Format_ARGB32_Premultiplied) << 0x7f000000u + << int(QImage::Format_RGB888) << 0xff000000u; +} + + +void tst_QImage::convertToFormat() +{ + QFETCH(int, inFormat); + QFETCH(uint, inPixel); + QFETCH(int, resFormat); + QFETCH(uint, resPixel); + + QImage src(32, 32, QImage::Format(inFormat)); + + if (inFormat == QImage::Format_Mono) { + src.setColor(0, qRgba(0,0,0,0xff)); + src.setColor(1, qRgba(255,255,255,0xff)); + } + + for (int y=0; y<src.height(); ++y) + for (int x=0; x<src.width(); ++x) + src.setPixel(x, y, inPixel); + + QImage result = src.convertToFormat(QImage::Format(resFormat)); + + QCOMPARE(src.width(), result.width()); + QCOMPARE(src.height(), result.height()); + + bool same = true; + for (int y=0; y<result.height(); ++y) { + for (int x=0; x<result.width(); ++x) { + QRgb pixel = result.pixel(x, y); + same &= (pixel == resPixel); + if (!same) { + printf("expect=%08x, result=%08x\n", resPixel, pixel); + y = 100000; + break; + } + + } + } + QVERIFY(same); + + // repeat tests converting from an image with nonstandard stride + + int dp = (src.depth() < 8 || result.depth() < 8) ? 8 : 1; + QImage src2(src.bits() + (dp*src.depth())/8, + src.width() - dp*2, + src.height(), src.bytesPerLine(), + src.format()); + if (src.depth() < 8) + src2.setColorTable(src.colorTable()); + + const QImage result2 = src2.convertToFormat(QImage::Format(resFormat)); + + QCOMPARE(src2.width(), result2.width()); + QCOMPARE(src2.height(), result2.height()); + + QImage expected2(result.bits() + (dp*result.depth())/8, + result.width() - dp*2, + result.height(), result.bytesPerLine(), + result.format()); + if (result.depth() < 8) + expected2.setColorTable(result.colorTable()); + + result2.save("result2.xpm", "XPM"); + expected2.save("expected2.xpm", "XPM"); + + QCOMPARE(result2, expected2); + QFile::remove(QLatin1String("result2.xpm")); + QFile::remove(QLatin1String("expected2.xpm")); +} + +void tst_QImage::convertToFormatRgb888ToRGB32() +{ + // 545 so width % 4 != 0. This ensure there is padding at the end of the scanlines + const int height = 545; + const int width = 545; + QImage source(width, height, QImage::Format_RGB888); + for (int y = 0; y < height; ++y) { + uchar *srcPixels = source.scanLine(y); + for (int x = 0; x < width * 3; ++x) + srcPixels[x] = x; + } + + QImage rgb32Image = source.convertToFormat(QImage::Format_RGB888); + QCOMPARE(rgb32Image.format(), QImage::Format_RGB888); + for (int x = 0; x < width; ++x) { + for (int y = 0; y < height; ++y) + QCOMPARE(rgb32Image.pixel(x, y), source.pixel(x, y)); + } +} + +void tst_QImage::createAlphaMask_data() +{ + QTest::addColumn<int>("x"); + QTest::addColumn<int>("y"); + QTest::addColumn<int>("alpha1"); + QTest::addColumn<int>("alpha2"); + + int alphas[] = { 0, 127, 255 }; + + for (unsigned a1 = 0; a1 < sizeof(alphas) / sizeof(int); ++a1) { + for (unsigned a2 = 0; a2 < sizeof(alphas) / sizeof(int); ++a2) { + if (a1 == a2) + continue; + for (int x=10; x<18; x+=3) { + for (int y=100; y<108; y+=3) { + QTest::newRow(qPrintable(QString::fromLatin1("x=%1, y=%2, a1=%3, a2=%4").arg(x).arg(y).arg(alphas[a1]).arg(alphas[a2]))) + << x << y << alphas[a1] << alphas[a2]; + } + } + } + } +} + +void tst_QImage::createAlphaMask() +{ + QFETCH(int, x); + QFETCH(int, y); + QFETCH(int, alpha1); + QFETCH(int, alpha2); + + QSize size(255, 255); + int pixelsInLines = size.width() + size.height() - 1; + int pixelsOutofLines = size.width() * size.height() - pixelsInLines; + + // Generate an white image with two lines, horizontal at y and vertical at x. + // Lines have alpha of alpha2, rest has alpha of alpha1 + QImage image(size, QImage::Format_ARGB32); + for (int cy=0; cy<image.height(); ++cy) { + for (int cx=0; cx<image.width(); ++cx) { + int alpha = (y == cy || x == cx) ? alpha2 : alpha1; + image.setPixel(cx, cy, qRgba(255, 255, 255, alpha)); + } + } + + QImage mask = image.createAlphaMask(Qt::OrderedAlphaDither); + + // Sanity check... + QCOMPARE(mask.width(), image.width()); + QCOMPARE(mask.height(), image.height()); + + // Sum up the number of pixels set for both lines and other area + int sumAlpha1 = 0; + int sumAlpha2 = 0; + for (int cy=0; cy<image.height(); ++cy) { + for (int cx=0; cx<image.width(); ++cx) { + int *alpha = (y == cy || x == cx) ? &sumAlpha2 : &sumAlpha1; + *alpha += mask.pixelIndex(cx, cy); + } + } + + // Compare the set bits to whats expected for that alpha. + const int threshold = 5; + QVERIFY(qAbs(sumAlpha1 * 255 / pixelsOutofLines - alpha1) < threshold); + QVERIFY(qAbs(sumAlpha2 * 255 / pixelsInLines - alpha2) < threshold); +} + +void tst_QImage::dotsPerMeterZero() +{ + QImage img(100, 100, QImage::Format_RGB32); + QVERIFY(!img.isNull()); + + int defaultDpmX = img.dotsPerMeterX(); + int defaultDpmY = img.dotsPerMeterY(); + QVERIFY(defaultDpmX != 0); + QVERIFY(defaultDpmY != 0); + + img.setDotsPerMeterX(0); + img.setDotsPerMeterY(0); + + QCOMPARE(img.dotsPerMeterX(), defaultDpmX); + QCOMPARE(img.dotsPerMeterY(), defaultDpmY); +} + +void tst_QImage::rotate_data() +{ + QTest::addColumn<QImage::Format>("format"); + QTest::addColumn<int>("degrees"); + + QVector<int> degrees; + degrees << 0 << 90 << 180 << 270; + + foreach (int d, degrees) { + QString title = QString("%1 %2").arg(d); + QTest::newRow(qPrintable(title.arg("Format_RGB32"))) + << QImage::Format_RGB32 << d; + QTest::newRow(qPrintable(title.arg("Format_ARGB32"))) + << QImage::Format_ARGB32 << d; + QTest::newRow(qPrintable(title.arg("Format_ARGB32_Premultiplied"))) + << QImage::Format_ARGB32_Premultiplied << d; + QTest::newRow(qPrintable(title.arg("Format_RGB16"))) + << QImage::Format_RGB16 << d; + QTest::newRow(qPrintable(title.arg("Format_ARGB8565_Premultiplied"))) + << QImage::Format_ARGB8565_Premultiplied << d; + QTest::newRow(qPrintable(title.arg("Format_RGB666"))) + << QImage::Format_RGB666 << d; + QTest::newRow(qPrintable(title.arg("Format_RGB555"))) + << QImage::Format_RGB555 << d; + QTest::newRow(qPrintable(title.arg("Format_ARGB8555_Premultiplied"))) + << QImage::Format_ARGB8555_Premultiplied << d; + QTest::newRow(qPrintable(title.arg("Format_RGB888"))) + << QImage::Format_RGB888 << d; + QTest::newRow(qPrintable(title.arg("Format_Indexed8"))) + << QImage::Format_Indexed8 << d; + } +} + +void tst_QImage::rotate() +{ + QFETCH(QImage::Format, format); + QFETCH(int, degrees); + + // test if rotate90 is lossless + int w = 54; + int h = 13; + QImage original(w, h, format); + original.fill(qRgb(255,255,255)); + + if (format == QImage::Format_Indexed8) { + original.setColorCount(256); + for (int i = 0; i < 255; ++i) + original.setColor(i, qRgb(0, i, i)); + } + + if (original.colorTable().isEmpty()) { + for (int x = 0; x < w; ++x) { + original.setPixel(x,0, qRgb(x,0,128)); + original.setPixel(x,h - 1, qRgb(0,255 - x,128)); + } + for (int y = 0; y < h; ++y) { + original.setPixel(0, y, qRgb(y,0,255)); + original.setPixel(w - 1, y, qRgb(0,255 - y,255)); + } + } else { + const int n = original.colorTable().size(); + for (int x = 0; x < w; ++x) { + original.setPixel(x, 0, x % n); + original.setPixel(x, h - 1, n - (x % n) - 1); + } + for (int y = 0; y < h; ++y) { + original.setPixel(0, y, y % n); + original.setPixel(w - 1, y, n - (y % n) - 1); + } + } + + // original.save("rotated90_original.png", "png"); + + // Initialize the matrix manually (do not use rotate) to avoid rounding errors + QMatrix matRotate90; + matRotate90.rotate(degrees); + QImage dest = original; + // And rotate it 4 times, then the image should be identical to the original + for (int i = 0; i < 4 ; ++i) { + dest = dest.transformed(matRotate90); + } + + // Make sure they are similar in format before we compare them. + dest = dest.convertToFormat(format); + + // dest.save("rotated90_result.png","png"); + QCOMPARE(original, dest); + + // Test with QMatrix::rotate 90 also, since we trust that now + matRotate90.rotate(degrees); + dest = original; + // And rotate it 4 times, then the image should be identical to the original + for (int i = 0; i < 4 ; ++i) { + dest = dest.transformed(matRotate90); + } + + // Make sure they are similar in format before we compare them. + dest = dest.convertToFormat(format); + + QCOMPARE(original, dest); +} + +void tst_QImage::copy() +{ + // Task 99250 + { + QImage img(16,16,QImage::Format_ARGB32); + img.copy(QRect(1000,1,1,1)); + } +} + +void tst_QImage::setPixel_data() +{ + QTest::addColumn<int>("format"); + QTest::addColumn<uint>("value"); + QTest::addColumn<uint>("expected"); + + QTest::newRow("ARGB32 red") << int(QImage::Format_ARGB32) + << 0xffff0000 << 0xffff0000; + QTest::newRow("ARGB32 green") << int(QImage::Format_ARGB32) + << 0xff00ff00 << 0xff00ff00; + QTest::newRow("ARGB32 blue") << int(QImage::Format_ARGB32) + << 0xff0000ff << 0xff0000ff; + QTest::newRow("RGB16 red") << int(QImage::Format_RGB16) + << 0xffff0000 << 0xf800u; + QTest::newRow("RGB16 green") << int(QImage::Format_RGB16) + << 0xff00ff00 << 0x07e0u; + QTest::newRow("RGB16 blue") << int(QImage::Format_RGB16) + << 0xff0000ff << 0x001fu; + QTest::newRow("ARGB8565_Premultiplied red") << int(QImage::Format_ARGB8565_Premultiplied) + << 0xffff0000 << 0xffff0000; + QTest::newRow("ARGB8565_Premultiplied green") << int(QImage::Format_ARGB8565_Premultiplied) + << 0xff00ff00 << 0xff00ff00; + QTest::newRow("ARGB8565_Premultiplied blue") << int(QImage::Format_ARGB8565_Premultiplied) + << 0xff0000ff << 0xff0000ff; + QTest::newRow("RGB666 red") << int(QImage::Format_RGB666) + << 0xffff0000 << 0xffff0000; + QTest::newRow("RGB666 green") << int(QImage::Format_RGB666) + << 0xff00ff00 << 0xff00ff00;; + QTest::newRow("RGB666 blue") << int(QImage::Format_RGB666) + << 0xff0000ff << 0xff0000ff; + QTest::newRow("RGB555 red") << int(QImage::Format_RGB555) + << 0xffff0000 << 0x7c00u; + QTest::newRow("RGB555 green") << int(QImage::Format_RGB555) + << 0xff00ff00 << 0x03e0u; + QTest::newRow("RGB555 blue") << int(QImage::Format_RGB555) + << 0xff0000ff << 0x001fu; + QTest::newRow("ARGB8555_Premultiplied red") << int(QImage::Format_ARGB8555_Premultiplied) + << 0xffff0000 << 0xffff0000; + QTest::newRow("ARGB8555_Premultiplied green") << int(QImage::Format_ARGB8555_Premultiplied) + << 0xff00ff00 << 0xff00ff00; + QTest::newRow("ARGB8555_Premultiplied blue") << int(QImage::Format_ARGB8555_Premultiplied) + << 0xff0000ff << 0xff0000ff; + QTest::newRow("RGB888 red") << int(QImage::Format_RGB888) + << 0xffff0000 << 0xffff0000; + QTest::newRow("RGB888 green") << int(QImage::Format_RGB888) + << 0xff00ff00 << 0xff00ff00; + QTest::newRow("RGB888 blue") << int(QImage::Format_RGB888) + << 0xff0000ff << 0xff0000ff; +} + +void tst_QImage::setPixel() +{ + QFETCH(int, format); + QFETCH(uint, value); + QFETCH(uint, expected); + + const int w = 13; + const int h = 15; + + QImage img(w, h, QImage::Format(format)); + + // fill image + for (int y = 0; y < h; ++y) + for (int x = 0; x < w; ++x) + img.setPixel(x, y, value); + + // check pixel values + switch (format) { + case int(QImage::Format_RGB32): + case int(QImage::Format_ARGB32): + case int(QImage::Format_ARGB32_Premultiplied): + { + for (int y = 0; y < h; ++y) { + const quint32 *row = (const quint32*)(img.scanLine(y)); + for (int x = 0; x < w; ++x) { + quint32 result = row[x]; + if (result != expected) + printf("[x,y]: %d,%d, expected=%08x, result=%08x\n", + x, y, expected, result); + QCOMPARE(uint(result), expected); + } + } + break; + } + case int(QImage::Format_RGB555): + case int(QImage::Format_RGB16): + { + for (int y = 0; y < h; ++y) { + const quint16 *row = (const quint16*)(img.scanLine(y)); + for (int x = 0; x < w; ++x) { + quint16 result = row[x]; + if (result != expected) + printf("[x,y]: %d,%d, expected=%04x, result=%04x\n", + x, y, expected, result); + QCOMPARE(uint(result), expected); + } + } + break; + } + case int(QImage::Format_RGB666): + { + for (int y = 0; y < h; ++y) { + const qrgb666 *row = (const qrgb666*)(img.scanLine(y)); + for (int x = 0; x < w; ++x) { + quint32 result = row[x]; + if (result != expected) + printf("[x,y]: %d,%d, expected=%04x, result=%04x\n", + x, y, expected, result); + QCOMPARE(result, expected); + } + } + break; + } + case int(QImage::Format_ARGB8565_Premultiplied): + { + for (int y = 0; y < h; ++y) { + const qargb8565 *row = (const qargb8565*)(img.scanLine(y)); + for (int x = 0; x < w; ++x) { + quint32 result = row[x]; + if (result != expected) + printf("[x,y]: %d,%d, expected=%04x, result=%04x\n", + x, y, expected, result); + QCOMPARE(result, expected); + } + } + break; + } + case int(QImage::Format_ARGB8555_Premultiplied): + { + for (int y = 0; y < h; ++y) { + const qargb8555 *row = (const qargb8555*)(img.scanLine(y)); + for (int x = 0; x < w; ++x) { + quint32 result = row[x]; + if (result != expected) + printf("[x,y]: %d,%d, expected=%04x, result=%04x\n", + x, y, expected, result); + QCOMPARE(result, expected); + } + } + break; + } + case int(QImage::Format_RGB888): + { + for (int y = 0; y < h; ++y) { + const qrgb888 *row = (const qrgb888*)(img.scanLine(y)); + for (int x = 0; x < w; ++x) { + qrgb888 result = row[x]; + if (result != expected) + printf("[x,y]: %d,%d, expected=%04x, result=%04x\n", + x, y, expected, quint32(result)); + QCOMPARE(uint(result), expected); + } + } + break; + } + default: + qFatal("Test not implemented for format %d", format); + } +} + +void tst_QImage::convertToFormatPreserveDotsPrMeter() +{ + QImage img(100, 100, QImage::Format_ARGB32_Premultiplied); + + int dpmx = 123; + int dpmy = 234; + img.setDotsPerMeterX(dpmx); + img.setDotsPerMeterY(dpmy); + img.fill(0x12345678); + + img = img.convertToFormat(QImage::Format_RGB32); + + QCOMPARE(img.dotsPerMeterX(), dpmx); + QCOMPARE(img.dotsPerMeterY(), dpmy); +} + +#ifndef QT_NO_IMAGE_TEXT +void tst_QImage::convertToFormatPreserveText() +{ + QImage img(100, 100, QImage::Format_ARGB32_Premultiplied); + + img.setText("foo", "bar"); + img.setText("foo2", "bar2"); + img.fill(0x12345678); + + QStringList listResult; + listResult << "foo" << "foo2"; + QString result = "foo: bar\n\nfoo2: bar2"; + + QImage imgResult1 = img.convertToFormat(QImage::Format_RGB32); + QCOMPARE(imgResult1.text(), result); + QCOMPARE(imgResult1.textKeys(), listResult); + + QVector<QRgb> colorTable(4); + for (int i = 0; i < 4; ++i) + colorTable[i] = QRgb(42); + QImage imgResult2 = img.convertToFormat(QImage::Format_MonoLSB, + colorTable); + QCOMPARE(imgResult2.text(), result); + QCOMPARE(imgResult2.textKeys(), listResult); +} +#endif // QT_NO_IMAGE_TEXT + +void tst_QImage::setColorCount() +{ + QImage img(0, 0, QImage::Format_Indexed8); + QTest::ignoreMessage(QtWarningMsg, "QImage::setColorCount: null image"); + img.setColorCount(256); + QCOMPARE(img.colorCount(), 0); +} + +void tst_QImage::setColor() +{ + QImage img(0, 0, QImage::Format_Indexed8); + img.setColor(0, qRgba(18, 219, 108, 128)); + QCOMPARE(img.colorCount(), 0); + + QImage img2(1, 1, QImage::Format_Indexed8); + img2.setColor(0, qRgba(18, 219, 108, 128)); + QCOMPARE(img2.colorCount(), 1); +} + +/* Just some sanity checking that we don't draw outside the buffer of + * the image. Hopefully this will create crashes or at least some + * random test fails when broken. + */ +void tst_QImage::rasterClipping() +{ + QImage image(10, 10, QImage::Format_RGB32); + image.fill(0xffffffff); + + QPainter p(&image); + + p.drawLine(-1000, 5, 5, 5); + p.drawLine(-1000, 5, 1000, 5); + p.drawLine(5, 5, 1000, 5); + + p.drawLine(5, -1000, 5, 5); + p.drawLine(5, -1000, 5, 1000); + p.drawLine(5, 5, 5, 1000); + + p.setBrush(Qt::red); + + p.drawEllipse(3, 3, 4, 4); + p.drawEllipse(-100, -100, 210, 210); + + p.drawEllipse(-1000, 0, 2010, 2010); + p.drawEllipse(0, -1000, 2010, 2010); + p.drawEllipse(-2010, -1000, 2010, 2010); + p.drawEllipse(-1000, -2010, 2010, 2010); + QVERIFY(true); +} + +// Tests the new QPoint overloads in QImage in Qt 4.2 +void tst_QImage::pointOverloads() +{ + QImage image(100, 100, QImage::Format_RGB32); + image.fill(0xff00ff00); + + // IsValid + QVERIFY(image.valid(QPoint(0, 0))); + QVERIFY(image.valid(QPoint(99, 0))); + QVERIFY(image.valid(QPoint(0, 99))); + QVERIFY(image.valid(QPoint(99, 99))); + + QVERIFY(!image.valid(QPoint(50, -1))); // outside on the top + QVERIFY(!image.valid(QPoint(50, 100))); // outside on the bottom + QVERIFY(!image.valid(QPoint(-1, 50))); // outside on the left + QVERIFY(!image.valid(QPoint(100, 50))); // outside on the right + + // Test the pixel setter + image.setPixel(QPoint(10, 10), 0xff0000ff); + QCOMPARE(image.pixel(10, 10), 0xff0000ff); + + // pixel getter + QCOMPARE(image.pixel(QPoint(10, 10)), 0xff0000ff); + + // pixelIndex() + QImage indexed = image.convertToFormat(QImage::Format_Indexed8); + QCOMPARE(indexed.pixelIndex(10, 10), indexed.pixelIndex(QPoint(10, 10))); +} + +void tst_QImage::destructor() +{ + QPolygon poly(6); + poly.setPoint(0,-1455, 1435); + + QImage image(100, 100, QImage::Format_RGB32); + QPainter ptPix(&image); + ptPix.setPen(Qt::black); + ptPix.setBrush(Qt::black); + ptPix.drawPolygon(poly, Qt::WindingFill); + ptPix.end(); + +} + + +/* XPM */ +static const char *monoPixmap[] = { +/* width height ncolors chars_per_pixel */ +"4 4 2 1", +"x c #000000", +". c #ffffff", +/* pixels */ +"xxxx", +"x..x", +"x..x", +"xxxx" +}; + + +#ifndef QT_NO_IMAGE_HEURISTIC_MASK +void tst_QImage::createHeuristicMask() +{ + QImage img(monoPixmap); + img = img.convertToFormat(QImage::Format_MonoLSB); + QImage mask = img.createHeuristicMask(); + QImage newMask = mask.convertToFormat(QImage::Format_ARGB32_Premultiplied); + + // line 2 + QVERIFY(newMask.pixel(0,1) != newMask.pixel(1,1)); + QVERIFY(newMask.pixel(1,1) == newMask.pixel(2,1)); + QVERIFY(newMask.pixel(2,1) != newMask.pixel(3,1)); + + // line 3 + QVERIFY(newMask.pixel(0,2) != newMask.pixel(1,2)); + QVERIFY(newMask.pixel(1,2) == newMask.pixel(2,2)); + QVERIFY(newMask.pixel(2,2) != newMask.pixel(3,2)); +} +#endif + +void tst_QImage::cacheKey() +{ + QImage image1(2, 2, QImage::Format_RGB32); + qint64 image1_key = image1.cacheKey(); + QImage image2 = image1; + + QVERIFY(image2.cacheKey() == image1.cacheKey()); + image2.detach(); + QVERIFY(image2.cacheKey() != image1.cacheKey()); + QVERIFY(image1.cacheKey() == image1_key); +} + +void tst_QImage::smoothScale() +{ + unsigned int data[2] = { qRgba(0, 0, 0, 0), qRgba(128, 128, 128, 128) }; + + QImage imgX((unsigned char *)data, 2, 1, QImage::Format_ARGB32_Premultiplied); + QImage imgY((unsigned char *)data, 1, 2, QImage::Format_ARGB32_Premultiplied); + + QImage scaledX = imgX.scaled(QSize(4, 1), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + QImage scaledY = imgY.scaled(QSize(1, 4), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + uint *scaled[2] = { + (unsigned int *)scaledX.bits(), + (unsigned int *)scaledY.bits() + }; + + int expected[4] = { 0, 32, 96, 128 }; + for (int image = 0; image < 2; ++image) { + for (int index = 0; index < 4; ++index) { + for (int component = 0; component < 4; ++component) { + int pixel = scaled[image][index]; + int val = (pixel >> (component * 8)) & 0xff; + + QCOMPARE(val, expected[index]); + } + } + } +} + +// test area sampling +void tst_QImage::smoothScale2() +{ + int sizes[] = { 2, 4, 8, 10, 16, 20, 32, 40, 64, 100, 101, 128, 0 }; + QImage::Format formats[] = { QImage::Format_ARGB32, QImage::Format_RGB32, QImage::Format_Invalid }; + for (int i = 0; sizes[i] != 0; ++i) { + for (int j = 0; formats[j] != QImage::Format_Invalid; ++j) { + int size = sizes[i]; + + QRgb expected = formats[j] == QImage::Format_ARGB32 ? qRgba(63, 127, 255, 255) : qRgb(63, 127, 255); + + QImage img(size, size, formats[j]); + img.fill(expected); + + // scale x down, y down + QImage scaled = img.scaled(QSize(1, 1), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + QRgb pixel = scaled.pixel(0, 0); + QCOMPARE(qAlpha(pixel), qAlpha(expected)); + QCOMPARE(qRed(pixel), qRed(expected)); + QCOMPARE(qGreen(pixel), qGreen(expected)); + QCOMPARE(qBlue(pixel), qBlue(expected)); + + // scale x down, y up + scaled = img.scaled(QSize(1, size * 2), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + for (int y = 0; y < scaled.height(); ++y) { + pixel = scaled.pixel(0, y); + QCOMPARE(qAlpha(pixel), qAlpha(expected)); + QCOMPARE(qRed(pixel), qRed(expected)); + QCOMPARE(qGreen(pixel), qGreen(expected)); + QCOMPARE(qBlue(pixel), qBlue(expected)); + } + + // scale x up, y down + scaled = img.scaled(QSize(size * 2, 1), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + for (int x = 0; x < scaled.width(); ++x) { + pixel = scaled.pixel(x, 0); + QCOMPARE(qAlpha(pixel), qAlpha(expected)); + QCOMPARE(qRed(pixel), qRed(expected)); + QCOMPARE(qGreen(pixel), qGreen(expected)); + QCOMPARE(qBlue(pixel), qBlue(expected)); + } + + // scale x up, y up + scaled = img.scaled(QSize(size * 2, size * 2), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + for (int y = 0; y < scaled.height(); ++y) { + for (int x = 0; x < scaled.width(); ++x) { + pixel = scaled.pixel(x, y); + QCOMPARE(qAlpha(pixel), qAlpha(expected)); + QCOMPARE(qRed(pixel), qRed(expected)); + QCOMPARE(qGreen(pixel), qGreen(expected)); + QCOMPARE(qBlue(pixel), qBlue(expected)); + } + } + } + } +} + +static inline int rand8() +{ + return int(256. * (qrand() / (RAND_MAX + 1.0))); +} + +// compares img.scale against the bilinear filtering used by QPainter +void tst_QImage::smoothScale3() +{ + QImage img(128, 128, QImage::Format_RGB32); + for (int y = 0; y < img.height(); ++y) { + for (int x = 0; x < img.width(); ++x) { + const int red = rand8(); + const int green = rand8(); + const int blue = rand8(); + const int alpha = 255; + + img.setPixel(x, y, qRgba(red, green, blue, alpha)); + } + } + + qreal scales[2] = { .5, 2 }; + + for (int i = 0; i < 2; ++i) { + QImage a = img.scaled(img.size() * scales[i], Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + QImage b(a.size(), a.format()); + b.fill(0x0); + + QPainter p(&b); + p.setRenderHint(QPainter::SmoothPixmapTransform); + p.scale(scales[i], scales[i]); + p.drawImage(0, 0, img); + p.end(); + int err = 0; + + for (int y = 0; y < a.height(); ++y) { + for (int x = 0; x < a.width(); ++x) { + QRgb ca = a.pixel(x, y); + QRgb cb = b.pixel(x, y); + + // tolerate a little bit of rounding errors + bool r = true; + r &= qAbs(qRed(ca) - qRed(cb)) <= 18; + r &= qAbs(qGreen(ca) - qGreen(cb)) <= 18; + r &= qAbs(qBlue(ca) - qBlue(cb)) <= 18; + if (!r) + err++; + } + } + QCOMPARE(err, 0); + } +} + +void tst_QImage::smoothScaleBig() +{ +#if defined(Q_OS_WINCE) + int bigValue = 2000; +#elif defined(Q_OS_SYMBIAN) + int bigValue = 2000; +#else + int bigValue = 200000; +#endif + QImage tall(4, bigValue, QImage::Format_ARGB32); + tall.fill(0x0); + + QImage wide(bigValue, 4, QImage::Format_ARGB32); + wide.fill(0x0); + + QImage tallScaled = tall.scaled(4, tall.height() / 4, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + QImage wideScaled = wide.scaled(wide.width() / 4, 4, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + QCOMPARE(tallScaled.pixel(0, 0), QRgb(0x0)); + QCOMPARE(wideScaled.pixel(0, 0), QRgb(0x0)); +} + +void tst_QImage::smoothScaleAlpha() +{ + QImage src(128, 128, QImage::Format_ARGB32_Premultiplied); + src.fill(0x0); + + QPainter srcPainter(&src); + srcPainter.setPen(Qt::NoPen); + srcPainter.setBrush(Qt::white); + srcPainter.drawEllipse(QRect(QPoint(), src.size())); + srcPainter.end(); + + QImage dst(32, 32, QImage::Format_ARGB32_Premultiplied); + dst.fill(0xffffffff); + QImage expected = dst; + + QPainter dstPainter(&dst); + dstPainter.drawImage(0, 0, src.scaled(dst.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + dstPainter.end(); + + QCOMPARE(dst, expected); +} + +static int count(const QImage &img, int x, int y, int dx, int dy, QRgb pixel) +{ + int i = 0; + while (x >= 0 && x < img.width() && y >= 0 && y < img.height()) { + i += (img.pixel(x, y) == pixel); + x += dx; + y += dy; + } + return i; +} + +const int transformed_image_width = 128; +const int transformed_image_height = 128; + +void tst_QImage::transformed_data() +{ + QTest::addColumn<QTransform>("transform"); + + { + QTransform transform; + transform.translate(10.4, 10.4); + QTest::newRow("Translate") << transform; + } + { + QTransform transform; + transform.scale(1.5, 1.5); + QTest::newRow("Scale") << transform; + } + { + QTransform transform; + transform.rotate(30); + QTest::newRow("Rotate 30") << transform; + } + { + QTransform transform; + transform.rotate(90); + QTest::newRow("Rotate 90") << transform; + } + { + QTransform transform; + transform.rotate(180); + QTest::newRow("Rotate 180") << transform; + } + { + QTransform transform; + transform.rotate(270); + QTest::newRow("Rotate 270") << transform; + } + { + QTransform transform; + transform.translate(transformed_image_width/2, transformed_image_height/2); + transform.rotate(155, Qt::XAxis); + transform.translate(-transformed_image_width/2, -transformed_image_height/2); + QTest::newRow("Perspective 1") << transform; + } + { + QTransform transform; + transform.rotate(155, Qt::XAxis); + transform.translate(-transformed_image_width/2, -transformed_image_height/2); + QTest::newRow("Perspective 2") << transform; + } +} + +void tst_QImage::transformed() +{ + QFETCH(QTransform, transform); + + QImage img(transformed_image_width, transformed_image_height, QImage::Format_ARGB32_Premultiplied); + QPainter p(&img); + p.fillRect(0, 0, img.width(), img.height(), Qt::red); + p.drawRect(0, 0, img.width()-1, img.height()-1); + p.end(); + + QImage transformed = img.transformed(transform, Qt::SmoothTransformation); + + // all borders should have touched pixels + + QVERIFY(count(transformed, 0, 0, 1, 0, 0x0) < transformed.width()); + QVERIFY(count(transformed, 0, 0, 0, 1, 0x0) < transformed.height()); + + QVERIFY(count(transformed, 0, img.height() - 1, 1, 0, 0x0) < transformed.width()); + QVERIFY(count(transformed, img.width() - 1, 0, 0, 1, 0x0) < transformed.height()); + + QImage transformedPadded(transformed.width() + 2, transformed.height() + 2, img.format()); + transformedPadded.fill(0x0); + + p.begin(&transformedPadded); + p.setRenderHint(QPainter::SmoothPixmapTransform); + p.setRenderHint(QPainter::Antialiasing); + p.setTransform(transformed.trueMatrix(transform, img.width(), img.height()) * QTransform().translate(1, 1)); + p.drawImage(0, 0, img); + p.end(); + + // no borders should have touched pixels since we have a one-pixel padding + + QCOMPARE(count(transformedPadded, 0, 0, 1, 0, 0x0), transformedPadded.width()); + QCOMPARE(count(transformedPadded, 0, 0, 0, 1, 0x0), transformedPadded.height()); + + QCOMPARE(count(transformedPadded, 0, transformedPadded.height() - 1, 1, 0, 0x0), transformedPadded.width()); + QCOMPARE(count(transformedPadded, transformedPadded.width() - 1, 0, 0, 1, 0x0), transformedPadded.height()); +} + +void tst_QImage::transformed2() +{ + QImage img(3, 3, QImage::Format_Mono); + QPainter p(&img); + p.fillRect(0, 0, 3, 3, Qt::white); + p.fillRect(0, 0, 3, 3, Qt::Dense4Pattern); + p.end(); + + QTransform transform; + transform.scale(3, 3); + + QImage expected(9, 9, QImage::Format_Mono); + p.begin(&expected); + p.fillRect(0, 0, 9, 9, Qt::white); + p.setBrush(Qt::black); + p.setPen(Qt::NoPen); + p.drawRect(3, 0, 3, 3); + p.drawRect(0, 3, 3, 3); + p.drawRect(6, 3, 3, 3); + p.drawRect(3, 6, 3, 3); + p.end(); + + { + QImage actual = img.transformed(transform); + + QCOMPARE(actual.format(), expected.format()); + QCOMPARE(actual.size(), expected.size()); + QCOMPARE(actual, expected); + } + + { + transform.rotate(-90); + QImage actual = img.transformed(transform); + + QCOMPARE(actual.convertToFormat(QImage::Format_ARGB32_Premultiplied), + expected.convertToFormat(QImage::Format_ARGB32_Premultiplied)); + } +} + +void tst_QImage::scaled() +{ + QImage img(102, 3, QImage::Format_Mono); + QPainter p(&img); + p.fillRect(0, 0, img.width(), img.height(), Qt::white); + p.end(); + + QImage scaled = img.scaled(1994, 10); + + QImage expected(1994, 10, QImage::Format_Mono); + p.begin(&expected); + p.fillRect(0, 0, expected.width(), expected.height(), Qt::white); + p.end(); + + QCOMPARE(scaled, expected); +} + +void tst_QImage::paintEngine() +{ + QImage img; + + QPaintEngine *engine; + { + QImage temp(100, 100, QImage::Format_RGB32); + temp.fill(0xff000000); + + QPainter p(&temp); + p.fillRect(80,80,10,10,Qt::blue); + p.end(); + + img = temp; + + engine = temp.paintEngine(); + } + + { + QPainter p(&img); + + p.fillRect(80,10,10,10,Qt::yellow); + p.end(); + } + + QImage expected(100, 100, QImage::Format_RGB32); + expected.fill(0xff000000); + + QPainter p(&expected); + p.fillRect(80,80,10,10,Qt::blue); + p.fillRect(80,10,10,10,Qt::yellow); + p.end(); + + QCOMPARE(engine, img.paintEngine()); + QCOMPARE(img, expected); +} + +void tst_QImage::setAlphaChannelWhilePainting() +{ + QImage image(100, 100, QImage::Format_ARGB32); + image.fill(Qt::black); + QPainter p(&image); + + image.setAlphaChannel(image.createMaskFromColor(QColor(Qt::black).rgb(), Qt::MaskInColor)); +} + + +// See task 240047 for details +void tst_QImage::smoothScaledSubImage() +{ + QImage original(128, 128, QImage::Format_RGB32); + QPainter p(&original); + p.fillRect(0, 0, 64, 128, Qt::black); + p.fillRect(64, 0, 64, 128, Qt::white); + p.end(); + + QImage subimage(((const QImage &) original).bits(), 32, 32, original.bytesPerLine(), QImage::Format_RGB32); // only in the black part of the source... + + QImage scaled = subimage.scaled(8, 8, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + for (int y=0; y<scaled.height(); ++y) + for (int x=0; x<scaled.width(); ++x) + QCOMPARE(scaled.pixel(x, y), 0xff000000); +} + +void tst_QImage::nullSize_data() +{ + QTest::addColumn<QImage>("image"); + QTest::newRow("null image") << QImage(); + QTest::newRow("zero-size image") << QImage(0, 0, QImage::Format_RGB32); +} + +void tst_QImage::nullSize() +{ + QFETCH(QImage, image); + QCOMPARE(image.isNull(), true); + QCOMPARE(image.width(), image.size().width()); + QCOMPARE(image.height(), image.size().height()); +} + +void tst_QImage::premultipliedAlphaConsistency() +{ + QImage img(256, 1, QImage::Format_ARGB32); + for (int x = 0; x < 256; ++x) + img.setPixel(x, 0, (x << 24) | 0xffffff); + + QImage converted = img.convertToFormat(QImage::Format_ARGB8565_Premultiplied); + QImage pm32 = converted.convertToFormat(QImage::Format_ARGB32_Premultiplied); + + for (int i = 0; i < pm32.width(); ++i) { + QRgb pixel = pm32.pixel(i, 0); + QVERIFY(qRed(pixel) <= qAlpha(pixel)); + QVERIFY(qGreen(pixel) <= qAlpha(pixel)); + QVERIFY(qBlue(pixel) <= qAlpha(pixel)); + } +} + +void tst_QImage::compareIndexed() +{ + QImage img(256, 1, QImage::Format_Indexed8); + + QVector<QRgb> colorTable(256); + for (int i = 0; i < 256; ++i) + colorTable[i] = qRgb(i, i, i); + img.setColorTable(colorTable); + + for (int i = 0; i < 256; ++i) { + img.setPixel(i, 0, i); + } + + QImage imgInverted(256, 1, QImage::Format_Indexed8); + QVector<QRgb> invertedColorTable(256); + for (int i = 0; i < 256; ++i) + invertedColorTable[255-i] = qRgb(i, i, i); + imgInverted.setColorTable(invertedColorTable); + + for (int i = 0; i < 256; ++i) { + imgInverted.setPixel(i, 0, (255-i)); + } + + QCOMPARE(img, imgInverted); +} + +void tst_QImage::fillColor_data() +{ + QTest::addColumn<QImage::Format>("format"); + QTest::addColumn<Qt::GlobalColor>("color"); + QTest::addColumn<uint>("pixelValue"); + + QTest::newRow("Mono, color0") << QImage::Format_Mono << Qt::color0 << 0u; + QTest::newRow("Mono, color1") << QImage::Format_Mono << Qt::color1 << 1u; + + QTest::newRow("MonoLSB, color0") << QImage::Format_MonoLSB << Qt::color0 << 0u; + QTest::newRow("MonoLSB, color1") << QImage::Format_MonoLSB << Qt::color1 << 1u; + + const char *names[] = { + "Indexed8", + "RGB32", + "ARGB32", + "ARGB32pm", + "RGB16", + "ARGB8565pm", + "RGB666", + "ARGB6666pm", + "RGB555", + "ARGB8555pm", + "RGB888", + "RGB444", + "ARGB4444pm", + 0 + }; + + QImage::Format formats[] = { + QImage::Format_Indexed8, + QImage::Format_RGB32, + QImage::Format_ARGB32, + QImage::Format_ARGB32_Premultiplied, + QImage::Format_RGB16, + QImage::Format_ARGB8565_Premultiplied, + QImage::Format_RGB666, + QImage::Format_ARGB6666_Premultiplied, + QImage::Format_RGB555, + QImage::Format_ARGB8555_Premultiplied, + QImage::Format_RGB888, + QImage::Format_RGB444, + QImage::Format_ARGB4444_Premultiplied + }; + + for (int i=0; names[i] != 0; ++i) { + QByteArray name; + name.append(names[i]).append(", "); + + QTest::newRow(QByteArray(name).append("black").constData()) << formats[i] << Qt::black << 0xff000000; + QTest::newRow(QByteArray(name).append("white").constData()) << formats[i] << Qt::white << 0xffffffff; + QTest::newRow(QByteArray(name).append("red").constData()) << formats[i] << Qt::red << 0xffff0000; + QTest::newRow(QByteArray(name).append("green").constData()) << formats[i] << Qt::green << 0xff00ff00; + QTest::newRow(QByteArray(name).append("blue").constData()) << formats[i] << Qt::blue << 0xff0000ff; + } + + QTest::newRow("RGB16, transparent") << QImage::Format_RGB16 << Qt::transparent << 0xff000000; + QTest::newRow("RGB32, transparent") << QImage::Format_RGB32 << Qt::transparent << 0xff000000; + QTest::newRow("ARGB32, transparent") << QImage::Format_ARGB32 << Qt::transparent << 0x00000000u; + QTest::newRow("ARGB32pm, transparent") << QImage::Format_ARGB32_Premultiplied << Qt::transparent << 0x00000000u; +} + +void tst_QImage::fillColor() +{ + QFETCH(QImage::Format, format); + QFETCH(Qt::GlobalColor, color); + QFETCH(uint, pixelValue); + + QImage image(1, 1, format); + + if (image.depth() == 8) { + QVector<QRgb> table; + table << 0xff000000; + table << 0xffffffff; + table << 0xffff0000; + table << 0xff00ff00; + table << 0xff0000ff; + image.setColorTable(table); + } + + image.fill(color); + if (image.depth() == 1) { + QCOMPARE(image.pixelIndex(0, 0), (int) pixelValue); + } else { + QCOMPARE(image.pixel(0, 0), pixelValue); + } + + image.fill(QColor(color)); + if (image.depth() == 1) { + QCOMPARE(image.pixelIndex(0, 0), (int) pixelValue); + } else { + QCOMPARE(image.pixel(0, 0), pixelValue); + } +} + +void tst_QImage::fillColorWithAlpha() +{ + QImage argb32(1, 1, QImage::Format_ARGB32); + argb32.fill(QColor(255, 0, 0, 127)); + QCOMPARE(argb32.pixel(0, 0), qRgba(255, 0, 0, 127)); + + QImage argb32pm(1, 1, QImage::Format_ARGB32_Premultiplied); + argb32pm.fill(QColor(255, 0, 0, 127)); + QCOMPARE(argb32pm.pixel(0, 0), 0x7f7f0000u); +} + +void tst_QImage::rgbSwapped_data() +{ + QTest::addColumn<QImage::Format>("format"); + + QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8; + QTest::newRow("Format_RGB32") << QImage::Format_RGB32; + QTest::newRow("Format_ARGB32") << QImage::Format_ARGB32; + QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("Format_RGB16") << QImage::Format_RGB16; + QTest::newRow("Format_ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied; + QTest::newRow("Format_ARGB6666_Premultiplied") << QImage::Format_ARGB6666_Premultiplied; + QTest::newRow("Format_ARGB4444_Premultiplied") << QImage::Format_ARGB4444_Premultiplied; + QTest::newRow("Format_RGB666") << QImage::Format_RGB666; + QTest::newRow("Format_RGB555") << QImage::Format_RGB555; + QTest::newRow("Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied; + QTest::newRow("Format_RGB888") << QImage::Format_RGB888; + QTest::newRow("Format_RGB444") << QImage::Format_RGB444; +} + +void tst_QImage::rgbSwapped() +{ + QFETCH(QImage::Format, format); + + QImage image(100, 1, format); + image.fill(0); + + QVector<QColor> testColor(image.width()); + + for (int i = 0; i < image.width(); ++i) + testColor[i] = QColor(i, 10 + i, 20 + i * 2, 30 + i); + + if (format != QImage::Format_Indexed8) { + QPainter p(&image); + p.setCompositionMode(QPainter::CompositionMode_Source); + for (int i = 0; i < image.width(); ++i) + p.fillRect(QRect(i, 0, 1, 1), testColor[i].rgb()); + } else { + image.setColorCount(image.width()); + for (int i = 0; i < image.width(); ++i) { + image.setColor(0, testColor[i].rgba()); + image.setPixel(i, 0, i); + } + } + + QImage imageSwapped = image.rgbSwapped(); + + for (int i = 0; i < image.width(); ++i) { + QColor referenceColor = QColor(image.pixel(i, 0)); + QColor swappedColor = QColor(imageSwapped.pixel(i, 0)); + + QCOMPARE(swappedColor.alpha(), referenceColor.alpha()); + QCOMPARE(swappedColor.red(), referenceColor.blue()); + QCOMPARE(swappedColor.green(), referenceColor.green()); + QCOMPARE(swappedColor.blue(), referenceColor.red()); + } + + QImage imageSwappedTwice = imageSwapped.rgbSwapped(); + + QCOMPARE(image, imageSwappedTwice); + + QCOMPARE(memcmp(image.constBits(), imageSwappedTwice.constBits(), image.byteCount()), 0); +} + +void tst_QImage::deepCopyWhenPaintingActive() +{ + QImage image(64, 64, QImage::Format_ARGB32_Premultiplied); + image.fill(0); + + QPainter painter(&image); + QImage copy = image; + + painter.setBrush(Qt::black); + painter.drawEllipse(image.rect()); + + QVERIFY(copy != image); +} + +void tst_QImage::scaled_QTBUG19157() +{ + QImage foo(5000, 1, QImage::Format_RGB32); + foo = foo.scaled(1024, 1024, Qt::KeepAspectRatio); + QVERIFY(!foo.isNull()); +} + +QTEST_MAIN(tst_QImage) +#include "tst_qimage.moc" diff --git a/tests/auto/gui/image/qimageiohandler/.gitignore b/tests/auto/gui/image/qimageiohandler/.gitignore new file mode 100644 index 0000000000..6ea7bdb667 --- /dev/null +++ b/tests/auto/gui/image/qimageiohandler/.gitignore @@ -0,0 +1 @@ +tst_qimageiohandler diff --git a/tests/auto/gui/image/qimageiohandler/qimageiohandler.pro b/tests/auto/gui/image/qimageiohandler/qimageiohandler.pro new file mode 100644 index 0000000000..46e5cfb2cf --- /dev/null +++ b/tests/auto/gui/image/qimageiohandler/qimageiohandler.pro @@ -0,0 +1,9 @@ +############################################################ +# Project file for autotest for file qimageiohandler.h +############################################################ + +load(qttest_p4) + +SOURCES += tst_qimageiohandler.cpp + + diff --git a/tests/auto/gui/image/qimageiohandler/tst_qimageiohandler.cpp b/tests/auto/gui/image/qimageiohandler/tst_qimageiohandler.cpp new file mode 100644 index 0000000000..dd132302f8 --- /dev/null +++ b/tests/auto/gui/image/qimageiohandler/tst_qimageiohandler.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qdebug.h> +#include <qimageiohandler.h> +#include <qfile.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QImageIOHandler : public QObject +{ +Q_OBJECT + +public: + tst_QImageIOHandler(); + virtual ~tst_QImageIOHandler(); + +private slots: + void getSetCheck(); +}; + +class MyImageIOHandler : public QImageIOHandler +{ +public: + MyImageIOHandler() : QImageIOHandler() { } + bool canRead() const { return true; } + bool read(QImage *) { return true; } +}; + +tst_QImageIOHandler::tst_QImageIOHandler() +{ +} + +tst_QImageIOHandler::~tst_QImageIOHandler() +{ +} + +// Testing get/set functions +void tst_QImageIOHandler::getSetCheck() +{ + MyImageIOHandler obj1; + // QIODevice * QImageIOHandler::device() + // void QImageIOHandler::setDevice(QIODevice *) + QFile *var1 = new QFile; + obj1.setDevice(var1); + QCOMPARE(obj1.device(), (QIODevice *)var1); + obj1.setDevice((QIODevice *)0); + QCOMPARE(obj1.device(), (QIODevice *)0); + delete var1; +} + +QTEST_MAIN(tst_QImageIOHandler) +#include "tst_qimageiohandler.moc" diff --git a/tests/auto/gui/image/qimagereader/.gitignore b/tests/auto/gui/image/qimagereader/.gitignore new file mode 100644 index 0000000000..fdf03f239d --- /dev/null +++ b/tests/auto/gui/image/qimagereader/.gitignore @@ -0,0 +1,2 @@ +tst_qimagereader +junk diff --git a/tests/auto/gui/image/qimagereader/baseline/35floppy.png b/tests/auto/gui/image/qimagereader/baseline/35floppy.png Binary files differnew file mode 100644 index 0000000000..56b9b44c47 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/baseline/35floppy.png diff --git a/tests/auto/gui/image/qimagereader/baseline/connect.png b/tests/auto/gui/image/qimagereader/baseline/connect.png Binary files differnew file mode 100644 index 0000000000..9544bb9c76 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/baseline/connect.png diff --git a/tests/auto/gui/image/qimagereader/baseline/kde_favicon.png b/tests/auto/gui/image/qimagereader/baseline/kde_favicon.png Binary files differnew file mode 100644 index 0000000000..e19287b49d --- /dev/null +++ b/tests/auto/gui/image/qimagereader/baseline/kde_favicon.png diff --git a/tests/auto/gui/image/qimagereader/baseline/semitransparent.png b/tests/auto/gui/image/qimagereader/baseline/semitransparent.png Binary files differnew file mode 100644 index 0000000000..a3ad780699 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/baseline/semitransparent.png diff --git a/tests/auto/gui/image/qimagereader/images/16bpp.bmp b/tests/auto/gui/image/qimagereader/images/16bpp.bmp Binary files differnew file mode 100644 index 0000000000..74ce63edd4 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/16bpp.bmp diff --git a/tests/auto/gui/image/qimagereader/images/4bpp-rle.bmp b/tests/auto/gui/image/qimagereader/images/4bpp-rle.bmp Binary files differnew file mode 100644 index 0000000000..ae71e678fd --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/4bpp-rle.bmp diff --git a/tests/auto/gui/image/qimagereader/images/YCbCr_cmyk.jpg b/tests/auto/gui/image/qimagereader/images/YCbCr_cmyk.jpg Binary files differnew file mode 100644 index 0000000000..b8aa9ea609 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/YCbCr_cmyk.jpg diff --git a/tests/auto/gui/image/qimagereader/images/YCbCr_cmyk.png b/tests/auto/gui/image/qimagereader/images/YCbCr_cmyk.png Binary files differnew file mode 100644 index 0000000000..a24db1b13f --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/YCbCr_cmyk.png diff --git a/tests/auto/gui/image/qimagereader/images/YCbCr_rgb.jpg b/tests/auto/gui/image/qimagereader/images/YCbCr_rgb.jpg Binary files differnew file mode 100644 index 0000000000..8771224cb5 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/YCbCr_rgb.jpg diff --git a/tests/auto/gui/image/qimagereader/images/away.png b/tests/auto/gui/image/qimagereader/images/away.png Binary files differnew file mode 100644 index 0000000000..0e21a37883 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/away.png diff --git a/tests/auto/gui/image/qimagereader/images/ball.mng b/tests/auto/gui/image/qimagereader/images/ball.mng Binary files differnew file mode 100644 index 0000000000..81544780fd --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/ball.mng diff --git a/tests/auto/gui/image/qimagereader/images/bat1.gif b/tests/auto/gui/image/qimagereader/images/bat1.gif Binary files differnew file mode 100644 index 0000000000..cb6f4f7a8e --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/bat1.gif diff --git a/tests/auto/gui/image/qimagereader/images/bat2.gif b/tests/auto/gui/image/qimagereader/images/bat2.gif Binary files differnew file mode 100644 index 0000000000..fbbda4ef76 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/bat2.gif diff --git a/tests/auto/gui/image/qimagereader/images/beavis.jpg b/tests/auto/gui/image/qimagereader/images/beavis.jpg Binary files differnew file mode 100644 index 0000000000..d55504779b --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/beavis.jpg diff --git a/tests/auto/gui/image/qimagereader/images/black.png b/tests/auto/gui/image/qimagereader/images/black.png Binary files differnew file mode 100644 index 0000000000..6c94085ed5 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/black.png diff --git a/tests/auto/gui/image/qimagereader/images/black.xpm b/tests/auto/gui/image/qimagereader/images/black.xpm new file mode 100644 index 0000000000..d7925bf211 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/black.xpm @@ -0,0 +1,65 @@ +/* XPM */ +static char * ddd_xpm[] = { +/* $Id: ddd.xpm,v 1.5 1999/08/19 11:30:07 andreas Exp $ + * DDD Logo. Copyright (C) 1997 TU Braunschweig, Germany. + * For details on DDD, see `http://www.gnu.org/software/ddd/'. + * width height ncolors chars_per_pixel */ +" 48 48 8 1", +/* Colors */ +" c None m None g None g4 None s Background ", +". c black m black g black g4 black s Legs ", +"X c grey m white g grey g4 grey s Body ", +"- c grey m white g grey g4 grey s Border ", +"o c #000040 m black g grey25 g4 grey25 s Handle1 ", +"O c blue4 m black g grey25 g4 grey25 s Handle2 ", +"+ c white m white g white g4 white s Light ", +"* c DarkGreen m black g grey25 g4 grey25 s Eye ", +/* Pixels */ +" . . ", +" . .. ", +" . . ", +" .. . ", +" .. .. .. ", +" .. . . . ", +" . . . . .. ", +" . .X. . ", +" . *.X.* .. ", +" .. .. .XXX. .. ... ", +" . .X...XXX...X. . ", +" .. ..XXX.XXX.XXX. .. ", +" .....XXXX...XXXX. . ", +" .. ..XXXXXXXXX.. .. ", +" ...XXXXXXX..... ", +" ......... ", +" .XXXXXXX. ", +" .....XXX..... ", +" .XXXXXoOOOOOOX. ... ", +" .. ..XXXoOOO-----OOO..... ", +" .........XXoO-----..----O .. ", +" .. ..X..oO--.........--O .. ", +" . ..XXXoO--..++.......--O .. ", +" .. .XXXXO-XXX+++XXXXXXXXX-O . ", +" .. .....oO-XX+++XXXXXXXXXXX-O .. ", +" .. .XXXoO--XX++XXXXXXXXXXXX-O .. ", +" .. ..XXXoO-..+++............-O .. ", +" . .. .XXoO--..++.............-OO .. ", +" . ... ...oO--..................-O ", +".. . .XXoO-XXXXXXXXXXXXXXXXXXX-O ", +" .. .XXoO-XXXXXXXXXXXXXXXXXXX-O ", +" .. .XoO-XXXXXXXXXXXXXXXXXXX-O. ", +" . ...oO-.................-O .. ", +" . .XXoO-.................-O .. ", +" . ..XoO-.................-O .. ", +" . ...oO-XXXXXXXXXXXXXXX-OOO . ", +" .. .XoOO-XXXXXXXXXXXXX-OOOOO . ", +" .. ..XoOO---.......---OOOOOO . ", +" .. ....oOO---...----OOOOOOOO ", +" . .XX..oOO-----OOOOOOOOOOO ", +" . .....OOOOOOOOooOOOOOOOOO ", +" . .XXooooooOo oOOOOOOOOO ", +" . .XXX. ooOOOOOOO ", +" .. ... ooOOOOOO ", +" . ooOOOOOO ", +" ooOOOOOO ", +" ooOOOOOO ", +" ooOOOOOO "}; diff --git a/tests/auto/gui/image/qimagereader/images/colorful.bmp b/tests/auto/gui/image/qimagereader/images/colorful.bmp Binary files differnew file mode 100644 index 0000000000..8ea6f4acd7 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/colorful.bmp diff --git a/tests/auto/gui/image/qimagereader/images/corrupt-colors.xpm b/tests/auto/gui/image/qimagereader/images/corrupt-colors.xpm new file mode 100644 index 0000000000..f8d80edbbc --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt-colors.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static const char *marble_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 240 240 223 2", +/* colors */ +".. c #959595", +".# c #c5c5c5", +".a c #adadad", +".b c #dedede", +".c c #b7b7b7", +".d c #d2d2d2", +".e c #bebebe", +".f c #c9c9c9", +".g c #b8b8b8", +".h c #d6d6d6", +".i c #9e9e9e", +".j c #eaeaea", +".k c #b2b2b2", +".l c #cecece", +".m c #a5a5a5", +".n c #e4e4e4", +".o c #c4c4c4", +".p c #d9d9d9", +".q c #b1b1b1", +/* pixels */ +"aYbla9aN.N#x", diff --git a/tests/auto/gui/image/qimagereader/images/corrupt-data.tif b/tests/auto/gui/image/qimagereader/images/corrupt-data.tif Binary files differnew file mode 100644 index 0000000000..d63c688b27 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt-data.tif diff --git a/tests/auto/gui/image/qimagereader/images/corrupt-pixel-count.xpm b/tests/auto/gui/image/qimagereader/images/corrupt-pixel-count.xpm new file mode 100644 index 0000000000..3a736ff262 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt-pixel-count.xpm @@ -0,0 +1,11 @@ +/* XPM */ +static const char *marble_xpm[] = { +/* width height num_colors chars_per_pixel */ +"2 2 2 -2", +/* colors */ +"a c #adadad", +"b c #dedede", +/* pixels */ +"ab", +"ba" +}; diff --git a/tests/auto/gui/image/qimagereader/images/corrupt-pixels.xpm b/tests/auto/gui/image/qimagereader/images/corrupt-pixels.xpm new file mode 100644 index 0000000000..21031ee604 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt-pixels.xpm @@ -0,0 +1,7 @@ +/* XPM */ +static char * test_xpm[] = { +"256 256 1 1", +" c grey", +" ", +" ", +" "}; diff --git a/tests/auto/gui/image/qimagereader/images/corrupt.bmp b/tests/auto/gui/image/qimagereader/images/corrupt.bmp Binary files differnew file mode 100644 index 0000000000..824190bdeb --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt.bmp diff --git a/tests/auto/gui/image/qimagereader/images/corrupt.gif b/tests/auto/gui/image/qimagereader/images/corrupt.gif Binary files differnew file mode 100644 index 0000000000..07259454c9 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt.gif diff --git a/tests/auto/gui/image/qimagereader/images/corrupt.jpg b/tests/auto/gui/image/qimagereader/images/corrupt.jpg Binary files differnew file mode 100644 index 0000000000..1959662922 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt.jpg diff --git a/tests/auto/gui/image/qimagereader/images/corrupt.mng b/tests/auto/gui/image/qimagereader/images/corrupt.mng Binary files differnew file mode 100644 index 0000000000..17fd43a5ca --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt.mng diff --git a/tests/auto/gui/image/qimagereader/images/corrupt.png b/tests/auto/gui/image/qimagereader/images/corrupt.png Binary files differnew file mode 100644 index 0000000000..9d8911c64e --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt.png diff --git a/tests/auto/gui/image/qimagereader/images/corrupt.svg b/tests/auto/gui/image/qimagereader/images/corrupt.svg new file mode 100644 index 0000000000..8747df008f --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt.svg @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + width="40px" + height="5px" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docname="test.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + inkscape:window-height="1005" +
\ No newline at end of file diff --git a/tests/auto/gui/image/qimagereader/images/corrupt.svgz b/tests/auto/gui/image/qimagereader/images/corrupt.svgz Binary files differnew file mode 100644 index 0000000000..67fdceee0b --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt.svgz diff --git a/tests/auto/gui/image/qimagereader/images/corrupt.xbm b/tests/auto/gui/image/qimagereader/images/corrupt.xbm new file mode 100644 index 0000000000..8510634e6d --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/corrupt.xbm @@ -0,0 +1,5 @@ +#define noname_width 271 +#define noname_height 273 +static char noname_bits[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f}; diff --git a/tests/auto/gui/image/qimagereader/images/crash-signed-char.bmp b/tests/auto/gui/image/qimagereader/images/crash-signed-char.bmp Binary files differnew file mode 100644 index 0000000000..b35cda6c35 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/crash-signed-char.bmp diff --git a/tests/auto/gui/image/qimagereader/images/earth.gif b/tests/auto/gui/image/qimagereader/images/earth.gif Binary files differnew file mode 100644 index 0000000000..2c229eb110 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/earth.gif diff --git a/tests/auto/gui/image/qimagereader/images/endless-anim.gif b/tests/auto/gui/image/qimagereader/images/endless-anim.gif Binary files differnew file mode 100644 index 0000000000..00df8da786 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/endless-anim.gif diff --git a/tests/auto/gui/image/qimagereader/images/fire.mng b/tests/auto/gui/image/qimagereader/images/fire.mng Binary files differnew file mode 100644 index 0000000000..c6695c8369 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/fire.mng diff --git a/tests/auto/gui/image/qimagereader/images/font.bmp b/tests/auto/gui/image/qimagereader/images/font.bmp Binary files differnew file mode 100644 index 0000000000..28b8c66924 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/font.bmp diff --git a/tests/auto/gui/image/qimagereader/images/four-frames.gif b/tests/auto/gui/image/qimagereader/images/four-frames.gif Binary files differnew file mode 100644 index 0000000000..6aff2e0af2 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/four-frames.gif diff --git a/tests/auto/gui/image/qimagereader/images/gnus.xbm b/tests/auto/gui/image/qimagereader/images/gnus.xbm new file mode 100644 index 0000000000..58d1ac845a --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/gnus.xbm @@ -0,0 +1,622 @@ +#define noname_width 271 +#define noname_height 273 +static char noname_bits[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x49,0xe0,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x97,0xaa,0x8a,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x57,0x2a,0x41,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0x52,0x16,0xfe,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4a,0x49,0x05, + 0xf9,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0x95,0xaa,0x58,0xf4,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xa5,0x54,0x26,0xe1,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x54,0x49,0x49,0xe4,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x2a,0xa5, + 0x2a,0xd1,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0xd5,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xaf,0x52,0x95,0x54,0xc4,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab, + 0x24,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x57,0x29,0xa9,0x92,0x11,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x57,0xd5,0xfa,0xff,0xff,0xab,0xea,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x4a,0x55,0x2a,0x41,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x25,0x29,0xe5,0xff,0xff,0x95,0xa4,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa7,0xa4, + 0x24,0xa5,0x14,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4a,0xa5,0xd4,0xff, + 0x3f,0x52,0xa9,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x29,0x55,0x55,0x55,0x41,0x7e,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xa9,0x54,0xea,0xff,0xdf,0x2a,0x55,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55,0x4a,0x49,0x12,0x7e,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0x55,0xa5,0x92,0xff,0x23,0xa5,0x4a,0xd6,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa5,0xa4,0x94,0xaa,0x42, + 0x7d,0xff,0xff,0xff,0xff,0xff,0xff,0x9f,0x4a,0x2a,0xa9,0xff,0xad,0x92,0x24, + 0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2a, + 0x95,0x52,0x52,0x29,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x52,0x49,0x55, + 0xfe,0x91,0x54,0x55,0x55,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0x49,0x29,0x55,0x25,0x85,0x7c,0xff,0xff,0xff,0xff,0xff,0xff, + 0x4f,0x95,0xaa,0x92,0x7e,0x55,0x55,0xa9,0x4a,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2a,0x50,0x95,0xaa,0x24,0x7e,0xff,0xff, + 0xff,0xff,0xff,0xff,0x57,0x2a,0x95,0x54,0x79,0x95,0x92,0x92,0x94,0xfc,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xb9,0x62,0x29,0x49, + 0x85,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x49,0x49,0x95,0xba,0xa4,0x54, + 0xaa,0x52,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf, + 0x1a,0xf8,0xa7,0xaa,0x22,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55,0x52, + 0x2a,0x75,0x55,0xa5,0x24,0xa5,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xbf,0x5a,0xfd,0x57,0x92,0x94,0x7e,0xff,0xff,0xff,0xff,0xff, + 0xff,0x4a,0x4a,0x55,0x49,0x89,0x92,0x94,0xaa,0x94,0xf4,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x1a,0xfc,0x2f,0x55,0x05,0x7c,0xff, + 0xff,0xff,0xff,0xff,0xff,0x55,0xa9,0x4a,0x55,0x2a,0x55,0x55,0x55,0x55,0xe5, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x4e,0xfd,0x5f, + 0x29,0xa5,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0xa4,0x54,0x52,0x4a,0x55,0xa9, + 0xa4,0x24,0xa5,0x94,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x2f,0x1d,0xfe,0x3f,0x95,0x04,0x7c,0xff,0xfd,0xff,0xff,0xff,0x3f,0x49,0xa5, + 0x54,0xa9,0xa4,0x92,0x4a,0x49,0x4a,0x55,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xaf,0x44,0xfe,0x5f,0xa9,0x52,0x7d,0xff,0xe5,0xff,0xff, + 0xff,0x5f,0x55,0x92,0x2a,0x95,0x52,0x4a,0x52,0xaa,0x52,0x4a,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x16,0xff,0xbf,0x4a,0x05,0x7c, + 0xff,0xd9,0xff,0xff,0xff,0x5f,0x95,0x42,0xa5,0x52,0x95,0xaa,0xaa,0xaa,0x94, + 0x54,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x43,0xfe, + 0xbf,0x54,0x52,0x7d,0x7f,0x25,0xff,0xff,0xff,0xa7,0xa4,0x28,0x92,0x54,0x4a, + 0xa5,0x4a,0x92,0xaa,0x4a,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xab,0x12,0xfe,0x7f,0xa5,0x02,0x7c,0x7f,0x55,0xfd,0xff,0xff,0x95,0x2a, + 0x82,0x54,0xa5,0x54,0x2a,0xa9,0x2a,0xa5,0x52,0xf5,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x27,0x4b,0xff,0xff,0x4a,0x29,0x7d,0xff,0x92,0xfe, + 0xff,0xff,0x55,0x92,0x20,0xa8,0x94,0x2a,0xa5,0x94,0x52,0x29,0xa9,0xf4,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x01,0xff,0x7f,0x52,0x42, + 0x7c,0xff,0x25,0xf9,0xff,0x7f,0xaa,0x02,0x8a,0x40,0x29,0x49,0x09,0x41,0x4a, + 0x55,0x25,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x57, + 0xff,0xff,0x95,0x12,0x7d,0xff,0xa9,0xfa,0xff,0x7f,0x25,0xa9,0x20,0x2a,0xa5, + 0xaa,0x42,0x92,0x54,0x92,0x54,0x95,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xaf,0x83,0xff,0xff,0xa9,0x42,0x7e,0xff,0xaa,0xf4,0xff,0xaf,0x54, + 0x01,0x82,0x80,0xaa,0x54,0x14,0x08,0xa2,0xaa,0x4a,0xd2,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xef,0xcf,0xd7,0xff,0xff,0x52,0x12,0x7f,0xff,0x4a, + 0xea,0xff,0x57,0x92,0xaa,0x28,0x24,0x29,0x25,0x81,0x82,0x08,0x49,0x52,0x55, + 0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xdf,0xef,0xe7,0xff,0xff,0x2a, + 0x05,0x7e,0xff,0x55,0xd5,0xff,0xa5,0x2a,0x00,0x8e,0x10,0x4a,0x89,0x24,0x28, + 0xa0,0xaa,0x2a,0x49,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xe7,0xff, + 0xef,0xff,0xff,0xa5,0x50,0x7e,0xff,0x25,0xe5,0xff,0x2a,0xa5,0x52,0x7f,0x85, + 0x54,0x35,0x08,0x82,0x0a,0x55,0x95,0xaa,0xfc,0xff,0xff,0xff,0xcf,0xff,0xff, + 0xff,0xff,0xd7,0xff,0xff,0xff,0x7f,0x52,0x85,0x7e,0xff,0xab,0x94,0x1e,0x55, + 0x2a,0xc8,0xff,0x10,0x90,0x92,0xa0,0x08,0x20,0x24,0x52,0x25,0xfd,0xff,0xff, + 0xff,0xef,0xff,0xff,0xff,0xff,0xe9,0xff,0xff,0xff,0xff,0x94,0x10,0x7e,0xff, + 0x93,0xaa,0x6a,0x49,0x49,0xf2,0xff,0x85,0x52,0x09,0x0a,0xa2,0x4a,0x92,0x29, + 0xa9,0xf2,0xff,0xff,0xff,0xd3,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0x7f, + 0x55,0x25,0x7f,0xff,0x55,0x49,0x49,0x95,0x0a,0xf9,0xff,0x17,0x48,0x26,0x50, + 0x08,0x00,0xa9,0x4a,0x95,0xfa,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xf2, + 0xff,0xff,0xff,0xff,0x92,0x80,0x7e,0xff,0xa7,0x54,0xaa,0xa4,0x52,0xfc,0xff, + 0xaf,0x42,0x89,0xfa,0xbf,0x54,0x20,0xa9,0xa4,0xd4,0xff,0xff,0xff,0xcb,0xff, + 0xff,0xff,0xff,0xf5,0xff,0xff,0xff,0xff,0x54,0x29,0x7f,0xff,0x4b,0xa5,0x92, + 0x2a,0x01,0xff,0xff,0x1f,0xa8,0x22,0xff,0xff,0x01,0xa5,0x2a,0x55,0xa9,0xff, + 0xff,0xff,0xd4,0xff,0xff,0xff,0x7f,0xfa,0xff,0xff,0xff,0x7f,0xa5,0x04,0x7f, + 0xff,0x57,0x2a,0x55,0xa9,0x54,0xfe,0xff,0x3f,0x05,0x89,0xff,0xff,0x5f,0x48, + 0x92,0x2a,0x95,0xff,0xff,0xff,0xea,0xff,0xff,0xff,0xff,0xd2,0xff,0xff,0xff, + 0x7f,0x2a,0x91,0x7f,0xff,0xa9,0x54,0x4a,0x52,0x02,0xff,0xff,0xff,0x50,0xd1, + 0xff,0xff,0x1f,0x81,0xaa,0xa4,0x52,0xfe,0xff,0x3f,0xe9,0xff,0xff,0xff,0x7f, + 0x1d,0xff,0xff,0xff,0xff,0x54,0x41,0x7f,0xff,0x93,0x92,0x52,0x95,0xc8,0xff, + 0xff,0xff,0x8b,0xc4,0xff,0xff,0x7f,0x24,0xa5,0x2a,0x49,0xf9,0xff,0x7f,0xd5, + 0xff,0xff,0xff,0xbf,0x4a,0xff,0xff,0xff,0xff,0x4a,0x14,0x7f,0xff,0x28,0xa5, + 0x94,0x2a,0xa0,0xff,0xff,0x7f,0x22,0xf0,0xff,0xff,0x7f,0x12,0x94,0xa4,0xaa, + 0xea,0xff,0xaf,0xea,0xff,0xff,0xff,0x5f,0x8e,0xff,0xff,0xff,0x7f,0xa9,0x40, + 0x7f,0xff,0x48,0x55,0x55,0x12,0xca,0xff,0xff,0xff,0x0a,0xf5,0xff,0xff,0xff, + 0x80,0x52,0x95,0x54,0xaa,0xfe,0x55,0xc4,0xff,0xff,0xff,0x5f,0xa5,0xff,0xff, + 0xff,0xff,0x94,0x14,0x7f,0xff,0x52,0x2a,0xa9,0x4a,0xe1,0xff,0xff,0xbf,0x24, + 0xf0,0xff,0xff,0xff,0x0b,0x28,0xa9,0x92,0x24,0x55,0x49,0xe5,0xd7,0xff,0xff, + 0xa7,0x8a,0xff,0xff,0xff,0x7f,0xa5,0xc0,0x7f,0xff,0x50,0x49,0x95,0x04,0xf8, + 0xff,0xff,0x5f,0x1f,0xfd,0xff,0xff,0xff,0x47,0x45,0x55,0xaa,0xaa,0x4a,0xaa, + 0xea,0xaf,0xff,0xff,0x2b,0xc3,0xff,0xff,0xff,0x7f,0x55,0x94,0x7f,0x7f,0x4a, + 0x55,0x52,0x51,0xfe,0xff,0xff,0x5f,0x4e,0xf8,0xff,0xff,0xff,0x1f,0x50,0x92, + 0x52,0x49,0xa9,0x92,0xe4,0xd3,0xff,0xff,0x4b,0xd5,0xff,0xff,0xff,0xff,0x94, + 0xc0,0x7f,0x3f,0xa0,0xa4,0xaa,0x04,0xfe,0xff,0xff,0xa7,0x1d,0xfd,0xff,0xff, + 0xff,0x9f,0x84,0xaa,0x4a,0xaa,0x24,0x55,0xf2,0x2b,0xff,0x7f,0xa9,0xc1,0xff, + 0xff,0xff,0x7f,0x4a,0x95,0x7f,0xbf,0x2a,0x95,0x24,0x50,0xff,0xff,0xff,0x97, + 0x5e,0xfe,0xff,0xff,0xff,0x3f,0x92,0x24,0x95,0x92,0xaa,0xa4,0xf2,0xcb,0xff, + 0x5f,0xd5,0xe5,0xff,0xff,0xff,0xff,0x52,0x80,0x7f,0x3f,0xa0,0x52,0x15,0x85, + 0xff,0xff,0xff,0xd7,0x38,0xfe,0xff,0xff,0xff,0xff,0x20,0xaa,0x52,0x55,0x55, + 0x55,0xf9,0x29,0xfd,0xab,0xa4,0xf0,0xff,0xff,0xff,0x7f,0x29,0xa9,0x7f,0xff, + 0x42,0x25,0x49,0xe8,0xff,0xff,0xff,0x69,0x7a,0xff,0xff,0xff,0xff,0xff,0x82, + 0x52,0xaa,0x24,0x89,0x4a,0xf8,0x55,0x2a,0x49,0x95,0xf5,0xff,0xff,0xff,0xbf, + 0x2a,0xc4,0x7f,0x7f,0x90,0x54,0x15,0xe2,0xff,0xff,0xff,0x25,0xbc,0xff,0xff, + 0xff,0xff,0xff,0x29,0x48,0x49,0xaa,0xaa,0xa4,0xfa,0x95,0x92,0x54,0x52,0xf0, + 0xff,0xff,0xff,0xbf,0x4a,0xd1,0x7f,0xff,0x05,0xaa,0x40,0xf8,0xff,0xff,0x7f, + 0xaa,0xfc,0xff,0xff,0xff,0xff,0xff,0x43,0xa9,0xaa,0x4a,0x52,0xa9,0xf8,0xa4, + 0xaa,0x52,0x95,0xfc,0xff,0xff,0xff,0x7f,0x52,0xc0,0x7f,0xff,0xa1,0x00,0x24, + 0xfa,0xff,0xff,0xff,0x0a,0xfe,0xff,0xff,0xff,0xff,0xff,0x17,0x92,0x24,0xa5, + 0x2a,0x55,0xfe,0xaa,0xa4,0x2a,0x29,0xf9,0xff,0xff,0xff,0xbf,0x2a,0xea,0x7f, + 0xff,0x05,0x92,0x90,0xfc,0xff,0xff,0xbf,0xa4,0xff,0xff,0xff,0xff,0xff,0xff, + 0x4f,0xa0,0xaa,0x54,0x49,0x25,0x7c,0x49,0x95,0xa4,0x12,0xfc,0xff,0xff,0xff, + 0x7f,0x8a,0xe0,0x7f,0xff,0xa3,0x04,0x05,0xfe,0xff,0xff,0xbf,0x06,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1f,0x49,0x95,0x52,0xaa,0x12,0x7f,0x55,0x52,0x55,0x0a, + 0xfd,0xff,0xff,0xff,0x3f,0x29,0xe8,0x7f,0xff,0x0f,0x50,0x50,0xff,0xff,0xff, + 0x5f,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x04,0xa9,0x4a,0x25,0x45,0x3e, + 0xa9,0x2a,0xa9,0xa2,0xfc,0xff,0xff,0xff,0x7f,0x55,0xe1,0x7f,0xff,0x27,0x05, + 0xc4,0xff,0xff,0xff,0x9f,0x91,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x41,0x4a, + 0x29,0xa9,0x12,0x5e,0x95,0x94,0x4a,0x0a,0xfe,0xff,0xff,0xff,0xbf,0x12,0xf4, + 0x7f,0xff,0x8f,0x50,0xf1,0xff,0xff,0xff,0xa7,0xc2,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x14,0x92,0xaa,0x4a,0xa2,0xbf,0xa4,0x52,0x95,0x22,0xff,0xff,0xff, + 0xff,0x3f,0x45,0xf2,0x7f,0xff,0x3f,0x04,0xf4,0xff,0xff,0xff,0xd7,0xe8,0xff, + 0xff,0xff,0xff,0x5f,0xff,0xff,0x83,0xa8,0x94,0x54,0x09,0x2f,0x55,0x4a,0x52, + 0x49,0xff,0xff,0xff,0xff,0x5f,0x99,0xf0,0x7f,0xff,0x7f,0x51,0xfc,0xff,0xff, + 0xff,0x6b,0xf1,0xff,0xff,0xff,0xff,0x5f,0xfd,0xff,0x2b,0x2a,0xa9,0x12,0x20, + 0x5f,0xa9,0xaa,0x54,0x00,0xff,0xff,0xff,0xff,0x5f,0x15,0xf2,0x7f,0xff,0xff, + 0x8f,0xff,0xff,0xff,0xff,0x2b,0xfc,0xff,0xff,0xff,0xff,0x2f,0xfd,0xff,0x87, + 0xa0,0x4a,0xaa,0x8a,0x9f,0x4a,0x52,0x15,0xa9,0xff,0xff,0xff,0xff,0x5f,0x8a, + 0xfc,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x94,0xf8,0xff,0xff,0xff,0xff, + 0x57,0xf2,0xff,0x2f,0x82,0x52,0x05,0xd0,0x2f,0x95,0x4a,0x49,0x84,0xff,0xff, + 0xff,0xff,0xbf,0x24,0xf8,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x12,0xfd, + 0xff,0xff,0xff,0xff,0x4b,0xd5,0xff,0x9f,0x28,0x54,0x48,0xc5,0xbf,0x52,0x55, + 0x0a,0xe1,0xff,0xff,0xff,0xff,0x9f,0x4a,0xfa,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1a,0xfe,0xff,0xff,0xff,0xff,0x57,0xa9,0xff,0x3f,0x82,0x00,0x21, + 0xf0,0x5f,0x2a,0x49,0x21,0xc4,0xff,0xff,0xff,0xff,0xaf,0x1a,0xfd,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0x3f,0x85,0xff,0xff,0xff,0xff,0xff,0x29,0xa5,0xff, + 0xff,0x24,0x52,0x88,0xfc,0xbf,0x92,0x2a,0x09,0xf1,0xff,0xff,0xff,0xff,0x9f, + 0x4c,0xfc,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x15,0xff,0xff,0xff,0x7f, + 0xff,0xa5,0x4a,0xff,0xff,0x90,0x08,0x01,0xfe,0x3f,0x55,0x52,0x24,0xf4,0xff, + 0xff,0xff,0xff,0xaf,0x02,0xfd,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xc6, + 0xff,0xff,0xff,0xbf,0xfe,0x95,0x54,0xff,0xff,0x05,0x42,0xa8,0xfe,0xbf,0xa4, + 0x2a,0x41,0xf9,0xff,0xff,0xff,0xff,0x5f,0x55,0xfc,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0x4f,0xd0,0xff,0xff,0xff,0xbf,0x7c,0xaa,0x92,0xfc,0xff,0x53,0x08, + 0x01,0xff,0x1f,0x4a,0x01,0x04,0xfc,0xff,0xff,0xff,0xff,0x27,0x05,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xc5,0xff,0xff,0xff,0x4f,0xbf,0x52,0xaa, + 0xfe,0xff,0x07,0x42,0xea,0xff,0xbf,0x50,0x54,0x51,0xff,0xff,0xff,0xff,0xff, + 0x97,0x56,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xf0,0xff,0xff,0xff, + 0x2f,0x7f,0xa5,0x54,0xfd,0xff,0x3f,0x09,0xe0,0xff,0x1f,0x02,0x01,0x04,0xff, + 0xff,0xff,0xff,0xff,0xaf,0x02,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x4b, + 0xf5,0xff,0xff,0xff,0xab,0x9f,0x94,0x92,0xfc,0xff,0xff,0x40,0xfd,0xff,0x9f, + 0x48,0x48,0xa1,0xff,0xff,0xff,0xff,0xff,0xa7,0x56,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0x6b,0xf8,0xff,0xff,0xff,0xa4,0x5f,0xa9,0x2a,0xfd,0xff,0xff, + 0xff,0xff,0xff,0x3f,0x22,0x21,0xc4,0xff,0xff,0xff,0xff,0xff,0x2f,0x03,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0xfa,0xff,0xff,0x7f,0xd5,0x2f,0xa5, + 0xa4,0xfa,0xff,0xff,0xff,0xff,0xff,0xbf,0x08,0x08,0xf9,0xff,0xff,0xff,0xff, + 0xff,0x97,0x4a,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x94,0xfc,0xff,0xff, + 0x7f,0x69,0xac,0x2a,0x55,0xf9,0xff,0xff,0xff,0xff,0xff,0x7f,0xa2,0x22,0xf8, + 0xff,0xff,0xff,0xff,0xff,0x53,0x21,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0x15,0xfe,0xff,0xff,0x9f,0x2a,0x95,0x94,0x92,0xf4,0xff,0xff,0xff,0xff,0xff, + 0xff,0x08,0x88,0xfe,0xff,0xff,0xff,0xff,0xff,0x57,0x8b,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xa9,0xfe,0xff,0xff,0x5f,0x52,0xbc,0x52,0x55,0xf5,0xff, + 0xff,0xff,0xff,0xff,0xff,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xa1, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x7f,0x0d,0xff,0xff,0xff,0x57,0x15,0x3f, + 0x55,0x49,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xc8,0xff,0xff,0xff,0xff, + 0xff,0xff,0xd7,0x89,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xbf,0xd6,0xff,0xff, + 0xff,0x4b,0x45,0x3f,0x49,0xaa,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf9, + 0xff,0xff,0xff,0xff,0xff,0xff,0xc9,0xe2,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0x3f,0x81,0xff,0xff,0xff,0x29,0x11,0x5f,0x28,0x55,0xf5,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0xc8,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0x5f,0xd6,0xff,0xff,0x7f,0xaa,0xc2,0x0f,0x55,0x49,0xea, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa5, + 0xe2,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x9f,0xe1,0xff,0xff,0xbf,0x4a,0xd1, + 0x5f,0x48,0xa5,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xe9,0xe0,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x27,0xf4,0xff, + 0xff,0xbf,0x94,0xc4,0x07,0x91,0x2a,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0xea,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xaf,0xf1,0xff,0xff,0x9f,0x52,0xe0,0x4b,0x44,0x52,0xe9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6a,0xe0,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0x4b,0xfc,0xff,0xff,0xab,0x2a,0xf5,0x0f,0x51,0xa5, + 0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x69,0xe5,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x55,0xf8,0xff,0xff,0x95,0x14, + 0xf0,0x5f,0x84,0x54,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0x75,0xf0,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x13,0xfd, + 0xff,0xff,0xa5,0x42,0xf9,0x7f,0x91,0x4a,0xf5,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb2,0xfa,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0x54,0xfe,0xff,0x7f,0x52,0x12,0xfa,0xff,0x20,0xa5,0xe4,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x34,0xf8,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0x25,0xff,0xff,0xaf,0xaa,0x48,0xfc,0xff,0x0b, + 0x29,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xb5,0xf8,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x52,0xff,0xff,0x2f,0x49, + 0x02,0xfe,0xff,0x43,0xaa,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x3f,0x3a,0xfa,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0x4a, + 0xff,0xff,0xa5,0x2a,0xa9,0xff,0xff,0x17,0x25,0xe9,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x9a,0xfc,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0x2a,0xff,0x7f,0x95,0x54,0x80,0xff,0xff,0x07,0xa9,0xea,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x1d,0xfc, + 0xff,0x7f,0xff,0xff,0xff,0xff,0x3f,0xa9,0xfe,0x7f,0xa9,0x12,0xe5,0xff,0xff, + 0x5f,0x4a,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x5f,0xad,0xfe,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0x95,0xea,0x97,0x54, + 0x4a,0xf0,0xff,0xff,0x1f,0xa8,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x5f,0x0e,0xfe,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f, + 0x52,0x55,0xa9,0x92,0x02,0xfd,0xff,0xff,0x5f,0x53,0xf5,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x5e,0xfe,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xbf,0x2a,0x49,0x4a,0x55,0x49,0xfc,0xff,0xff,0x3f,0x94,0xf8, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0x0f, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4f,0xa5,0xaa,0x92,0xa4,0x20,0xff,0xff, + 0xff,0xbf,0xa4,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x5f,0x57,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f,0x52,0x52,0xaa, + 0x2a,0x0a,0xff,0xff,0xff,0x7f,0x54,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x8f,0x07,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xa7,0x94,0x4a,0x55,0x4a,0xa0,0xff,0xff,0xff,0xff,0xa8,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x57,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0x2f,0x55,0xa9,0x92,0x12,0xe9,0xff,0xff,0xff,0x7f,0x24, + 0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf, + 0x87,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0xa5,0x4a,0xaa,0x44,0xf4,0xff, + 0xff,0xff,0xff,0x55,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0xab,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xab,0x94,0xa4, + 0x92,0x12,0xf9,0xff,0xff,0xff,0xff,0xa8,0xfa,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xab,0x83,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0x47,0xa9,0x2a,0x55,0x40,0xfc,0xff,0xff,0xff,0xff,0x25,0xf5,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xd7,0x97,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0x33,0x55,0xa9,0x24,0x15,0xfe,0xff,0xff,0xff,0xff, + 0x95,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff, + 0x93,0xc3,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0x25,0xa5,0x2a,0x40,0xff, + 0xff,0xff,0xff,0xff,0xa9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xff, + 0xff,0xff,0xff,0xff,0xe7,0xd5,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4b,0x92, + 0x54,0x92,0xd4,0xff,0xff,0xff,0xff,0xff,0x55,0xf5,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xe9,0xff,0xff,0xff,0xff,0xff,0xd5,0xc1,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0x97,0xaa,0x4a,0x05,0xe2,0xff,0xff,0xff,0xff,0xff,0x25,0xf1,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xfd,0xff,0xff,0xff,0xff,0xd5,0xea,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0x55,0x25,0xa1,0xf0,0xff,0xff,0xff,0xff, + 0xff,0x95,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe8,0xfa,0xff,0xff,0xff, + 0xff,0xea,0xe0,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xa7,0x24,0x59,0x04,0xfa, + 0xff,0xff,0xff,0xff,0xff,0xa9,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe2, + 0xfd,0xff,0xff,0xff,0xff,0xc9,0xe9,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4f, + 0x52,0x05,0xa1,0xfc,0xff,0xff,0xff,0xff,0xff,0xa5,0xfa,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x70,0xf9,0xff,0xff,0xff,0xff,0x74,0xe2,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0x47,0x95,0x92,0x04,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0xf8, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xe2,0xfa,0xff,0xff,0xff,0xff,0x72,0xe8, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x97,0xaa,0x20,0xd0,0xff,0xff,0xff,0xff, + 0xff,0xff,0x55,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xb8,0xfc,0xff,0xff, + 0xff,0xff,0xea,0xe2,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x07,0x04,0x82,0xc2, + 0xff,0xff,0xff,0xff,0xff,0xff,0x29,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x71,0xfd,0xff,0xff,0xff,0x7f,0x2a,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0x4f,0x91,0x28,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1f,0x54,0xfe,0xff,0xff,0xff,0x7f,0x75,0xf2,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0x27,0x44,0x82,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x29, + 0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0xb8,0xfc,0xff,0xff,0xff,0xbf,0x14, + 0xf1,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x0f,0x11,0x20,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x55,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x9a,0xfe,0xff, + 0xff,0xff,0x7f,0x5a,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f,0x40,0x85, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x09,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x4f,0x2d,0xfd,0xff,0xff,0xff,0x9f,0x12,0xf9,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0x3f,0x14,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0x07,0xa6,0xfe,0xff,0xff,0xff,0x5f,0x4d,0xfa,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0x40,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x09,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0x4b,0xfe,0xff,0xff,0xff,0xbf, + 0x2c,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xf5,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x43,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x57,0xff, + 0xff,0xff,0xff,0x5f,0x0a,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x89,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xd5,0xa9,0xff,0xff,0xff,0xff,0xaf,0x5a,0xfc,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa3,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x81,0x95,0xff,0xff,0xff,0xff,0x9f,0x06,0xfd,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0xa5,0xff,0xff,0xff,0xff, + 0x2f,0x95,0xfc,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0xea, + 0xff,0xff,0xff,0xff,0xaf,0x26,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd5,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xf5,0xf4,0xff,0xff,0xff,0xff,0xaf,0x86,0xfe,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc1,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0x70,0xe5,0xff,0xff,0xff,0xff,0x4f,0x2e,0xfe, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xb2,0xfa,0xff,0xff,0xff, + 0xff,0x57,0x83,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x78, + 0xf2,0xff,0xff,0xff,0xff,0xa7,0x22,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x5f,0x5d,0xfd,0xff,0xff,0xff,0xff,0x97,0x87,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x3c,0xfd,0xff,0xff,0xff,0xff,0x53,0xa3, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xac,0xfe,0xff,0xff, + 0xff,0xff,0x57,0x95,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, + 0x9e,0xfe,0xff,0xff,0xff,0xff,0x97,0x81,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0x57,0xfe,0xff,0xff,0xff,0xff,0xa9,0xa5,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xaf,0xff,0xff,0xff,0xff,0xff,0x4b, + 0x89,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0x93,0xff,0xff, + 0xff,0xff,0xff,0x95,0xa2,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x83,0xab,0xff,0xff,0xff,0xff,0xff,0xd3,0xc8,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff, + 0xff,0xff,0xff,0xff,0xe9,0xa5,0xff,0xff,0xff,0xff,0xff,0xa5,0xe1,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0xd5,0xff,0xff,0xff,0xff,0xff, + 0xd5,0xc8,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xea,0xea,0xff, + 0xff,0xff,0xff,0xff,0x14,0xc1,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xff,0xff, + 0xff,0xe0,0xe4,0xff,0xff,0xff,0xff,0xff,0x65,0xe8,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf, + 0xff,0xff,0xff,0xff,0x3f,0x72,0xe9,0xff,0xff,0xff,0xff,0xff,0x6a,0xe1,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xbf,0xb8,0xfa,0xff,0xff,0xff,0xff, + 0xff,0x52,0xea,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd3,0xff,0xff,0xff,0xff,0x1f,0x7a,0xf5, + 0xff,0xff,0xff,0xff,0x7f,0x2a,0xe0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff, + 0xff,0x8f,0x58,0xfa,0xff,0xff,0xff,0xff,0x7f,0x25,0xf5,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xb5,0xff,0xff,0xdf,0xff,0x57,0x5e,0xfd,0xff,0xff,0xff,0xff,0xff,0x34,0xe0, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xca,0xff,0xff,0x8f,0xff,0x07,0xac,0xfc,0xff,0xff,0xff, + 0xff,0x7f,0x2a,0xf5,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd4,0xff,0xff,0x57,0xff,0x2b,0x2d, + 0xfd,0xff,0xff,0xff,0xff,0xff,0xb2,0xf0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd2,0xff,0xff, + 0x07,0xff,0x43,0x4a,0xff,0xff,0xff,0xff,0xff,0xbf,0x2a,0xf8,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x3f,0xc5,0xff,0xff,0x2b,0xfe,0x08,0xab,0xfe,0xff,0xff,0xff,0xff,0x7f,0xaa, + 0xf2,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xbf,0xea,0xff,0xff,0x83,0x36,0x20,0x55,0xff,0xff,0xff, + 0xff,0xff,0x3f,0x15,0xf0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0xc2,0xff,0xff,0x48,0x4a,0x85, + 0x49,0xff,0xff,0xff,0xff,0xff,0x7f,0x59,0xfa,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0xf5,0xff, + 0x7f,0x10,0x29,0x50,0xa5,0xff,0xff,0xff,0xff,0xff,0x3f,0x15,0xf9,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x97,0xe4,0xff,0x7f,0x05,0x95,0x42,0xd5,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x35,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xab,0xea,0xff,0xbf,0xa0,0x24,0xa8,0xd4,0xff,0xff, + 0xff,0xff,0xff,0x7f,0x19,0xf9,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x27,0xe5,0xff,0x3f,0x92,0xaa, + 0x50,0xe9,0xff,0xff,0xff,0xff,0xff,0x9f,0x4a,0xfc,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0xe2, + 0xff,0x9f,0xa0,0xaa,0x2a,0xf5,0xff,0xff,0xff,0xff,0xff,0x5f,0x1a,0xf9,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x95,0xf8,0xff,0x5f,0x4a,0x92,0x4a,0xf5,0xff,0xff,0xff,0xff,0xff, + 0xbf,0x4a,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0x52,0xf2,0xff,0x1f,0x20,0x49,0xa5,0xfa,0xff, + 0xff,0xff,0xff,0xff,0x5f,0x1a,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaa,0xf8,0xff,0x47,0xa9, + 0x2a,0x29,0xf9,0xff,0xff,0xff,0xff,0xff,0xbf,0x0a,0xfc,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x49, + 0xf2,0xff,0x17,0x92,0xaa,0xaa,0xfe,0xff,0xff,0xff,0xff,0xff,0x9f,0xac,0xfe, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x9f,0x2a,0xf8,0xff,0x43,0xa8,0x24,0x25,0xff,0xff,0xff,0xff,0xff, + 0xff,0xaf,0x0a,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x94,0xfa,0xff,0x91,0x54,0xaa,0x52,0xff, + 0xff,0xff,0xff,0xff,0xff,0x2f,0x4d,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0x45,0xfc,0xff,0x03, + 0x92,0x52,0xaa,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x06,0xfc,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf, + 0x12,0xfe,0xff,0x50,0xaa,0x2a,0x95,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0xa5, + 0xfe,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0x44,0xff,0xff,0x0a,0x25,0xa5,0xa4,0xff,0xff,0xff,0xff, + 0xff,0xff,0x97,0x06,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0x15,0xff,0xff,0x40,0xa9,0x92,0xea, + 0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x55,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xa1,0xff,0x7f, + 0x92,0x4a,0xaa,0xd4,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x06,0xfc,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x95,0x8a,0xff,0x3f,0x84,0x54,0xa9,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0x2f, + 0x25,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x52,0xe0,0xff,0xbf,0x50,0xa9,0x4a,0xf2,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0x8e,0xfe,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xa9,0xea,0xff,0x3f,0x24,0x95,0x54, + 0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x23,0xfe,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x4a,0xf0,0xff, + 0x9f,0x50,0x69,0x49,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x8b,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xa5,0xf4,0xff,0x0f,0x2d,0x75,0xaa,0xfa,0xff,0xff,0xff,0xff,0xff,0xff, + 0xaf,0x03,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x9f,0x14,0xfa,0xff,0x2f,0xa8,0xfa,0x25,0xfd,0xff,0xff, + 0xff,0xff,0xff,0xff,0x97,0xd7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xaa,0xfc,0xff,0x0f,0x4d,0xfd, + 0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0x83,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x12,0xfc, + 0xff,0x27,0x92,0xfe,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0xd7,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x97,0x0a,0xff,0xff,0x83,0x56,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xef,0xc7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xab,0x24,0xff,0xff,0x2b,0xaa,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xe7,0xef,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x45,0xff,0xff,0x05,0x95, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0x82, + 0xff,0xff,0x51,0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xa9,0xe8,0xff,0xff,0x85,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0x52,0xc1,0xff,0xff,0x90,0xd5,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x4d,0xe8,0xff,0xff,0xa5, + 0xe4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x51, + 0xf2,0xff,0x7f,0x40,0xd5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x3f,0x95,0xf8,0xff,0x7f,0xa9,0xea,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x15,0xfa,0xff,0x3f,0xa4,0xf4,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xa4,0xfc,0xff,0x7f, + 0x71,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f, + 0x15,0xfe,0xff,0x3f,0x94,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0x0a,0xff,0xff,0x1f,0x79,0xf2,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0xa4,0xff,0xff,0x5f,0x8c,0xfa,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x53,0x82,0xff,0xff, + 0x1f,0x5c,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xa4,0x92,0xff,0xff,0xbf,0x56,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x9a,0xc4,0xff,0xff,0x0f,0x2e,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa2,0xf0,0xff,0xff,0xaf,0xa7,0xfe, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x55,0xe4,0xff, + 0xff,0x0f,0x57,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xbf,0x54,0xf2,0xff,0xff,0x9f,0x4b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x9f,0x92,0xf8,0xff,0xff,0xc7,0xab,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x15,0xfe,0xff,0xff,0x97,0xd7, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa7,0x94,0xfc, + 0xff,0xff,0xc7,0xe3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x2f,0x05,0xfe,0xff,0xff,0xcf,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x53,0xa9,0xff,0xff,0xff,0xd3,0xeb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x05,0xff,0xff,0xff,0xe3, + 0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x54,0xc2, + 0xff,0xff,0xff,0xeb,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x95,0xc8,0xff,0xff,0xff,0xf3,0xfa,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xa5,0xd2,0xff,0xff,0xff,0xff,0xf5,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xaa,0xe0,0xff,0xff,0xff, + 0xff,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x49, + 0xf8,0xff,0xff,0xff,0xff,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x9f,0x2a,0xf5,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x4a,0xf8,0xff,0xff,0xff,0xff,0xfc,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x14,0xfd,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97, + 0x4a,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xab,0x04,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0x52,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x53,0x85,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x54,0xa2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x4a,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xa5,0xe0,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x94,0xe4,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x5f,0x55,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xbf,0x12,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x54,0xfa,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x0a,0xfc, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x53,0x45,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x97,0x14,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x45,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x54,0x82, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x4a,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x52,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x55,0xe8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x24, + 0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0x55,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x24,0xf9,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x15,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f, + 0x49,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x2f,0x95,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x01,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0xd5,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x57,0x81,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x97,0xd4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xe0,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x93,0xf4,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x57,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x2b,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x89,0xfc,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xfc, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x05,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x49,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x89, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xe9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0x9f,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xf9,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0x6f,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f}; diff --git a/tests/auto/gui/image/qimagereader/images/grayscale-ref.tif b/tests/auto/gui/image/qimagereader/images/grayscale-ref.tif Binary files differnew file mode 100644 index 0000000000..960531ea86 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/grayscale-ref.tif diff --git a/tests/auto/gui/image/qimagereader/images/grayscale.tif b/tests/auto/gui/image/qimagereader/images/grayscale.tif Binary files differnew file mode 100644 index 0000000000..5f4e11429d --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/grayscale.tif diff --git a/tests/auto/gui/image/qimagereader/images/image.pbm b/tests/auto/gui/image/qimagereader/images/image.pbm new file mode 100644 index 0000000000..67e5efa3e9 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/image.pbm @@ -0,0 +1,8 @@ +P1 +16 6 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 +1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 diff --git a/tests/auto/gui/image/qimagereader/images/image.pgm b/tests/auto/gui/image/qimagereader/images/image.pgm new file mode 100644 index 0000000000..443bf40964 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/image.pgm @@ -0,0 +1,10 @@ +P2 +24 7 +15 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0 +0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0 +0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0 +0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/tests/auto/gui/image/qimagereader/images/image.png b/tests/auto/gui/image/qimagereader/images/image.png Binary files differnew file mode 100644 index 0000000000..7d4890a7ff --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/image.png diff --git a/tests/auto/gui/image/qimagereader/images/image.ppm b/tests/auto/gui/image/qimagereader/images/image.ppm new file mode 100644 index 0000000000..2a5640e189 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/image.ppm @@ -0,0 +1,7 @@ +P3 +4 4 +15 + 0 0 0 0 0 0 0 0 0 15 0 15 + 0 0 0 0 15 7 0 0 0 0 0 0 + 0 0 0 0 0 0 0 15 7 0 0 0 +15 0 15 0 0 0 0 0 0 0 0 0
\ No newline at end of file diff --git a/tests/auto/gui/image/qimagereader/images/image_100dpi.tif b/tests/auto/gui/image/qimagereader/images/image_100dpi.tif Binary files differnew file mode 100644 index 0000000000..fcf3cd89aa --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/image_100dpi.tif diff --git a/tests/auto/gui/image/qimagereader/images/kollada-noext b/tests/auto/gui/image/qimagereader/images/kollada-noext Binary files differnew file mode 100644 index 0000000000..2abd4bb763 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/kollada-noext diff --git a/tests/auto/gui/image/qimagereader/images/kollada.png b/tests/auto/gui/image/qimagereader/images/kollada.png Binary files differnew file mode 100644 index 0000000000..2abd4bb763 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/kollada.png diff --git a/tests/auto/gui/image/qimagereader/images/marble.xpm b/tests/auto/gui/image/qimagereader/images/marble.xpm new file mode 100644 index 0000000000..1c08049624 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/marble.xpm @@ -0,0 +1,470 @@ +/* XPM */ +static const char *marble_xpm[] = { +/* width height num_colors chars_per_pixel */ +" 240 240 223 2", +/* colors */ +".. c #959595", +".# c #c5c5c5", +".a c #adadad", +".b c #dedede", +".c c #b7b7b7", +".d c #d2d2d2", +".e c #bebebe", +".f c #c9c9c9", +".g c #b8b8b8", +".h c #d6d6d6", +".i c #9e9e9e", +".j c #eaeaea", +".k c #b2b2b2", +".l c #cecece", +".m c #a5a5a5", +".n c #e4e4e4", +".o c #c4c4c4", +".p c #d9d9d9", +".q c #b1b1b1", +".r c #d8d8d8", +".s c #e0e0e0", +".t c #d6d6d6", +".u c #b6b6b6", +".v c #bfbfbf", +".w c #cbcbcb", +".x c #a5a5a5", +".y c #d1d1d1", +".z c #cdcdcd", +".A c #aaaaaa", +".B c #9a9a9a", +".C c #dedede", +".D c #aeaeae", +".E c #e6e6e6", +".F c #d3d3d3", +".G c #c8c8c8", +".H c #bababa", +".I c #c4c4c4", +".J c #cccccc", +".K c #bcbcbc", +".L c #f0f0f0", +".M c #b5b5b5", +".N c #e3e3e3", +".O c #c2c2c2", +".P c #adadad", +".Q c #c9c9c9", +".R c #e1e1e1", +".S c #a2a2a2", +".T c #d1d1d1", +".U c #bebebe", +".V c #dbdbdb", +".W c #dbdbdb", +".X c #c8c8c8", +".Y c #b9b9b9", +".Z c #a8a8a8", +".0 c #d3d3d3", +".1 c #9f9f9f", +".2 c #c1c1c1", +".3 c #ebebeb", +".4 c #b4b4b4", +".5 c #d9d9d9", +".6 c #cecece", +".7 c #e8e8e8", +".8 c #d6d6d6", +".9 c #c5c5c5", +"#. c #b0b0b0", +"## c #dadada", +"#a c #c5c5c5", +"#b c #d1d1d1", +"#c c #afafaf", +"#d c #b1b1b1", +"#e c #cbcbcb", +"#f c #c1c1c1", +"#g c #eeeeee", +"#h c #9b9b9b", +"#i c #c6c6c6", +"#j c #c0c0c0", +"#k c #cbcbcb", +"#l c #bdbdbd", +"#m c #a1a1a1", +"#n c #b7b7b7", +"#o c #a7a7a7", +"#p c #e6e6e6", +"#q c #c9c9c9", +"#r c #bbbbbb", +"#s c #e2e2e2", +"#t c #b8b8b8", +"#u c #cdcdcd", +"#v c #d3d3d3", +"#w c #cfcfcf", +"#x c #e0e0e0", +"#y c #d5d5d5", +"#z c #bdbdbd", +"#A c #cecece", +"#B c #c0c0c0", +"#C c #b7b7b7", +"#D c #e5e5e5", +"#E c #c4c4c4", +"#F c #e3e3e3", +"#G c #d3d3d3", +"#H c #dddddd", +"#I c #dddddd", +"#J c #acacac", +"#K c #a3a3a3", +"#L c #eaeaea", +"#M c #e1e1e1", +"#N c #b9b9b9", +"#O c #d5d5d5", +"#P c #bababa", +"#Q c #d7d7d7", +"#R c #b5b5b5", +"#S c #d1d1d1", +"#T c #c6c6c6", +"#U c #dcdcdc", +"#V c #b4b4b4", +"#W c #c6c6c6", +"#X c #a8a8a8", +"#Y c #a0a0a0", +"#Z c #cbcbcb", +"#0 c #bfbfbf", +"#1 c #cbcbcb", +"#2 c #a4a4a4", +"#3 c #c0c0c0", +"#4 c #bbbbbb", +"#5 c #9c9c9c", +"#6 c #a2a2a2", +"#7 c #dcdcdc", +"#8 c #c3c3c3", +"#9 c #9d9d9d", +"a. c #aaaaaa", +"a# c #d5d5d5", +"aa c #eeeeee", +"ab c #b6b6b6", +"ac c #b0b0b0", +"ad c #b3b3b3", +"ae c #c9c9c9", +"af c #e9e9e9", +"ag c #bdbdbd", +"ah c #a0a0a0", +"ai c #b0b0b0", +"aj c #e8e8e8", +"ak c #cacaca", +"al c #c3c3c3", +"am c #dbdbdb", +"an c #d0d0d0", +"ao c #d8d8d8", +"ap c #c7c7c7", +"aq c #dcdcdc", +"ar c #c7c7c7", +"as c #f0f0f0", +"at c #a3a3a3", +"au c #bfbfbf", +"av c #d9d9d9", +"aw c #dfdfdf", +"ax c #d3d3d3", +"ay c #c0c0c0", +"az c #cacaca", +"aA c #b3b3b3", +"aB c #cfcfcf", +"aC c #dadada", +"aD c #b2b2b2", +"aE c #e2e2e2", +"aF c #d7d7d7", +"aG c #c4c4c4", +"aH c #b8b8b8", +"aI c #cdcdcd", +"aJ c #a6a6a6", +"aK c #d2d2d2", +"aL c #cecece", +"aM c #acacac", +"aN c #dfdfdf", +"aO c #d5d5d5", +"aP c #c9c9c9", +"aQ c #bcbcbc", +"aR c #c6c6c6", +"aS c #cdcdcd", +"aT c #bebebe", +"aU c #f2f2f2", +"aV c #b6b6b6", +"aW c #e4e4e4", +"aX c #c3c3c3", +"aY c #e2e2e2", +"aZ c #d2d2d2", +"a0 c #dddddd", +"a1 c #dcdcdc", +"a2 c #ececec", +"a3 c #eaeaea", +"a4 c #cccccc", +"a5 c #c7c7c7", +"a6 c #c2c2c2", +"a7 c #cccccc", +"a8 c #a8a8a8", +"a9 c #e7e7e7", +"b. c #e4e4e4", +"b# c #d9d9d9", +"ba c #bababa", +"bb c #cfcfcf", +"bc c #d4d4d4", +"bd c #d0d0d0", +"be c #aeaeae", +"bf c #e1e1e1", +"bg c #d7d7d7", +"bh c #cfcfcf", +"bi c #b8b8b8", +"bj c #e6e6e6", +"bk c #c5c5c5", +"bl c #e4e4e4", +"bm c #d4d4d4", +"bn c #dfdfdf", +"bo c #dedede", +"bp c #ececec", +"bq c #bababa", +"br c #bcbcbc", +"bs c #b0b0b0", +"bt c #cccccc", +"bu c #a6a6a6", +"bv c #c1c1c1", +"bw c #bcbcbc", +"bx c #ababab", +"by c #d7d7d7", +"bz c #b7b7b7", +"bA c #b2b2b2", +"bB c #b4b4b4", +"bC c #bfbfbf", +/* pixels */ +"aYbla9a9a9.7#D.N#L#La9.7a9#D#D.7#D#D#DaY#x#xa0ama0ama0am#xbnbnbnaYaYaYaYaY#DaYaYaYbn#x#x#xaY.N#Da9a9a9a9a9a9a9a9a9.7a9a9a9#Da9#D#L#L#L#L#L#La2#La2a2a2a2a2a2#ga2#ga2#ga2a2#ga2a2#L#L#L#Lafa9a9a9bl#Dbl#Da9a9a9#L#L#Laf#L#Laf#L#L#L#L#L#L#L#L#L#La2#La2a2a2#La2#L#L#Laf#L#Laf#L#Laf#L#Laf#L#Laf#Laf#Laf#Laf#Laf#L#D#DblblaYaYaCa0.t.Fb#bnbnaCbnblblblblblaYaY.RaYblblblblblblblbla9a9a9a9a9a9#pa9a9#pa9#pa9#pa9#pa9#pa9a9bl#D#D#D#pa9#pafa9a9a9a9#L#Lafa9a9a9#D#D#pbl#U.V.Vb#.8am#xbn#IaYbl.N.N#x", +"am#I#Da9a9a9bj#D#La9.7#D#Da9#D#D#p#DaYaY#xbna0amamamb#a0a0a0a0bnawaYaYaYaYaYaYaY#xbnaY.R#xaYaY.Nafa9afa9afa9afa9.7a9.7a9bja9bja9#Lafa2afa2af#L#L.3#La2#La2bpa2#La2#ga2a2#ga2a2#g#L#Laf#L#La9afa9bl#Dbl#Da9afa9#L#Laf#L#Laf#L#Laf#L#L#L#L#L#L#L.7a2#La2a2#La2#La2#Laf#L#Laf#Laf#Lafajaf#L#Laf#L#L#Lafajafajafajaf.na9#s#Daw#xbnaCb#bg.Vbnbn.RaYaY#Mbl#pblaYblaYaYaYblblbl#D#Dbl#D#paf#pafa9#pa9afbla9#pa9#pa9#pa9#pa9#p#D#p#Da9#D#pa9#pa9#Da9#Da9af#L#La9.7#D#s#D#MaYbnaCb#aOb#aC#x#UaYaY#M#DaYbf", +"aOambn.sa9bja9.7a9.7a9#Da9bj#D#D#D#DaYaY#x#xa0amaFaFbgb#aF.Va0.VaYaYaYaYaYaYaYaYbn#xaY#xaY.N#D#Da9a9a9a9a9a9a9a9a9bja9#Da9#Da9#D#L#L#L#L#L#La2#La2afa2a2a2a2#ga2#g#La2bpa2bpa2#L#L#L#L#Lafa9a9#p#DaY#D#Da9a9.7a9af#Laf#L#Laf#Laf#L.7#L#L.7#L#L#L#La2a2a2#La2#L.3#Laf#Laf#Lajaf#Laja9#Lajaf#Lajafaja9#La9#La9#La9a9a9blaYaYaYawa0b#b#.paYaYblaY.Rbla9#pblblaYblaYa9#p#D#pa9#pa9#pa9a9a9#pa9a9#pa9bl#pa9#pa9#pa9#pa9#pa9a9#D#Dbla9a9a9a9a9#pa9a9a9#L#Lafa9a9#D#D#Da9awbn.pb#bgamaCbn#xaw#D#D#D.N#x", +"amamaC#x#D#s.7.7a9#Da9#D#D#D.N.N#xaYaYaY#xbna0a0aOaFb#aOb#bg.Vambna0bnaCa0aYaYaY#U.RaYaYaY#Dbl#Da9a9#La9af.7afa9.7a9.7a9bja9bja9#L#L.3#L.3#Laf#Lafa2#L#La2#La2bpa2a2#ga2#ga2a2#g#L#L#L#Lafa9afa9.Nblbl#Da9a9afa9#Laf#L#Laf#Laf#L#L#L#L#L#L#L.7#L#La2#L#La2aja2#Laj#Lafaj#Laf#L#Laf#Lafafajafaf#Lafaj#Lafajafaj#Laja9.n#D#MaY.R#xbga0bnbn.RaYbl#Ua9#pa9#D#Dbl#D#Dbl#Dbl#Dbla9#Da9a9#pafa9af#pa9#p#pa9#pa9#pa9#pa9#pa9#p#D#pa9#Da9a9af#pafa9af.7a9#Laf#L.7a9#s#D#saYaY#Ua0aObgao#x#IaYbl#D#s#D.sbf", +"amaOama0.N.Na9a9bja9#Dbj#D#D#DaY.N#x#x#x#xbnaCa0#H.Vbgb#b#aFbgambnbn#Ubnbnbnbnbn#xaYawaYbl#Da9#Da9a9a9a9a9a9a9a9a9bja9#Da9#sa9#D#Laf#L#L#L#La2a2a2afa2#La2#ga2a2#g#L#g#La2bpa2#L#L#L#Laf#La9a9#pbl#Dbl#Da9a9.7a9#Lajaf#Lajaf#Lajafafajafafajafaf.j#L.3a2#Laf#La2af#Laf#Laf#Laf#L.n#L.n#La9#L#Lafa9afa9aja9#La9af.7afa9#Dbl#IaYawa0a0#UbnaYblblaY#pa9#pa9#D#D#D#Dafa9afa9af#pa9#pa9afa9#pa9a9a9a9#pa9#pa9#p#pa9#pa9#pa9a9#D#Dbla9a9a9a9a9a9.7a9.7af#Laja9a9#D#D#saYawbnaCb#aobn#x.Nbl#s#D#D#D.N.N", +".CamaOao.WaY#D.7#s#Da9#D#D.NaY.N#x#I#xbn#xaY#x#U#xa0a0a0bgamb#ambga0ama0am#xa0a0.RaYaY#Dbl#Dbl#Da9a9a9a9afa9afa9.7a9#D.7#Dbja9.7af#La2#La2af#L#La2a2a2a2a2#L#g#L#ga2a2#ga2#ga2#g#L#L#L#Lafa9a9a9#Dawbl#Da9a9a9.7af#Laf#Laf#L#Laf#L#Laf#L#Laf#L#Laf#L.j#La2afajaf#Lafajaf.Eafaj#Laf#Laf#Lafaja9aj#Lajaf#Laf#Lafajafajaf.n#DblaYaYaCbn#xbnaYaYaY.Rbla9#p#Da9a9.7#La9a9a9a9a9afa9afa9a9afa9afa9afa9#p#pa9#pa9a9#pa9#pa9#p#D#pa9#Da9afafafaf.7a9a9.7#L#Lafa9.n#D#s#D#D#x#Ua0aCaC#x.saY.s#D.7a9.Ebj.N", +"#xa0.8a#.8.Cbf.N#D#D.N.NaY.N.saY#x#xaY#IaYaYaYaYaYaY#x#x#xa0aCam.Vb#bg#yb#.Va0bnaYaYblaY#Da9#D#Da9afa9af.7a9a9a9.7a9bja9#s#Da9.7ajaf#Laf#L#La2#L.3#La2#La2a2#ga2a2bpa2#L#g#La2bp#L#L#Laf#La9af#paYbl#D#Da9a9a9a9#L#L#Laf#Laf#L#Lafafafafaf#Lafaf#La2#La2afajaf#Lajaf.7af#Lafa9aja9aja9#L.n#Lafafa9#L.n#L.n#La9#Laf#La9a9#Mbl#xaY#x#IaYawaYaYaYaYblbl#pa9a9.7#L.7afaf#Laf#Lafa9afa9a9a9a9a9a9a9a9a9#pa9#pa9#pa9#pa9#pa9a9#D#D#Da9af#Lafa9a9a9.7af#Laja9a9#D#D#D#M.N#I#xaCa0#UaY#D.NaY#D.n.7bj#Dbj", +"#x#xa0#vbcaq#xbf#D#D.Nbl.s.NaYbf#x#x#xaYaYaYaYaYaY#M.NaY#x#x.Ca0b#bgb#bgbg.V.p.VawaYblbl#Dbl#Dafa9a9a9a9afa9afa9.7a9#Da9#D#s#Da9af#La2#La2#Laf#La2#La2#La2bpa2bpa2#ga2#ga2#ga2a2#L#L#L#Lafa9a9a9aYaYbl#Da9afa9a9ajaf#Lajaf#Lajafafaj#Lafajafafajafa2#La2#Laf#Lafa9#Lafaja9aj#Laf#Lafajaf#Laf.7afaj#Laf#Lafajaf.Eafajaf.n#Dbl#MaY#IaY#xaY.RaY.RaY#FaYa9a9a9#L#L#Lafa9afafa9#Laf#L#La9afa9afa9afa9#pa9#pa9#pa9#pa9#pa9#p#D#p#Da9a9afa9a9.7a9#L.7.7.naf#La9.n#D#s.N.N#x#UaCbnaY#s#DaY#sa9.7b..7#DaW", +".7aw#x.CaoaB.y.5#s.N#I.Ca0a0ama0#x.N.NaY.NaY#D#Dbl#DblaYawaY#U.CbgbmaBaSaZbma0a0blaYaY#Dbla9a9#Da9af.7afa9a9a9a9bl#D#D#D#D.N#D#D.7a9a9a9a9a9#La9afafafafafaf#Lafa2#La2#L#L#L#La2a2a2af#La9a9#D#DawaY#sbla9b..7#La9a9a9a9.7a9a9a9afa9af.nafafafafafajafajafajafajafaja9a9bl#MaY#s#Da9#Da9#sa9.na9.7af.Eaf.7af#Lafafa9a9bl#M.NaY#Ibn#UaYaYaw#Da9a9.n#p#pa9a9.7.7.7.7a9.7a9.7a9a9#Lafafaf#Lafa9a9a9#pa9a9#pa9#pa9a9a9a9afa9.7af.7.7.7afa9a9a9a9a9a9#L.na9.na9.na9.n#Maw.Nawaw.N#D#D.E.7bj.7#Dbjb.#D", +".7#D.s#x.5.y#va#.NaYbf.Ca0ao#xbn.s.N.N#D#D#Da9#Dbl#Dbl#DaYaYaYbn.p.taBan#uaZ.FbgbnawaYawbl#D#D#D#D#Dbl#D#D#D#D#D#Dblblawbl.N#D#Da9a9a9.7af.7a9a9afafafajafaf#L#L#La2a2a2a2a2#La2#La2af#La9#D#D#DaYaY#D#D#Da9a9.7a9a9.7a9a9a9.7a9#Lafafafaf#Lafafaja9af#pafa9af#pajaf.na9#s#DblaYa9a9.na9a9a9#Da9aj#Lafaj#La9aja9ajaf.nbl#DaYaw#xa0#x.b#xaY#D#D#p#p#p.na9a9a9#L.7a9a9a9a9a9.7a9#Lafafafafafafa9af#p.na9#pa9a9a9afa9af.7a9#L.7#L#La9a9.7a9a9.7.na9a9a9.na9.na9.na9#D#MaYaw.N#s#D.n.7.7.n.7.E#D#D.7", +".7a9aY#xaCam#v#vaCaqa0aqama0#UaY.NaY#D#D#D#D#D#Da9#D#D#Dbl.NaY#Ibnambm#SaZa#a#b#aCa0a0#x#x#xaYbl#D#Da9#Dbl#Dbl#DblaYaYaYaYbl#D#Da9a9a9afa9afafafafafafafafaf#Laf#L#L#Laf#Laf#Laf.j#L#L.n.7a9#s#Daw#x#M#Da9#Daj.7a9.na9.7.na9a9.naf#Lafajafafajafafafajafajafafaf#pa9bl#Mbl#Daw#D.n#Da9#D.na9.na9a9af.7afafajaf#Lafa9a9#sblaY#x#IbnbnaYaYawbla9a9#p#pbl#pa9#D.7.7a9.7a9.7a9a9#L#Lafaf#Lafafa9a9a9a9#pa9.n#pa9a9a9afa9a9#L#Laf.7afa9a9a9a9.7a9a9a9.naf.na9.na9.na9#M.Nawaw#D#s#D#Daj.7aj.7#D.7b.a9", +"a9#saY.s.Ca0aF#v#v.5#vaF.8a0#x#D#D.N#D#Da9bja9.7a9a9bl#D#DaYaY.N.R#Uama#aFaOaFaFb#b#b#a0aCa0#I#xaYblaYblbl#DblaYaw.R#IaYawaY#D#Da9a9a9a9a9a9a9a9a9#p.na9af#La9.7af#Laf#Lafajaf#L#L.3#La9#D#D.NaYaYaYbl#D#D.7a9.7a9.7a9a9a9.7a9.7a9a9a9a9.na9#pa9.n#pa9#pa9#p.na9#sbl#s#Dbl#DblaYa9a9a9.Ea9a9bja9a9.na9#sa9#Da9#Da9.nblbl#D#M#x#x#U#x#UaYaY#Da9#sa9#p.na9a9.7a9a9#La9a9#La9#L#L#L#Lafafa9#La9afa9#pa9#pa9a9a9a9.7#Laf#L#L#L.7#L.7.7a9.7.na9a9.na9.7.n#D#D#s#D#M#D#Mbl.s#D.s#Da9#D.7.na9a9.n.7#D.7", +".N.N.NaY#Uaqamaoa#aB.0a#ambn#xbl#D#D#D#D#Da9.7a9a9.7a9#D#D.s.NaYaY.RaCamamaF.5b#amaob#amama0a0a0#IaYawaYaYaYaYaYbnbnbnaYaYaYbl#D.na9a9.7afa9a9a9a9af#paf.na9afa9.n.7#La9.7a9#L#Laf#La9a9#D#D.N.NaYaY#Dbl.n#D.7af.7a9.na9.na9a9.na9.na9a9#pa9.na9a9a9.na9.na9a9a9aY#MaYbl#sbl#s#D.n#Da9#Da9#sa9.n#Da9a9.7a9.na9.na9a9#DawaY#x#x#xbnbnaYawaYbla9a9a9a9#pa9#Da9a9.7a9.7af#L#L#La9#Laf#Laja9.7a9.7a9a9.n#pa9a9.7#Da9a9#L#La9#Laf.7afa9a9a9.7a9a9bja9#sa9#D#M#D#M#D#sbl#saY#saY#s#D#s.7a9.E.7#D#D#D#D", +"#I.N#I#xamaCamaFaB.Gaz#u.8am#xaY#D#D#D.7a9bja9.7.7a9.7a9#D#D#D.N#Ubna0aCama0amao.Va0amaCama0aC.Cbnbnbnbn#x#Ubn#Uam#Ua0awaYaYaw#D#pa9a9#pa9a9a9#p.na9a9a9a9a9.7a9.7a9af.7afa9a9a9aj#La9.E#D#D#saYaY#Mbl#Dbja9.7.7a9a9a9.7a9#sa9#D#p#D#pbl#sbla9#D#sblbl#Dblbl#sblawaY.N#MaYbl#Dbla9.Ea9.na9.7a9a9#D#s#D#s#D#D#D#D#D#MaYbl.Naw#x#Ibn#I.R#xaY#Da9#Da9a9a9a9.na9a9a9.7a9a9#La9#La9a9#L#Laf#La9a9#Dbj#pa9a9a9#Da9.7.7afafa9.7a9.7#L.7a9.7a9a9#sa9.na9#D#D#D#s#D.sbl#Dawbl#saY#sbj#Da9#s#D.Nbl.saY.s.N", +".Cbf.C.Cam.5aoa#.la5.G.waZ#va0.C#D#D#D.7a9a9#L#La9#L.7.7.7#D#D#D#x#x#x#x#x#xa0bnam.Va0.Va0a0#xbnaY#x#Ia0a0aCa0aCa0ambnbnaYawblbl#Dbl#M#Dblbl#D#Mbl#pa9a9#Da9a9.7a9.7a9.7a9.7a9a9#La9.n#D#D.NaY.NaYaY#D#Da9#Daja9.7a9a9a9a9.7a9.n#D#M#D#sbl#sblbl#D#M#D#M#D#M#D#M#x#xawaY#Dawa9#Ma9#Da9#Da9#sa9#s#D#D#D#D#D#s#D#sbla9blaw#x#x#xa0#UbnaYawaYbl#D.na9a9a9a9a9#Da9#pa9#La9#L#La9.7af#L#L#L.7#L.7.7.na9a9#D#s.7#D.7.7afa9#La9af.7a9.7.na9.na9a9a9#Da9#s#Dawblaw#D.sbl#sbl.s#D#D#s#D#saY.Naw#xaYbf#x#x", +"aqaoamavam.8a##v.5#Saza7.w#u#vam#Da9#D.7a9.7a9a9.7#L.7#La9bj#D#D.Cbn#xbnaYaY#x#x.pb#.Vamaobnbn#xbnbn#xbn#xbn#xa0a0b#aCa0aw.R.Nblaw#Dbl#Dbl#Dblbl#pa9#Ma9a9.nbja9a9a9#La9a9a9.7a9.na9#D#D#DaY.N.NaYaYbl#D#sa9a9#La9.Ea9.7a9a9#Da9#M#Dbl#Mbl#sbl#s#Mbl#sbl#D#MaY#sa0#I.NaYaYblbl#Da9a9.na9.Ea9a9a9#D#D#s#D#s#D#D#D#Dbl#saY#x#xaC.Ca0#x.R#xaY#D#Da9a9a9a9a9a9#p.na9a9a9a9#La9#La9a9#L#L#L.7#La9.7.7a9a9a9#Da9.7af.7a9afa9.7a9.7#L.7a9a9bja9#s.7.na9#sbl.s.saYaw#saY#saY#saY#s#D#s#D#xaY#x.W.C.C.Waq", +"amaFaOaFaOaFama0aY#x.8.0#u#uan#uam#xaY#Da9a9.7a9#Laf#L#La9#D#D.sbl#D#sbl#xaYaw#x.Rbn#Ub#.Va0b#b##Ubnbnbnbna0#xbnbnaYaYaYbnbn#UbnaYaYblaYblawblawa9.n#p#pa9#pafafa9a9a9.na9a9a9a9bl#Dbl#Dbl#sblblawaY#D#Da9.7.7#Laf#Laf.n.7#D.7#D.NaYawaY#xbn#Ua0#U#Ubn#UbnaC#UaY#xawaY#M#D.na9ajaY.N#Dbla9a9.na9.nbl#DblaYaYaw#x#MblaYawbn#Ibna0.b#U.RawaY#Mblbl.na9a9a9a9a9afa9#Dbj#D#D#D#D#D.7#Lafa9afa9.7#Da9#sa9a9a9#Da9.7.7afa9a9a9a9#D#s#D#D#Daw.N.NaY.NaY#D#sbl#saY#saY.N.na9#D#s#DaY.N.N#I#x.CamaoaFbya#", +"bgb#amam.5aCa0.C#M#xa0aFaZ#uaB.0aO#xaY#Dafa9a9a9#L#L.7af.7#D#D#D#D#DaY#D.N.N#xaY.Cbna0a0b#aFb#aF.Vbnbna0#Ubnbn#x#U#x.R#xawaYbn#x.R#I.Raw.RaY#x.R#p#p#pbl.na9a9a9a9a9a9#Da9#s#D#M#Dblbl#sblbl#DblaY#Dbla9#Da9af.7ajaf#L.7a9.n#Da9#M#DaYaYaYaYbnaCbn.paCa0bgaoaC#UaC#I#xaY#MaYblbl#Mbl#M#D.na9a9.n#D#M#D#M#DaY#DaY#M#pawaY#Ibn.Ca0aYbnaY.RaYblbl#Da9a9.na9afa9a9af#D#D#D#D#D#Da9#Daf#L.7a9.7#Da9#D#pa9.na9a9b.a9.7.7a9.7a9bja9#D#D#D#D#DaY#Daw#Daw#D#D#M.N#saY.saY#sbl#sbl.Naw.Nawbna0aCa0.8a#aF.5", +"amamaCa0a0#x#xaYblaY#Ia0bc#u#ua#amam#x#D#Da9.7a9#Laf#La9a9.7#D#Dbl#D#D#MaYaYboaYbna0a0aoamb#aOb#b#am.Va0bnbn#Ubnbn#xaYaY.R#xawaYbn#UbnaCbn#Ubn#U.RawaYblaYblawbl#D#D#D#Dbl#Dbl#Dbl#Dblbl#Dblbl#DaYaw#D#Da9bj.7#La9#Lafa9a9bja9bj#D#MblawaYaw.R#Ubn.V.8#vaB#S#waOaoa0aC#x#x.N#I.NaY.NaY#D#D#D.n#Dbl#sbl#Dbl#saYaYblawaYaYbnbnaCbn#U.baYawaY#M#Dbla9.na9a9.na9.na9#s#D#s#D#s#D#D#D.na9a9a9a9#D#D#D#pa9a9#Da9#D#L.7a9.na9#D.n#D#D#D.saY.saY.NaY.saY#sbl#s#Daw#DaY.NaY.NaY.saY.NaY#x.Wa0a0a0aOam.8a#", +"#x#x#x#xaYaY.N.N.7#D#x#xb#aZ.ya#amaObn#Da9#Da9bj#L#L#D.7#Da9.7a9a9.nbl#D#DaYaY.NaC#xa0.Vamb#aFaF#vaFbga0a0bn#xaY#Ubn#U#xaYaYaYaYbn#xa0a0a0a0aCa0bn#Ubn.baYaYaYaYbl#D#M#Dbl#D#Dbl#Dbl#s#D#D#D#D#MaY#Dbl#D#Da9.7a9ajafaj.7a9a9#sa9a9#M#DaYaYaY.b#xbgb##vaBa7.Q.z#S.5aO.8aoao.Ca0.W#x#I.Naw.NawaY#DawaYblawaYaYawaYawaYaY#U.C#U.Ca0aY#x.RaY#xblbl#D#Dbla9a9a9a9a9a9#D#D#D.NaY.N#s#Da9a9#sa9a9#M#Dbl.na9a9a9a9bja9.7a9a9a9.7#D#D#D#saY#DaY#Daw#DaY.N#M#D#s#Dbl.s.N#M.Naw.N#xaY#x#I#x#Ua0a0aCamama0am", +"aYaYbl.s#D#D#D#Da9#D#s.N.CaOa#aF.5ao#x#Dbl#Da9#Da9a9.7a9.7a9a9.7a9a9a9#Dbl.NblaY#x#xbna0a0amaFaFbmaFaFamaCbn#U#xbnbnbnaY.b#x.R#xaYbn#xbnaCa0bna0#Ubn#Ubnbn#I#xaY.NblaYaYawaYaw#Dbl#Dbl#D#M#Dbl#DaYaY#Dbl.na9.7a9#La9#La9a9bja9#D#MaYblawaY.R#x#U#S#SaB#uaz#u#vaO.8aOaOaOaOaOaOaO.Caoa0.W.C#I#x#I#x#I#x#x#I#x.NaY#x#Ubn#UbnaCbnaC#I.R#IaYawbl.sbl#M#D#Ma9#D.n#Dbl#D#D#s#D#D#D#D#D#Ma9bl#D#D#DblaYa9#p#sa9#D.n.7.7.na9#s#D#s#D.NaY.saY.saY.NaY.saY#s#D#p.s#saYaY.N#IaYaYaw#x#IaY#I#x#x#I#x#x#x#x#x", +"#D#D#D.7.7.7.7.7.7a9a9#DaY.CaO.y.5.5bnaY#D#D#D#D#D#Da9bja9a9.7a9a9a9#Da9#sbl.N#MaYaY#xawbna0aCb#aOaFbgb#b#a0a0bn#Ibnaw#xaYaYaYaY#Ubn#IaYaYaYaYbnbn.R#xaw#x.R#Ibnaw#IaY.sbl.Nbl.N#D#M#Dbl#D#M#DblawaY#M#D#D#s.7a9aj#L.na9.n#D#s#D#DaY#IbnaY#UbnaCaB#SaB#u#uaBaO.5amaoam.8.5aO.y#1#1#u.yaOamamaoamamamaC.C.C#xbn#x#Ua0aC.CaCa0#Ia0.R#x#UaYaYblaY.N#D#p#D#sbl#Dbl#D#s#D#D#D#D#s#D#Da9#p#MblblawaYaY#Ma9bl#sa9bja9.7#Da9a9.7a9#Daw#DaY.saY#Daw#DaY#D#M#D#sbl.N#saY.saY#xbo.N.N.s.N.Naw.N#D#D#D#Da9#D", +"a9.7.7af#Lajbp#L.7#L#La9#DaYa0#va#a0a0.Cbl#D#D#Dbj#D#Da9.7a9#L#L.na9a9a9a9#D#D#Dbl#DaYaY#xaYbna0b#aFb#b#aob#aoambnbnbnbn#U#x.R#xaY.RaY.R#IaYaYawblblaYblaYaYaYawbn#I#x#UaYawbl#Daw.N#D#D.NaY.NawaY#xbl#D#D#Da9.Eafaf#La9#D#D#D#D#I#x#xaCa0aCaoaO.FaO#v#u#u#uaFbgaC.Caoa0ao.5aB.z.U.Oaz.y.y#vbm.y#v#v.5amaoamao.8amaoa0aoa0#Ua0#x#U#xbnaw.N.saY#sbl#Dbl#Dbl#D#M#D#D#D#D#D#D#D#D#D.nbl#Dbl#xaYaYaY#pbla9bl#D#s.7.7.na9#Da9#s#D.NaY.NaY.Naw.Naw.Naw#D#M#D#D#Maw.Naw#x#IaYaY#s#Da9.nbj.7.7b..7.7bp#L", +"#L.7#L#Lbpbp#Lbp.7#L#L.n#D.N.C.5a#amaCaoaY#D#D.N#Da9#Da9#La9#Lafafa9a9#Da9bl#Dbl.n#D.nblawaY#x.Ra0.Vbgamb#amaFaF#Ubn#U#xbnbnaYaYawaYawaYaYblaYaY.bblaYblblblaYaYaYaYaY#I#x#I#x#I.NaYaY.sbl.sbl.NaYaw.N#M#D#sa9.7a9a9.na9.n#D#s#D#xaCa0aoaob##SaBaOaF#S#uaB#v.5aoa0aCamaoao.8#v#v#3ar.wanazaz#3#C#3aX.w.yaOam.8amaCambga0aoa0aCbn#U#x#IaYaw.NaY.NaYaY#sbl#sbl#D#M#D#D#D#D#s#D#D#DblblaY#MaY#IaYawbl.nbl.n#D#Da9#D#Da9.Ea9#D#D#Daw#D#saY.Naw.NaY.N#M#D#s#D.saYawaY#I.N.N#sa9a9.7af#L.E#L#Laj#L#L#g", +"#L#L#L#L#La2bpa2#L.j.7.7#D.Nbf#IaFaBa7an.5a0#Daf#D.7#D.7a9a9#L#L#D#Da9#D#M#D#Dbl#Dbl#Dbl#Dbl#sblaw.RbnaCb#aOaFa#bg.VambnaCbnaw#x.RaYaYaY.baYawbl#pbl.n#Da9a9#D.7#s#D#D#D#D#D#MaYaw#IawaY#x.N#I#x#IaYaY#D#Da9.na9aja9.n#D.N.N#x.CaCb##vaB#uaBaB#v#SaOaOaOaObg.8am.W.WaCaCamaOaB#u#a#faz#Sa#aBaBaz#u#u#uaz.w.wa7#u#uaB.yao.5aC.C#Ia0.pa0aCbnawaY.sbl#saYaYaY#DaYaY#D#s#D#D#D#D#D#D#s#D#sblaY#x#I#x#D#D#D#Da9.n#D#sa9#D#D#D#s#D#D#D#sbl#s#D#saY.saY#MblaY.C.W#I.N#s#Da9#sa9.7.na9.7#L#L#L#L#L#L#L#L", +"bpaj#Lbp#Lbp#Lbpa2#L#L.7#D.Nbfbf.Va#an#uaB.8bn#D#Da9#Da9.7a9ajafa9bl#Dbl#D#D#M#D#D#Dbl#D#Dbl.NblaYawbnamb#aFbm#Sb#.Vaobn#xbnaYaY.baY#MaYblaYblaY#pbl#p.n#Da9.n#D#D#D#s#D#s#D#D#saY.s#x.s#I#x#Ibn.W#I#xaw.N#s#D#D#D#D.NaY#I#x.WaCaCaCaF#SaB#v#SaOaOaOb#aOb#bgamao#x#I.CaCao.8#u.w.OaG.G#SaBaBbmaB#v#v#va#aB#u.G.Galbk#Taz.w#v#v.5bg.5bga0ao.C#IaYaY#Dbl#DawaY#D#M.NaY#D#s#D#D#s#D#D#MaYblaY#I#x#x#M#s#D#s#D#D#D#D#Dbj#s#D#D#D#s#D#D#s#D#Daw#Daw.N#M#s#x#I.Cbf.s#D#D.n.7a9.7a9.7.E.7#L.7#L.7#L#L#L", +"#Lbp#L#g#La2bpa2a2#g#La9bj#D.Nbf.RaCaOaZ.yaFa0aY#D#D#s#Da9a9a9a9#D#Da9#Dbl#D#Dbl#D#M#D#D#M#Dbl#saY#xbnaCa0aOaF#Sb#bg.VbnaCbnaY#xaYaYaY.baYblaYbl#Ma9#p#Da9a9#D.7#D#sbl#Da9#Da9#D#D#D#saY.N#I#I#Iaoao.W#xaY.Naw.N#I#I#U.WaCaoamaobnaCaO#vaF#vaOaFbgambgambg.5.8amav.WaC.CaoaF#uaza6.OazaZaB#vaF#vaFaFam.5aF#v#SaB.G.O#3bv.G.GaPaP.w#u#vaFama0.C.C#IawaYawaY.NaYaYaY#MaYaYaYblaYawblaYaw.NaY#I#x#I#D.N#M#D#D#s#D#s#D#s#D#D#s#D#Dbl#s#p#saY#s.Naw.Nblaw#I#xaY.N.N#sa9.7a9.Ea9.Ea9#L#L#L#L#L#L#L#L#L", +"#La2bp#L#Lbp#Lbp#L#L#L.7#Dbj#D.NaYbna0aoa##vam.C#D#D#D#D.7#D.7a9a9#D#Dbl#D#Dbl#Dbl#Dbl#Dbl#D#DaYaYaYawbna0b#aO.Fbgb#ama0bnbn#IaY.bblawblaYaY#MaYa9#p#sa9a9#Da9#Da9a9a9a9a9.na9a9#s#D#D.saY.NaY#x.C.C.C.W#I#x#I.WaF.8a0a0a0a0aCa0aCaCb##vaFaO#vbgaob#aoaoamaoaCam.W.Caoa0.8#v#ubkab#aan#vaZ#vaFa#aoaobga0aoamamaOa#aBaZ#u.w.w.G#3#3#a.w.y.yaOb#aCbnbn#I#xbn#UaYawbfaYbfaw#x.s#xaY.NawaYbl#x#Ibn#I#Daw#D.s#D#s#D#D#D#D#D#D#D#D#s#D#D#Dbl#saY#saY.saYaw#xaw.N#s#D#D.7.n.7a9.7a9.7#La9aj.7#L.E#L.7#L", +"bp#L#L#g#L#g#La2#g#L#L#L.7#D#DbjawaYaCamaoa#.8aF.N.s#D#D#D.n#Da9#sbl#D#D#M#D#D#M#D#M#D#Dbl#sbl#saYaY#x#UbnaCb#b#bgb#bga0aCbn#x.RaYaYaYaYawblaYbl#p.n#pa9a9.nbja9.7a9.7#sa9#D.7.na9a9#D#D#D#saY.s#x#I#I#x.C.Wa0aoaoama0.W.C.Wa0#Ibn.paO#S#v#v#S#Sbgaoaoa0aoa0avaCaqaoavao.8#v.w#T.Y#3an#va#aOamaOa0bnaoambgamaoam.pa0bgb#aoaFaO.ybk#T.GaXaz.waBbyaCa0a0bnaCa0#Ibn#I#x#x#x#x#x#xaC#x#I#x#I#x#I.C#IaY#saY#saY#D#M#D#s#D#M#D#M#D#D#D.n#M#D.s#DawaYaw#x#IaYaw#sa9.7.n.7#L.7aj.7#L#L#L#L#L#L#L#L#L#L#L", +"#L#g#L#g#g#gbp#L#L#L#L.7af.7.7.7#D.N#xaob#.8a#a##DaY#D#D#D#Da9bjbl#D#Dbl#Dbl#D#DaY#DaY#D#M#DaYaYaYawaY#x#Ibna0aCbgb#bg.VaCbn#U#xaw.Raw#FaYblaYbl#D#p#Da9#Da9a9#Dafaj#Laf#Lajaf.7a9#Da9#sa9#D.Nbl.NaY.NaYaY#I.C.Wamaoaoaobga0aoa0aCam#vaBa##SaBaBaobgaoaoaC.Waqaoav.8ao.5aOaBazaX#4alaza##vaOam.5aC.Wa0.Wa0aob#.8bnaCaCaCaC.W.WaC.y.yaB#ubkbkaX.Oazae#vaO.5ao.pbga0a0a0#Ua0aCa0ao.CaCaCa0#IaCa0#IaYaw#D.sbl#s.N#s#Dbl#D#s#D#D#sbl#D#D#saYaw.saw.NaC#xaw#D#sa9.n.7a9aja9#La9aja9#L#L#L#L#L#L#L#L#L", +"#Lbp#ga2bpa2#L#g#L#L#L#L#L#L#LafbjaYaY#xama0.5aO.N.NaY.s#D#D#Da9#Dbl#s#Dbl#Dbl#D#M#D#M#DaYblaw#D#MaY#I.R#U#x#U#Ub#b#bga0aCa0#x.R.Raw.RaYawaYblaw#p.n#pa9.na9#Da9aja9af.Eaf#Lafajafaja9#Da9#s#Daw#D#s#D#s.NaY.NaY#U#Ua0.paobgb#bgaO#vaB#u#u.y#ua5aObgaoamaoamaoavam.8.8#v#v#u.w.GaTbw.G.0#vaFaoamaoa0aoama0aqamaoamaCaqaC.W.W#I#Iaxbgaobg#va7.Oau.U#3#3a5#uaB#vaFaoaoa0amaCamaob#aoamaoaoa0aC#Ibn.sawaY.sbl#saY#s#D#s#DaY#saY#D#D#s#p#s#DawaY#Iaw.C#I.N.naf.Ea9.7aj#L#Laj#L#L#Laj#L#L#L#L#L#L#L#L", +"a2#L#g#g#g#gbp#L#L#L#L#L.7#L.7#L.N.N.s#x#xao.5b#.NaY.N#D#D#D#D#D#M#D#Dbl#D#D#sbl#D#Dbl#Dbl.sblaY.NaY#x#I#x#U#UaC.Vbgb#bgaCaC#U#I.R#x.baY.RaYblaYa9#pa9#Da9#Da9bjaf#Laf#Laf#L#La9#La9a9a9.7#Da9#D#sa9a9a9#D.NaY.Na9#paY#Ua0aoaO.yaBaBazazan#u.Gbk.daOaO.8aoavao.8.8.8bd.yaL#uazaX#0#4#TaZaOaO.5aoa0.Camaoamaoamambcby.8.C.C.W.W.W#U.rbgaO#S.yaB#uaP#3.U#3arbk#u#vaFbgbgaob#aob#bgamaOaoaoaoaC#U#IawaY.sbl.s#D#Daw#DaY#s.N#M#D#s#D#s#D#M.NawaY.s#xaC.C#Ma9aj#L.7.naf#Laf#Lafaj#Laf#L#L#L#L#L#L#L#L", +"#g#g#Lbp#Lbp#Lbpa2a2#L#L#L#L.7#L#D.N.NaYbo.C.C.W.Vbn.N#Dbjbj.E.7#D#D#D#D#s#D#D#D#D#s#D#s#D#D#D#sawawaYaw#x#U#xaCa0aCa0aC.Vamb#a0aYaw.RaY#M#p#M#pajafaj#pa9a9#Mbl.na9a9a9a9a9a9afajafaja9#D#s#D#Dbl#D#s#D#s#D.n#Dbl#saYaYaw#x#IaCaOaB#1a5.w.wbkaV.Qbt.ybcbc.8bcbcaBaB#u#uaz.waP#T.O#zbw.6aF#vaOaFambga0amamaOaoaOaoaCa0.WaC.W.C#I.WaCaoaOaoaOaobg#v#v#S#1.Q#3agaV#1aB.8aOamaoaCbg#v.8aoa0aC#x#U#Iawaw#D.s#D#s#D#s.N#saY#s#Daw#D#Mbl#saYaw#x#I#xaC#D#sbj#D#D.7#s.7.7.E#L.7#Laf#L#La2a2a2#ga2#g#g#g", +"#gasbp#g#Lbp#Lbp#L#g#L#L#L.7af.7#D.NaYbf#x#x#x#xaCbn#I.N#Dbja9.7#D#D#D#D#D#D#D#D#D#D#D#D#D#s#D#DblawaYawbn#I.WbnaCa0.pa0aoa0aoam#UbnaYaYaYblblbl#paf#p.n#pa9bl#Da9a9a9aja9af.na9.7af.7a9a9a9#D#sa9#M#D#D#D#D#D#D#D#D#M.NaY#x#x#xa0am#vaB.z#u#Ebi#nbCaX.Q.y.y.QaXbka5#u#u.w.wbkaP.O#4#4.wa##v.5a#aoamambg.5aO.5a#aoamaC.WaC.W.W#IaCaC.WaCaoaoaoao.8bg.8#v#v#u#uaPagagaXbka5aBaBaB.y.z#S.8bgaoamaC#x#IaYaw#D#sbj#D.sbl.sbl.N#saY.s#D#MaYawaY#U#x#Ibj#s#Db.#Db.#Dbj.na9#La9aj.7#L#La2#ga2a2#g#gas#g", +"#ga2#ga2#g#g.7bpa2a2#L#L#L#L.7#L#D#D.N#M.N#I#x#xa0a0#x.s.N.N#D#D#D#s#D#D#D#D#D#s#D#s#D#D#s#D#D#M#D#MblawaYaw#x#I#Ubn#Ua0.pa0.pa0aCbn#Ubnaw.Rawbl.n#p#p#pa9a9bl#Dafa9a9#pa9a9a9afajafaja9.7#D.n#D#Dbl#D#s#D.n#D#s#D#D#DaY#saYaw.N#UbnaCaOaO#vaBbkbq#Rbqag#3.U#zaVau#Tazazbkbkbv#3#E#0ab.2#uaOaF#vaFaOaOaFaObyaO.8aCaCaC.C.W.W#I.W.WaCaC.WaC.WaCaCaCaCaoao.8.8#v#vbbbbap#3.U.U.U#4a5#E#1#SaFaOaOaFaC.W#x#IaY.s#D#saY.s#xawawaY.saY.sbl.NaY.s#x#x#Ia9.7.E.7.E.7.n.7a9#L.E#L.7#L#L.7#L#L#L#L#ga2bpbp", +"#g#g#L#gbp#g#Lbp#L#g#L#L#L#Laf.7#Da9#D#DaY.N.N.sbn#Ua0.C#x.N#s#D#D#D#D#D#s#D#D#Da9a9.na9a9a9a9#Dawbl#saYawaY#U#x#U#x#Ubn#Ibna0aCa0a0#UbnbnbnaY.Rbl.n#D#p.n#pa9bla9af.nafa9afa9a9#Laf#La9a9a9bja9a9a9.na9a9.7a9.7a9a9#s#D#DaY.Naw#xaw#xaCamaoaOaB.v.O.Obqadbx.abzbi.U#3#T#3bvagag#3#4#caT.w#vaF.y#v.5#vaOa#ao.5.5aC.CaC#I#I#I#Ibo#I#Iaw#Iawaw#I#U#7.W#IaC.WaCav.W.8#v#v.y.w.G#T#3.Oag.O.w#uaB.ya#aoamaC#x#I#x.N.s#xaw#I#x#Ibfaw.Nbl.s.Naw.NaY.saY.E.7af.Eaf.7#L.E.7aj.7#La9aj#Lafajafaja2#L#ga2#g", +"#ga2#ga2#Lbp#Lbpa2a2#L#L#L#L.7#La9.7a9#D#D#DaY.NaY#xa0#U.CaYbl#D#D#D#D#D#D#D#D#Da9a9#Da9#sa9.na9#D#M#Dbl#saYawaYawaYaYawbn#Ibn#IbnaC#xbn#Ibna0bnblblbl#Dblbla9a9.na9a9a9a9.na9a9af#L#L.na9bja9#D.na9a9a9.n.7.n.7.Ea9.7a9#s#D#D#D#sblaw#IaCaobg.d.O#ia5.G#zadadadabadaVaVbq#3#3bvbqaba8.YbkaBaO#uaFaOaFao.5aoaqaC#I#I#Iaw#I.s.sawbobo.sbo.sbobo.s#M#M.s#7aw#Iaw#I#U#IaCao.8aO#v#u.Q#3biag#3aXazaZ#vaOam.C#x#I#IaY#I#x#I#I#x#I#xaw.Naw#D#s#D#s#Da9#Laj#L#Laj#Laj#L#La9#L.E#L#L.7#Laf#Laf.7#L#L#L#L", +"a2a2#L#g#L#L#L#La2bp#L#L#L#L#L#L#L.7#La9.7#Da9#D#DaYbnama0#xaY#s#D#D#s#D#D#D#D#Daj#Lafajaf#La9a9.na9#M#D#MaY#MaYbl#MawaYaYaYaw#x.RaY.b#xbnbn#Ibnaw#xawbl#D#Ma9#pafa9afa9afa9afa9aj#Laf.7a9.n#Da9ajafa9aja9#L.7#Laf#L.E#L.7.Ea9#sblawaw#xaCaCaO.8aBazbka5.Gbk.U#3biad.a.a.DaVaVaV.M#d.S.Yaz#u.0.y#vaF.8a0.W.C#I.C#Iaw.Naw.s.s.s#s#s#s#s#s#s#s#s#s#s#s#s#M#s#s#s#s.n.n#M.raC#OaO#w#u#E.vbkazbkbkbk.w.yaOamaC.C.C#I#I#I#x#I#x#I#x#Ibf.s.N#s#D.7a9.E#L.E#L.E#L#L#L#L.7aj.7af#L#L#L#Laf.nafaj#L#L#Lbp", +"#gaa#ga2#L#L#L#Lbpa2#L#L#L.7#L.7#Laf#L#L#La9.7#D#saY#xa0ama0aYaY#D#D#D#D#Da9#D#Daf.7aja9#L.n#Laj#p.n#p#Dbl#s#DaY#sbl#D#MawaYaYaY#Mblbl.baYawbnbnaYaYaYaYbl#D#pa9a9a9a9a9a9a9a9a9afafaja9a9bja9#Dafafajaf#L.Eaf.Ea2#Lafaja9a9#s#D#sawaw#IaC.WaoaoaO#uae#1#u#uaz#u.O.Ubi.D#d.D#J.D.abu#6.Y.G.w.yaZ.8aoam.W#xaw#I.saw.saw.s.s#s#sbj.Eb.#sb.b.#sb..E#s#s#s#s.s#s.E#s#s#s#s.r#U#IaCaCbd#1#SaOao.ya5bkaza5.waOamaoaC#x.WaC.W#I#x#I#x#I.Naw#D#D#s.7#L.7#Laj#L#Laj#Laj#Laja9#L.E.7.n.7.Ea9a9a9a9a9.7#Laf", +"a2#g#L#g#L#L.7#La2#g#L#L#L#L#L#L#La2#Laf#Lbja9a9#DaY.C.VaFa0#xaw#D#D#D#D#D#D#D#Dajafaf#Laf#Lafaf#p.nbl.n#Dbl#M#D#Ma9#M#DaYaw#Dawbl#MaY#Mbn.RaYawbn#xaw#x#Mbla9.naf#paja9af.nafa9aja9#La9a9a9#s#Daja9#La9#Laf.7#L#Laj.n#L.7.n.7#s#Daw#x#I.CaC.8.8#v#v#v#vaO.z#1.z.Gbk.O#zbibBbBad.x#5#9.YaPaz.y.0bgaoam#Iaw.N#s#Dawaw.s#s#D#s#s#s.E.7.E.7.E.E.E.Eb..Eb..E.E.E.E.E.s.saw#IaC.WaC#Oam.d#vao.8aFaO.8.G#3.OaB.8amaCaCaC.Wa0#I#I#I#I#x.s.N#s#D.na9.n#Laj#L#Laj#Laj#Laj.7#L.7af#L#Laf#Lafa9a9.na9a9.7.7", +"#L#L#L#L#L#L#L#L#La2bpa2#ga2bp#L#L#L#L#L.7a9.7.7.NaY#xbnao.VaF.V#xaY#Ma9.na9a9#D#La9aja9aja9aj.7.na9.na9.na9.na9#p#s#p#D.na9a9.n#p.nbla9#sbl#saYaYaYaYaYaYaYaYaY#pa9#p#pa9#pa9.nafafaja9#D#D.N.N.nafajafaja9ajafajaf.7.na9#D.n#D#Dawaw#I.W#IaCaCaobdaO#v#v.y.y.y#u.QaX.9#TbC#r#r.aatatbB.2aX.GanaC.W#Ibobf.sbf#I#s#s#s#sb.b.bj#s.7.E.E.E.7.Ea9.Eaj#Lajajajajajaj.s#s#I.s.s#I.s.WaCaCaCaCa0.W.W.W#v#vbtbkbk#uaB.0aObgaoaoamaC.C.W.n.na9.E.7.E.7#Lbjb..Ea9aj#L#La2a2.jbpaj#L.E.7bjajaf#La9#Laf#Laf", +"#L#L#L#L#L#L#L#L#L#ga2a2bpa2a2a2#L#L#L#L#L.7#L.7#DaY#Ibnb#b#aOb##xaY#D#Da9.n.7#Dafajaf#Laf#Lafafa9aja9a9.na9.na9.na9.na9#p.na9a9afa9.n#p#D#M#DblaYawaYaw#xaw#xaY#p.na9a9a9a9#p#pafaf#pa9#D#s.N#sa9a9#La9#Laf#Laf.7aja9.n.7.n#Da9.saYaw#x#I#x.W.WaCao.8.8aObc#v.y#v#ubkbvbvaXbvbC.k.Dai.UaXbv.Ga7aOaoaNboaWbo.s.Nb.#sb.#D#s#sbjb.b.a9b.a9.E.7.Ebjajaja2aj#Laj.naj#D#s.sbo#I.sbo.saCaCaC#I#I#I.W#xavaoaO.y.z#1bkbkaBaBaO.5aoaoav.Wa9#s#L.E#L#L.7.E.7#D.7.E#L#L#Laja2bpa2#L#L#L#L.7af.7afajafaj#L#L", +"a2#La2#ga2#ga2#ga2#L#ga2a2#g#L#g#L#L#L.7af.7a9.7#Daw#x#xam#SaZa#aC#xaYa9a9a9#Da9aja9#L.n#L.n#Lajafa9.naf.na9a9.na9a9.na9.na9a9.n.na9a9.na9#D#D#saY#x.R#xaYbn#x#xblblbl#Mblbl#Dbl.n#p.nbl#D#D.N.N.naf.nafaja9#L.n#L#La9.7.n#D#s#saYaw#I#I#I#U#Ia0.Wao.8aObc.8.y.y#u#ubk#3bCapbkag.kbqaX.Q.Qbka5#u#v#vamava1bob..E.na9b..E#s.7.E.E.7.E.7.E.7.E.7.naj#L.jaja2ajajaj.n#D.s#I.s#I.saY#I#U#x#I#x#x#Ibo#x#I.CaoaO#v.y#1bkbk#u#vbcam.C#I#sa9.n.7.E#L.E.7#s#s.7.n#Lajbpa2bp.jbp.j#Laj#L#Lajafajaf#La2afa2", +"#ga2#ga2a2a2#g#La2#ga2#g#L#ga2a2#L#L#L#L.7.7#La9#D#D#xaCaF.0aZana0#xaYbla9.na9#D#Laf#Laf#Laf#La9af#L.na9af.nafa9ajaf#Laf#Lajaf#Lafajaf#L#D.n#D#DawaYaY#IaY#I#x#IaYawaYaYaYawaYawbl#Mbl#D#sbl.s#Da9.na9.7afajaf#Laf.Ea9.Ea9#sa9#s.N#I#x#I#x#Ia0#I.Wao.8.8aObc.ybba5bkaXaX#3bvag#n.c.#bt#baLbcbdaBaB.y#vam.Wbfb..7#s#s#s.7.E.E.E.7#s.E.E.7.n.7.E.7aj#g.ja2.jaja2#L.E.n#s.s.s#I.s.s#x#I#I#x.s#I.Nbo#x#I#I.CaoaoamaObkaz.Q.z#v.8.Wbf.N#s.N#s#D.sa9.E#D#D.E.7#L#Laj#Laj#g#L#g#L#gbp#L#L#L#L#L#La2bpa2", +"a2bpa2bpa2bpa2a2#g#La2bpa2a2bpa2#L#L#La9#L.7a9.E.7aYaY.Cam#vaZaZaobn#xbla9a9a9#s#L.n#L.n#L.n#Lajaf#Laf.na9a9ajaf#L#Laj#Laf#L#Laj#L#L#Laj.7a9.7a9#D#Dbl.NaYaY#xaY#xaY#x#U#xbn#IbnblaY#MaY.NaY#s#D.na9aja9af.7af.E#Laja9a9b.#D#s#Daw#x#I#I#x#I.Wbn.Wa0aoao.5.8.y.QazaX#3.O#3aVai#n#8aLax#O.W.Wao.8#1aB.y.5.Ca1bo.sbo#D#sb.#D.E.7aj.7.E#D.E.7.E.7.7.ja2.j#gbp.jaj.j.7#s#s#s#s.N.s#Iawaw#D.saw.N.s.s#D.s#x.W.WaoaC.8.0.y#v#v#v.d.8ao#I#Ibf.s#Db.bj.7#Dbj#L#Laj#L#L#La2aj#gaj#ga2asasa2a2a2a2#La2a2#g", +"#ga2a2a2#ga2a2#ga2a2#ga2a2#L#ga2#L#L#L#La9.7.7a9.7.N.s#xamaF#va#.5am#x.N#D.na9.7af#Laf#Laf#Lafa9#L.n#La9.naf#Laf#Lajaf#L#Laj#Lafa2ajaf#Laf.7.7.na9.n#D.nbl#D#DawaYawaY#U#x#U#x#UaYaw.Nblaw#D#D#sa9.na9.nafajaf#Lafaj.7.na9#sa9#saY#I#I#xaC#xao.CaCavaoao#v.yaI.Qae.O#zaV.Dah#Xag#b#O.r#7#7#7.W#QaObdaB.y#vaoaqbo#Ibobf.N.Ebj.E.7.E.E.7.E.7.E.7.Ebp.j#g#g.ja2#L.j.E.7#s.nb.#s#D.saw.Naw.s#D.s#s.N.s.sbo#I.C.Wam.8bgbgamao.C.8axbcaxaoaobo.N#s#Db.#s.7.E#L#L#L#Laj#L#g#La2#gas.jasbp.j#L#g.j#g#L#g", +"a2asa2asa2aa#ga2#g#L#g#Lbpa2#L#L#L#L#L.7.7.n.7.7a9.saYaY.Wa0amam.5am#IaYbla9a9a9aja9aja9aja9ajaf#Laf#L.na9#L.n#Lajaf#L.jafa2a2.ja2a2#Laj#Laja9#L#Laf#Lafa9.n#D#DaY#xaYaYaYawaY#U#xbnawaY.Naw#D#sa9.na9af.na9.na9.Ea9.na9.E#D#s#D#I#x#I#x.WaCaoaoao.8.8.8.y#1#1.Q#T#3bq.D#m#haibkavao#7aE.sbo.W.W.s.Wbd.GazaBbc.8##avbobfbobjbjb..7.7.E.7.E.7.E.7#g.j#g.j#g.jaja2.Eaj.n#D.nb.#sb.#D#s#s#D#s#D#s#s.s.N.N#I#x.Wam.WaC#x#I#xaCa0av.8.8.8ao.W#Ibo#s#s#Dbj.7#Lajaj#L#Laj#gaj#g#gasasaU#g#g#ga2bp#ga2#g", +"a2a2#ga2a2#ga2a2a2#ga2aja2bp.ja2#L.7#L#L.7a9.7a9bj.N.N.N#xa0a0aCaF.5bnaY#D.na9.7af#Laf#Laf#Laf#L.n#L.na9.naf#Laf#Laja2#La2aja2#La2aja2#Laf#L.E#L#Lajafaj#La9#L.nblblbl#MblaYaYawbn#U#x#xaw.N.s#D.nafa9.na9a9a9.na9aj.7#sa9#sa9#s#x#I#x.Wbnavamaoao.8aObd.ybt#ubbag.O#3bA.iaJ#3bbav.h#7b.b.boa1#IaE#I#QaB#uaPaz.Gbcbcavavbobfb.bj.E.7.E.7.7.E.7#L.j#g#g#gaj#g.jajaf.E.n#s#s#D.E#D#s#s#D.s#Db.aW#sbf.Nbo.C.Wav.Cam#Mblaw#x#Iaoaqaoaqavavaoav.s.Nb.#D#s.7.E#L#Laj#g#Lbpa2asas.jaUaU#ga2bpa2#g.jbpa2", +"#ga2#g#g#ga2#g#ga2#g#g#ga2#g#Lbpa2#L#L#L#L#La9.Ea9a9#saY#I.C.Wam#x#U#x#IaY.N#D#Daj#Laj.7.7a9.7.7a9#Laf#L#L#L.n#Lafafafajafaf#Laj#L#L#Laj#Laf#Laf.jaf#Laf#Laja9#Da9.na9#Da9.n#D#DawaYawawaYaY#MaY.7.n.7.n.7.Ea9.7ajaf.Ea9#s#D#D#D#Ibn#UaCaoao.8#vao.d.d.y.z.y#1bbagaX#3aAbx.caLav#7#I.s#7b.#sb.b..sbo#Iav#QaOaKbtau.GaZaFaq#Ibf.s.7.n#L.E#L.7aja3.Ebp.jbpbpajbpa3#s#D#s#s#s#s#D#sa9.n#D#s#D#s#D#s#x#Iaw#I.N#s#s#D#saY#saYaY#I#I#I#I#U.W#IaC.8ao.C#sa9#L.7.n#L#L#L.ja2.j#gasasas.jas#g.jas#gas#gas", +"a2#ga2#ga2#g#ga2#ga2a2bp#ga2bp#Lbpa2#L#Laja9.7#La9#D#D.N#x#x.C.CbnbnbnaYaY#D#D#D#L#La9aja9.7.E#D.nafajaf.Eafafaj#Lajaf#Lafajafaf#Lafajaf#L#Laj#L#La2afaj#La9a9.na9bja9.na9#D.na9awblaYawaYawaYawa9.na9.Ea9a9.na9ajaj#L.n#D#s#s.N#U#Ibn.WamaO.8#v#OaObdbd.yaLbb.Q#8.v#3aV.abCbd.8#7#7.sb..sb..sbj#s.s.s#I.Cav.8.8#u#uaB.ybcao.Wbf#D#s#D.7.E.7.Ea3ajbpajbpajbp#L.E#s#D#s#D#s#D#s#D.n.7#s#D#s#D.s.N#x#I.NaY.s.N#s#D#s#D#M.N.s#I#x#I#x#I#x#IaCbd.8ao#s#D#s#L.7aj#L#L.j#gas#g#g.j#gas.jas#gas#g.j#g#g", +"#g#La2#ga2#ga2bpa2bpa2#L#L#L#g#La2aj#L#L.7.7a9.7.n#D#saY.s.N#x#I#x#xawaY#Ibl.N.Naf.E#La9.7#sa9#D.n#Laf#Laf#La9afaf#Lajaf#Lafaj#Laj#L#L#Lajaf#Laf.j#Laf#Laf#La9a9a9a9.n#Da9.na9#D#D#s.N#s#D#s.N#s#D.Ea9a9.Ea9.7.na9.na9#s#D.s.N#x#Ibnbn.Waobg.8.8.d.d#vbd#v.z#1bb.QaX#3aA.kaXbcao#7.s.sb.b.b.b.#s#s#D.s.N.s#x.CavaFam#v.y#u.ybyby#Ibf.s.Nb..7.E#L.7.E#L.7.E.7.E.7#s#s#D#s#D#s#D#s#D#s#D#s#D.s.N.s#x#IaYbo.s#D#saW.n.7#s#D#s.N.s.s#I#I#I.CaCax#vaO.saw#s#D.n#Lafaja2a2.j#gas#g#g#g#g#g.j#g#gas#g.j", +"#ga2#ga2#g#L#ga2#ga2#g#L#g#L#L#L#g#L#L#L#L.n#L.7#D#D#D#DaYaY.N.NawaY#xaY#x.NaY#Ma9.7a9.Ea9#D#Da9a9af.7af.Eafaj#Lajafafafaj#Lafaf#Lafaj#Laf#Laj#La2af.j#Laf#La9.7a9.7a9.7a9#Da9a9#s#Dbl.saY#saY#s#D#s#D.na9.Ea9.7a9.n#D#s.N.s#xbobna0aCa0am.8aOaO.8#vbd#vbd.yaL#1.Qbk.Obi#R#8#v.rbo.saE#sb.#sbjb..7.E.n.E#s.s#I#xbo.Wavbc.y#u.yanaoaq.Cbo.N#D.E.7.E.7#L.E.7.E.7#s#D#s#D#s#D#s#D#D#s#s#s.N#s.Naw.N#x#xaw.N#s#D#sbj.n.7.E#DaE#saYboaCaCaoaoaoao#Oao#Iawaw#s#D.n.7a9aj#g#L#g.j#ga2#g.jas#gas.j#gasas", +"a2bp.jbpa2#ga2bpa2bpa2#L#Lbp#L#L#La2#L.7#L.7a9.7#s#D#D#D#D#s.NaYaYaY.s#x.s#xaYaY#D#s#D#D#D#s#D#sa9ajaf#Laf#La9af#Lajaf#Lafajafaj#L#Lafaj#L#L#L#L#L.jafa2#Laja9a9.na9a9.na9.na9#s#D#D#s#D#s#D#s#D#sa9#sa9#Da9.n#D#s#D#D.saY#xaY#IamaCamaobgaObcbdaOax#vbd#v#v.yaL#1.Qa5#3#R.vbc.W#7#s.sb.b.bjb.bj.E.7.Ea9bj#s#Daw#s.Nbo.C.8#van#ubc#v.8a0bf.s#D#sbj.7bj.7#D.7#sbjawaY#saY#s#D#s#Daw#DaY.saY.NaY.saY.saY.N.s#D#s#D.Ea9#s#s.N.sboawao.8.d.daoaC#I#x.sawbo#M#D#Daj.7#L#L.jbpa2bpa2#g#g#g.j#gas#gas#g", +"#ga2#ga2#g#L#g.ja2#g.jbpa2aj#Lbpaj#L#Laj#Laf.7af#D#D#s#D#D#D#D#D.N.saYaY#xaY#x#IaY.N#D#D#s#D#Da9#L.na9.na9ajafajaf#Lafajaf#Laf#Lafaj#L#Lajaf#L#La2a2a2#Laf#La9a9.7a9.7#Da9bja9a9.7#sa9#D#s#D#s#D#s#D#D#s#D#s#D#sa9#s.NawaY#I.C.WaF.8b#ao.8bg#vbd.8#vbd#vbd#v.d#v#1#1.wagbi#8ao#O.saE.sb.#sb.#s.Eaf.Ea9.E.n#D#s#Db.#s.N#Iaqambca#aB.y#vaO#I.Cbf#I#s#Db.#Db.#Dbj#saYawaw#D.saY#M.N#M.N#saY.s#x.s#x.s#x.s.N#s#Db.#D#Db..N.s.N#Ibo.W.CaoaxaoaxaCaC#I#x#I#I#Iaw#s#D.n#Laj#L#Lbp#L#L#L.j#ga2#g.ja2.j#g", +"#L#g#L#g.j#ga2bp#g#L#g#L#Lbp#L#L#La2.7#L.7.Ea9.EaY#D#D#s#D#s#D#saYbl.NawaY#UbnbnawaYawbl#D#p.na9afa9.n#La9#La9#Lajaf#Lafajafajaf#L#Laf#L#L#La2.ja2#La2#L#Laf.7a9a9a9a9.na9.na9a9.7a9#s#D.n#D#s#D#s.N#sbj#D#D#s#DblaYaw#x#I.CaCamaOaF.8.8aO#vbdaO#v.d#vaO.8aObd#v.zaBa5.O#r.Q#O.Wbo.s.sb.aEbjb.bjb.a9.E.7.n#s#D#s#D#D.s.N#Ibf.W.C#v#va#aOaF.8aoam.s#D#s#D#s#D#s.saYawaYaYawblaYaw#DaYaYaYbl.N#x#xaY.saY.N#s.N#saWawaY#I#x#I#x#IaC.C.WamaCaC.W#I#I#I#x#I#I#I.s#sa9.E#L.E#Laja2bpa2a2.j#ga2#ga2#ga2", +"aj#g.ja2#g#L#ga2#ga2#ga2bpa2#L#L#Lajaf.Eaf.7a9.7aY#s#D#D#D#Da9a9.saY.saYbn#x#xa0#I#x.NaY#M#Da9.na9aja9a9.nafajafafafajaf#Laf#Lafaj#Lajafaja2#L#La2.3#L.jaf#L.na9.7.n.7a9bja9#D.n.7#sa9.n#D#s#D#s#D#s#D#D#s#D#s#DawaY#Ibn#Ia0aoa0#v#vaOaFaObd#vax.ybc.d.8.8.8.8bd.y#1a5aX.v#1ao.W#7.saE.s#sb.#Db.#s.7.E#D#s#D#sa9#s#D#s#D#s#D.s.saFaFamaO.y#v#v.5#I#Iawbf.s#x.s#xawaYawaYblaw#DblaY#Mbl#saYaw#x#I#x.Naw.N#sbj#s#D#I.WaC.WaC.Wamao.8aoao.W#IaY.NaY.N.N.s#D.saw#s#D.n.Ea9aj#Laj#Laj#ga2#gas.j#g.j#g", +"a2#ga2#ga2aj#L#L.ja2a2aj#L.E#Laj#pa9a9#pa9.n#pa9#M#Dbl#Dbl#MaYaYaYawaYaYawaY#UaYa0.p.VbnaYawa9#La9a9ajaf#L#Lafaj#L#L#Laj#Laj#L#Laf#L#L#L#L#La2#La2a2#La2#La2#L#L#L#L#L.Ea9.7#s#D#La9.E#D.na9.na9.n#s#D#saw.Naw#xaw#I#x#I#U.CaCaoao.VaoaoaO.8aO.8#Oaoaxao.haC#Oao.daO#uagbibk#vav.W#I#s.E.Eaj.Ea3aj.n#L.E.7.nb.#s.N.saY.N#I.N#IaY#I#I.C.8#v.yaBaPaBa#aFa#.5aqaqaN#xbfbf.N.NaY.Naw.NaYaY.Naw.NbfaYawaYaYaw#x#I#xa1#U#I#U#I#x#I.N.s#D#s#D#Dbj#sbj.E.7.Ea9.7.7#L.7.7.7.7.E.7#L.7#Lbpa2.jas#g#gas#gas", +"a2.ja2#L.j#L#La2a2#g#L#Laf#L.7#La9#pa9a9#pa9#pa9bl#Dbl#sbl.NblawblaYblaY#xaYaY#Ubna0b##UbnaY.n.7#s#Da9.na9.n#Laf#Lajaf#Laf#Lafaj#Lajafaj#L#L#L.j#L.j#La2af#La9a9#L.7#L#La9.7a9#Da9.Ea9.n.7.n.7#s.na9#M#Daw#x.s#xawbn#I#U.CaCaCaCaobgaCaoaOaOax#vao.hao.W.W.Wav.haoax.y#E#zagapbc.Wbo.s#s.E.Ea3.E.7aja9.Ea9b.a9.EaY.Naw.Naw.Naw.N#I#x#Ia0amaF.yaBa7#u.ya#aoaqavaq#x.C#x#I.Naw.NaYaw#x#I#I#x.s#xboaYaY#I#x#I#x#IbfblaYbl.NaY#D.N.N#Dbj#sbj.Ebj.7bja9#L.E#Laj#Laj#L.E#L#L.7aj#La3ajas#g.jas.j#g.j#g", +"a2#gas.ja2#L#Laja2#Laj#L#L#La9.7.na9a9#Da9#Da9a9#s#D#D#s#D#s#D#Dbl#sbl#D#M#DaYaYaY#Ubga0bnaY#s#D#s#Da9a9.na9ajafaj#Laj#Laj#L#Laf#L#L#Laf#L.j#L#La2a2#La2#Lafa9a9ajafaja9a9#s#D#s#Da9.n#D#sbl#s#D#M#s#D#Maw.N#I#I#I#I#x#I#IaC.CaC.paCaCaoao#O.8ao.h.W.W.W.W.W.W.W#I#Q#v.w.Obiagbk.W.r#I#sb..E.E.Eaja9.E.n.7.n#D.saY.saY.Naw.NaY.Naw.N.s#xaCaq.8aF#Sa7a7#u.yaFam.5ao.Ca0.C#x#x#x#Ibn.R#x#x#xaY#xaY#Ibn#UaC.W#xbf.sbl#s#D#sa9.Ea9.7.E.7.7#L#L#Laj#Laj#L#L#L#L#L#L#Lbpajbp#Lbpbp#Lbp#g#gas#g#gas#gas", +"a2.ja2#La2aja2#L#L#Laf#L.Ea9aja9a9a9a9.na9a9.na9#D.n#Da9#Da9a9.na9a9#sa9#D#D#D#saY#xaCa0#U#x.N#s#D#D.na9a9.n#La9#L.n#Laf#Laf#Lajafaj#Laj#Laf#L#Lafajafafaj#L.Ea9#La9a9.n#D#D#D#D#D#s.Nbl#D#s.N#M#D#M#D.saYawaw#IaY#I#U#I#x#IaC.WaC.CaC#IaCavao.W.Wav.W.Wbo#I.W.Wbo.W#Q.y.w.Uau#3bd.8bo.s#s#sbjb.a9.E.n.7b.#sbj#s.Naw.Naw.NaY.saY#s#s#D#I#x#Ia0aoaFa#aBaBaBa##va#aoa0aoa0aoa0aC.Ca0#xaCbn#I#xaw#xa0aCa0#x.Caw.N.Na9a9a9a9.7a9.Ebj#L#Laj#L.E#L.7#L#L#Laj#L#Laj#Lajbp#L#Lbpajbpaj#Las.j#g.jas#g.j#g", +"a2a2a2.ja2#Laf#Lajaf#Laja9a9.7a9a9.na9a9a9a9a9a9.7a9.7.n.7.7a9.7.7#L.7a9#s#D#D#D#D#Mbnbn#x#xaY.N.s#D#D#sa9a9#Laj#L#L#Laj#Laj#L#L#Laf#Lafaj#Laj#La2a2afajafafa9a9a9.na9#Da9#s#D#D#MaYblawaYawaYbl.s.Naw#D.saYawawawaw.s#I#I.C.W.W#U#I#I#x.WaC.W.W.W#I#Ibo#xbo#I#Ibo.Wavbc.y#u.G#3.Qbc.Wbfaw.s#sbj.n.7.n.7#s#D.s#D.saY.NaY.N#M.NaYb.#D#s#Daw#Ia0#UaFaOamam.5.8.yaB.8aO.5ao.5amam.8amaCa0a0#x.C#I#Iaoam#I#xaY#D.N#Da9.7.7.7a9.7.7.7aj#L#L#L#L#Lajbp#Lbp#L#Laj#L#L#L#Lajbpaj#L#Lbp#L.j#gas#gas#gas#g", +"a2a2.j#La2#L#L#Laf#Lafa9a9a9#D#D.7#Laf#L#Lajafaj.7aj#L#L#L#Laj.7aj#Laj#Lbj.7.7b.a9#D#D#xaCa0.W.NaYaw#D#Da9.na9af#Lafajaf#Laf#Lafaj#Laj#L#L#Laf#L.3ajaf#La9aj.7a9a9a9a9a9bl#DblaY#DaY.NawaYblawaY.NaYaw.sbl#s#Maw.N.saw#x#I#I#I.C#I#x#I#I.W#Ibo#Ibo.Wbf#Ibo#Ibfbo#Ibo.W.8#Qbc.ybkbv.Q.8#I.s.s#s#sb..nbj#s.N#sbj#saY.Naw.saY.NaY.s#D#s.Nbo.N#I#I#xaCamao.Ca0b#aobyaOaF#v#vaB.y.ya#aOaF.5aCa0aC.CaCbn#xaY#D#D#D.7#D#Laj#L#Laj#L.7#L#Laj#L#Lajbp#Laj#L#gaja2bpa2bp#g.jas#gas#gas.j#gas#g#g#g.j#g.j#g", +"a2.ja2#L.j#Lajafajafa9a9a9#Da9.n#L#L.7#L#L#L.7#Laf#L#L#Laf#Laf#L#L#L#Laj#Laj.7.7#L.n#DaY#x.W.C.C.s.NaY#s#D#Da9#s#Laj#L#Laj#Laj#Laf#Laf#Lajafaj#Laja2afajafafa9.na9#pa9#M#Dbl#DaYaYaYawaY#xaYaYaYaw.Naw#D#sbl#s#M#s#saY.s.s#x#I#I#Iawawawbo.N.s#I.s.s.sbo.N.s.s#I#I#x#Ia1.Wao#vaLbkap.yaobo.N.N.s.7#s#sbj#s#D.sbjaY.saY.Nbl.saY.N.s.N.s.N.N#I#x.sbfbf.C.WaCaqamaq.5aoa##v.0#u#u#ua##vaOaFama0#x#xaYaY#D#Da9.7#L.Eaf#Lafaj#Lbpbp#Lbpa2bp.jbpa2#L#ga2aj#g#L.jbp.j#L#g#g.j#g.j#gas#g.j#g.jas#gas#gas", +"a2#L.ja2a2#L#L#Lafafa9.na9a9a9#D.7#L#Laj.7#L#L#L#L#Laj#L#Laj#Lajbpaj#Lbp#L.7.7bj#L.7#DaY#xa0.C.WaYaw.N#D#D#D#sa9aj#L.Eafajaf#Laf#Laj#Laj#L#L#L#L.3#L#Laf.7#La9a9a9a9#p#Dblbl.NblawaYaYaYaYawaYawaY.NaY.sbl#sa9.n#D#D#saw.s#I#I#xaw#x.saY.s.s.N.s.N.s.Naw#D.s.N.sbn#I#Iboa1#b.d.8#Tap.Qbcbo#D#sbo.nb.#D#s.Nb.#D.s.Naw.Naw.NaY.Naw.Nbf.s.N.sbfaY.N.saY.sbf.C.Waqavbga#a#a#.yaZ.0anaBbm#vaOaobn#I#xblaY#Ma9a9af#La2#L#L#Lbp#Lbpaj#L#g.ja2bpa2aj#gaja2#g#L#g#L#g#L#g.j#gas#gas#g.j#gas#gas.j#g#g.j#g", +"as.j#g#La2aj#Laja9ajaf#L#L.n#Laf#Laj#L#L#La2#ga2#ga2a2a2#ga2a2#g#L#Lbpaj#Laj#Laj#D.s#DblaY.VaObm.C#IaYaw#D#s#D#Dbl#Ma9a9af.7aj#Lajaf#Laf#Lajafaj#Lajafaj#Laj#L#Lajafa9a9.7#sa9#DaYaYaYaYaY#xaY#x.N#s#D#s#D#s#Db..n#sbj.n#D.sbfbo.s.s.N.s.N.s.s.N#s#D#s#D.s.N#Ibf.s#Ibo#I.Wav.8bcbta5.U#3aB.5.W.N#x#I#x.saY.s.N.N.s#D#Ma9b..E.7.nbfaw.NaY#xaY#Ibf#D#s.N.N#x.Waqavb#ambga#aO.0.y.yaoaCa0#x#xaY.N#D.Ebj.7.7.7.7.7.7#ga2#ga2#ga2#g#ga2#ga2aj#g#g#L#g#g#L.jbp#Lajbp#L#g.jas.jas#gas.j#ga2#ga2#g.jas#g", +".ja2#Laj#L#L.7.7af#Lafajaf#Laf#Lbpa2#La2#L#L#Lbp.ja2#g#ga2#ga2#g#L#L#L#L#L#L#L#L.7#D.NaYaYaobmaZamaCbn#x.NaY.N.N#Mbla9.nafajaf.7a9#Laj#Lajaf#L#Laf#L#L#Laf#Lafaja9af.7.n#Da9bja9#xawaYaYawaYaYaw#Dbl#s#D#D#s.7.n.7b..nbj#sbj.s.saw.s#D#saw#D.s#D#s#s.s.N.sbfawbf#Ibf.sbo#Iav.8bc#uaz#3bi.G#vaq.W#I#x#I#x#x#x.s#DaY#s#D#s#D#s#Db.aY.saY.N#I#I#x#x#I#x#I.C.WaqamamaFaObm#vaBaZ#va#bna0#xaYaw#D#D#Dbj.7.7.7.7.7.7.7#g.ja2#g.j#ga2bpa2a2a2#g#La2#L#g.j#g#gajbpbp#Lbp.j#gas#g#g.j#gas#g.j#g.ja2a2#ga2", +"#L#L#L#L#L.na9.n#Lafajaf#L#L.ja2#L#Lbp#Laj#g#L#L#gbp.j#L#gaj#ga2aj#g#Lbpajbp#Laj.7#D#sblaYb#aOa7b#amaoa0aC#x.baYbl#Mbla9#D#L.na9aj#Laf#L#Laj#Laj#Lajafaj#L#Laj#Lafajaf.7a9a9#Da9#Dblblblblblblbl#D#s#D#D.n.7.E.7.E.7.7.E#s#s#D.s.N.s#Db.#D#s#D#sbj#s#D#s.N.sbfboaYbo#Ibf.Wavbcbc.wa5au.M#3.w#v.5#Ibn#I#IaY.s.N.N#saY#s#D.s#D.s.NawaYawaY#I.C#Ibn.Wa0amamao.5.8.5#uanaB.ya#aoama0awaYaY.NaY#D#D#D#L#L#Lbp#L#L#L#Laj#gbpa2bpa2.j#g.j#L.j#L.jbp#g#Las#ga2#ga2aj#L#L#g.j#g.j#ga2#g.ja2#ga2#g#Laj#Laj", +"#D.na9#sa9#Da9#Daj#L#L#Lajaf#L#L#g.ja2#g#g#g.j#ga2a2#g#ga2#ga2bp#ga2#ga2#ga2#g#g#Lb.a9aY#UambmaZaO.t#SaFb#a0a0#UblaY#s#D.na9.7.n.7aj#Lajaf#Laf#Laf#L#Lafaj#Laf#L#Laf.7af.7.n.7#D#M#D#D#D#D#D#D#s#D#Da9#sa9.Ea9aj.7.E.E.7.7b.#sbj.s#s#D#s.N#saW#s.N#s.Nb..N.Nbo.N#xbo#x#I.Wav.8.yaz#T#3#z#z.O#uaF.CaC.C#x#I.Naw#D.sbl.saY.s.Nbo#Ibn#U#x#Ua0#Ua0aCb#am.8a##va#aBan#u#u.0aFama0#xaY.NaY#D#s#D.7.7.7#Lbpaj#Lbpajbp#Lbp#L#L#L#Lbp#L#L#L#L#Lbp#L#Lajbpas.ja2.j#ga2bp#Laja2#L#La2aja2#L#L#L#Laj#L#Laj#L", +"a9a9a9a9a9.na9a9#Lafajaf#L#La2a2aj#g#ga2#L#g#L#g.j#g#g.j#g#g.j#ga2#gaj#ga2#ga2#g#L#L#L#s#xb#aOa#.t#SaZaBbmbga0bnawaYblbl#Da9.n.7#Laf#L#Laj#Laj#L#Lajaf#L#L#Laj#Lajafajaf#La9a9a9#D#D.na9a9.na9a9a9.na9.7a9.E#L.Eafaj.7.E.7.nbj#s#Db.#Dbj#sbj#sbj#sbj#D#s.N.s.N#x.W#xbo#xavambcbb.O.O#a#a.Oba#3aBamaoa0.W#x.s.N#saY#saY#I#x#I#x#IaCa0aoamaob#aoamaF#v#vaB.0aB.0#ua#a#.5ao#xaY.Nbl#sbl#Da9.7.n.7.7aj#L#L#L#L#La2#Laj#Laj#L#g#L#L#Laj#Laj#L#L#Lbp#L.j#g#L#L#Laj.7#L#Laj#Laj#Laj#Laj.7aja9#La9aja9a9", +"#Da9#s#L.n#L#L#Laj#L#L#g#L.jbpa2#ga2#g.j#gas#gas#g#g#g#g.j#g#gas.j#g#g#g#g.jas#g#gaj#L#D#xaOaZan.FbmaBaZbmaFb##UaYblawaY#s#Da9.7.n#Laj#Laf#Lafajaf#L#Lajafajaf#L.3#Laf#La9aj.7a9#Ma9a9#Da9#Da9#Da9#D#La9aj.7aj#L.E#Laj.7.Ebj.nb.#s#D#sbj#s.N#s#D.s#D#sbj.N.sbf.s.C.Wa0.Wam.8.ybb#a.O.GaPaz.M#C.faOaoaq.W#xaw#D.s#D#I.N#I#xaCamaoaFaO#vaO#S.y#S#v#v#S#va#aOaFaOaFamaoa0#xaY#D#sa9#D#Da9.7.7#L#L#La2#L#g#L#g#Lajbp#L#Lbp#Laj#Laj#L#Laf#L#Laj#Lajbp#L#Laj#L.n.7a9#sa9.n.7.nbj.nbj.na9a9a9.na9#Da9a9", +".7#L#L#L#L#Laja2#L.jbp.j#L#g#L.j#g#g#gasas.jas#g.jas.jasasas.jas#gas.jasas#gas#gasbp#L.7awam.yan.Fbm.TaZaBaFam.R#IaYawbl.N#s#D#D#Lajaf#Laj#L#L#L#Lajaf#L#L#L#Laj#L.jafajafafafaja9#Da9a9a9a9a9.n#Lajaf.E#L#Laj.7.j#Laj#L.E.7.E#D#saW#D#sbj#sbj#Db.#DaE#D.sbf#IbfaCaq.Waoao#v.y.wbkaz.w.waz#3biau#uaOamao#xboaw.N.s#x#I#xaCambgbg#uaBa7#ua7an#ubh#vaFaOama0aCa0a0a0bn#UaY#sa9af#L#sa9.7a9aj#Lbpaj#g#L.j#gaj#g#L#Laj#Laj#L#L#Lbp#L.E#L.E#L#L#L.7#L.n.7a9#D#D.N.s.Na9#s#Da9#sa9#D.n#D#D#s#D#D#s#D.7", +"aj.7aj#gaj#gas.ja2bpa2#L#gaja2bpas.jas#gas#g.jasasasasas.jasaU.j#gas#gas#gas#gas#g.ja2#LaYa0.0aZ.Fa#aBaZa#aFbn#UaYaY.N#MaY#D#D#Daj#L#Laf#Lafajafajaf#L#Lajafaj#L.3#La2af#L.Eaf.7a9a9.n.7a9.n.7a9af#Laf#Lafaj#L#L.j#g.E#L.E.7#s.Ebj#s#sbj#D.s#Db..N#s#D.s.sbf.s#Iaqa0ao.C.8#vbbaPbk#u.w.Q.w.wau#N.Q.yavam#I#x.sawaY#I#IaCaoaoaO#vaz.Gaz.GazaS#uanaoaCa0.Wa0.CaC.CawaY#Da9a9#La9aja9a9.7aj#L#L#Lbpaja2bpa2bpa2#Laj#L#L#L#L#Laj#Laj#La9#L.7.7.E.7.E#D#D.N.s.N.s.N#x.7.7.n.7a9#sa9#D#s#D#D#D#D.7#D#D", +"#g#g.j#g#g#g.j#g#g.j#g.j#g#g#g.j#g#gas#gas#gas#g.jasasasas#gasasas#gas.jas#g.jas#g#g#ga2a9.C#SbhaFbgamam.8amaCa0aYaYaY#Da9.E#Laja9#Laj#Laj#L#L#L#L#Lajaf#L#Laf#Laja2ajaf#Lafa9a9.na9a9a9a9.7a9a9af.n#Lajaf.7#L.E#Lbpaj#g.n.7#s.N.s#DaY.saY.Naw#x.saYbo#x#x#I#x#I.8amaob##v#u.G.2bkaz#ubbaP.w.G.2.u.Oa#aoav#Ibfboawbo#xaoamaBan.Gba#a#ua#ao.5#Qaq.W#x#x#x#I#x#xaY#xawaYbl#D#M#Da9a9a9a9a9.7a9a9a9#L#Lajaf#Lajaf#La9.n#D#saY.NaYaY.N#sbl#D#MaY#M#D#D.n#Da9#D#D#D.n#Laj#L#L.E#Laj#L.7aj#Laj#Laj#Laj", +"#g.j#gas.j#gas.j#ga2a2#ga2.jas#gas.j#g.jas#g.jas#g#g.j#gas#gas#g.jas#gas#gasas#g#g#La2.j.7bnaF#ub#b#amb#ama0bn.CaY#M.N#sa9.na9#Lajaf#Laf#Lafajafaj#Laf#Laj#Laj#La2afafaj#L#La9.7a9.7a9.7a9a9a9.7afafafa9#L.n#L.7ajaja2.j.7.E#D.N#Daw.Naw.N#I#x#x#I#x#I#x#IaC.CaC.5bg.8aO.0.w#T.2.G#u.ybbbb#u.GaX.e#z#SaoaC.s.W.W#I#Iaoam#v#u.G#TarazbmaoamavaN.C#x#xawaY#x#IaY.saY#Daw#D#Da9a9a9#sa9.na9a9.na9.na9a9a9#sa9#Da9#sa9a9a9#D#Mbl.NawblblaY#MaYaYaYaw#D#D#s#D#D.n#D#D.n#La9ajaf#Laf#Laj#L#L#L#L#L#L#L", +"#g#g#g#gas#g#g#ga2.j#g.j#gas#g.j#g#gasas#g.jas#g.jas#gas.jas#gasas#gas#gas#g#gasa2aj#g#La9aYa0bmbgambgama0.C#x#xawaY.N#Da9.7#L#Laf#Laj#Laj#Laf#L#Lafaj#Laf#Laf#Laja2#Lafaf#L.na9.na9a9a9.Ea9a9.7ajafajaf#L.7#L.7bp.Ebp.Eaj.7#s.Naw.Naw.Naw#x#I.N#I#x#I.C.Wa0aoamao.5ao#vaBazal#3aB#vaF.y.yaB#u.wa6#z.w.8.C.Wam.CaoamaO#v#uaz.G.GaBaFama0#xawbfa1aY.NaY.NaYaY.NaY.N#D#D#D#Da9a9a9a9.7#D.n#D.7a9a9#D#s#D#D#D#s#D#Da9.na9a9#D#Daw.N#D#s#D#D#D#s#D#D.7.7.7.7.E.7.7.7#L#Laj#L#Laj#L#L#Laj#Lajbpaj#Lbp", +"as.jas.j#g.jas.ja2#ga2as#g.j#gas.j#g#g.jas#g#gas#g.j#g#gas#gas#gas.j#gas.jasas.j#ga2#gaj#LaY#Uamb#ama0a0aCbn#Ibn.Nblaw#Da9aja9aj#Laj#L#Laf#L#Lafaj#L#Laj#L#Laj#L.3aj.3#L#L#La9.7a9a9.7a9a9.7a9a9afa9#La9aj#L.n#L.E.7aj#L.E#D.sbfaw#M.NaY.s#x#IaY.C.W.C.W.Caqaqao.5aoaF#v#uaz#T.o#vaO.8.8bcbcaB#ualbaa5#vaoa0avaoaF#vbm#uaz#u#uaZa0am#x#M.N.N.N.N#D.Naw.N#s#D#D#D#D#sa9#Da9.n#L#L.na9a9.7a9a9.7#s#D#D#Da9#Da9#D#s#Laf.7a9.n#Da9a9#L.7#L.7aj.7#L#Laj#Laj#L#L#Laj#L.j#L#La2#La2#La2ajbp#Lbpa2#L#ga2", +"#g#g#g#gas#g#gas.j#g.j#g#gas#ga2#gas.j#g#g.jas.j#gas#g.jas#gas#gas#gas#gas#gas#gaa.j#g#L#LbjaY#Ua0aCa0a0#xbn#xawbl.N#D#Da9.7#L#Laf#Lafaj#Laj#L#Laf#Laf#Lafajaf#L#La2#Lajaf#La9a9.n.7a9a9a9a9a9#Lafafajafaf.7#L.7#L.7#Laja9#saY#IaY.saY.saY#I#x.s.C#xaC#x.Caoaqamao.8a##v#u.Ga5azaOaOaoao.8#v.ya5ba#z.w#vao.Wam#vaB#uaB#uaZa#aF.5#xawaYbla9.E#D#sa9#sa9#D.7.7a9#s.7a9.7.7#L#L#L#L#L#Lajaf#L#Lajafa9.7.na9a9.7a9a9.7aj#L.7#L.E#Lajafajaf#Laf#Lajaf#L#L#L#Laj#L#L#L#La2aj#gaj#gaj#g#La2.jbp.jbp.jbp", +"as.jas#g.jas.j#ga2as#gas.j#g.j#g.j#gas#ga2#g#gas#g.jas#gas#gas.j#gas#gas#gas#gas#g#ga2bp#L.na9bla0bnbn#UaYawaYaYaYbl#Da9.n.7afaj#Laj#L#L#L#Lafaj#Laj#Laj#L#L#L#L.ja2a2a2af#L.n.7a9a9a9a9.7.n.7a9afaf#Lafaj.7af.E#Laj#L.Ea9aw#x#IaY.saY.NawbfaY#x#I#x#I.C#I.C.Wa0.8am#v.0#u.G.w#uaO#v.8#Q.8bdbb.Q.K#z#u#vaFaoaBa7a7#u#SaFaoamaCbnaYaY#Da9aja9a9bj.7a9.7a9.Ea9.7.7af.7#L#Laj#L#La2ajafaf#L#Lafafafaj#Laf#Lajaf#L#La9#L#Laj#La2a2a2#ga2.j#g.ja2a2#gaj#gaj#g#La2bp.j#g.j#ga2#ga2#g#g#g.j#g#g#ga2a2#g", +"#g#g#g.jas#g#gas.j#g.jas#gas#ga2as.j#g.j#g.jas#ga2#g#g.jas#gasasas.jas#g.jas#g.jasaa#g#Lbp.7afajbn.RaYaYaYaYaYaYbl.N#D#D.7#L#L#Laf#Lafaj#L#L#L#Laf#Laf#L#La2#L.3#La2#L#L#Lafa9a9.n.7a9.7a9a9a9.7afaf#Laf#La9aj.7.7.7aja9#saw#x#I.N#saY#I.NaY.s#I#x#I#x#I#xaC.CaoamaO.yaB.waz#uaZ.8bc.8.8#Q.y.Q.w#4#4.wa##vaB.Qaz#vaFama0#x#x.N.s.N#D#sa9.7a9.E#D.E#L.7aj.7#Laja9aj.7#L#L#La2.ja2af#Lajafajafaj#Lafafajaf#Lafajaf#L#L#La2a2.j#ga2.jas#gas#g.jas#gasa2#g.j#g.j#g#g#g#g#g.j#g.jas.ja2#gas.ja2.j#g#g", +"as.jas#g#gas.j#ga2as#g#gas.j#g.j#g#g#ga2a2#g#g.j#g.jas#gas.jas#g#gas#gasas#gasasa2#g.jbp#LajafafaYbnaYaYblaYaY#MaY#D#sa9a9.7#L#L#Laj#L#La2afa2#L#L#Laja2#Laf#L#La2.j#L.3aj#La9.7a9a9a9a9.n.7a9a9afaj#La9aj#L.7#L#D.na9#s.naw#x#Ibl.Naw.Naw.NaY#xawaYaw#x#I#xaC#I.8aO.yan.w.G.w#vb#by.8.8bc.ybb.Qay.Y.G#u#1a5.GaBamamaobn.s#Da9.7aY#Da9.7a9.7.7#Da9aj.7af.7af.7#L.7afaj#La2a2a2.j#Laf#Laf#Laf#Laf#La2#La2#La2a2a2.7.j#La2#gaa.jasas#gas.jasasas.j#g.j#gas#gas#gas.jas.j#gas#g#gas#ga2.j#ga2#ga2a2", +"a2#ga2.jas#gasas#gas.j#g#g#gas#g.ja2a2a2.ja2a2#ga2#ga2.jas#gas#gas#gas.j#gas#gas#g.j#ga2bp#L#Laj#L.naY.R#xaYaY#D#Dbl#D.7#saf.7.n#L#L#L#L#Laj#L#Laja9#La9aj#L#L#La2a2a2.j#L#Lajafa9#sa9.7a9a9a9.E#Lafafajafa9.na9aj.na9#s#D.N#IaY#s.sbl.s#D#s#D#s.N#I#x.W.Cavam.5.8aF.0azal#T.w.0.8#v.8byaKbbaIaP#aba#N.O.GazaB.5#xaw.N.NaY#D#D#s.7.n.7#L#La9.7a9#L.7af.E#L.E#L#L#L#L#La2#La2bpa2#L#Laj#La2#L#Laja2aja2#ga2.jbpa2as#gas#gas#gas#g.j#g.j#g#g.j#gas#ga2.j#g.j#g.j#g#ga2#g#ga2.j#ga2a2#g#ga2#g.j#g#g", +"#g.j#g#g#g.j#gas.j#g#gas.j#g.j#ga2a2#ga2#g.ja2a2#g.jas#g#gas#gasas.j#gas#gas.j#gasasas#g.j#g#Lbp#La9#Dbl.RaYaY#D#D#Da9#D.7a9.7#L#L#Lbp#L#Lbp#L#L#L#L#L#g#La2a2#Las.ja2a2#Laf#L.7a9.7.na9a9.7a9a9af#L#La9#Lafaja9.na9.n#D.s.s#x#I.Nbl.s#D#M#DaY.saY#I#xaC.Caqao.5bgaO#uaz.G.G#u.y#x.W.8#v#v.y.0.ybabaay.f#uaB.8a0bfaYaY.N.N#D#D#Da9.7.7af.7.7af.E.7aj.7#La9#L.n#L#L.jaf#L#gaja2#L#La2#Lafaj#La2#L#g#g#L#g#L#ga2#g#gas#gas.jas#gasasas#gas#gas#g#g.j#g#gas#ga2as#g#ga2#g#L#gbpa2bp.j#L#gajbpa2bpa2", +"a2a2#g.jas#gas#g#gas.j#g#gas#g#g.ja2a2.ja2a2a2.jas#gas#gas#g.jas#gasas#gas#gasas#g#g#ga2#g#L#La2#La9a9#DaYbl#Dbl#Da9#Da9a9.7#L#La2#g.j#g#ga2#ga2.j#ga2.j#g#g#g#ga2a2#g#La2aj#L#L.n#Da9a9.na9a9.7#Lajafajaf.7a9.naf.na9aE.N#I#Ibn.saY.Naw.NaY.saY#x#I#x.Wa0ao.5.8aoaO#u.G.Gaz#ua##IaCaCaobg#va7azaH#zaz#uaFam#x#xaw.N.N#D#D.n#D.7.E#L#L#Laj#L#L#Laf.7#L#L.E#L#L#L#L#La2#La2#L#gaja2#L#La2#L#L#La2a2#g.j#ga2#g#L.jas#g.jas#gas#gas#g#g.j#gas.j#g.j#ga2.jas.j#g.j#g.j#ga2.j#ga2#g#L#g#gaja2bp.j#L#g", +"a2#g.jas#g#g.jas.j#gasa2#g.j#g.ja2a2#ga2#La2a2#g.jas#gas.jas#gas#gas#gas#gas#gasas.j#ga2#gaj#Lbp.j#La9a9#D#Dbl#Dbl#D.7a9.7.7af.7a2a2a2a2a2a2.ja2bpaj#Lbp#Lbpa2#L.j#g#La2#L.7#L.7a9a9a9.7a9.7a9.n#Lafaf.7afafaja9.na9.n#D#s#I#x#IaY.sawaY.saYaw.N#I#x#I.C.W.5av.5bgaOaB.G.O.G.y.5aO.8bgaFaB.Gau#N#zaz.0aFa0#x.NaY.N.N#D.n#D.7.7a9#L#La9#L.7#L.7#L.E#L#L#L#Laf.7#L#La2#L.jbpa2#La2#La2#Lajafa2#L.j#L#g#L#gaja2#g#g#gasasas#gasasas.jasasas#gas#gasa2.j#g#gas#gas#g#ga2bpa2bpaja2aj#ga2#L#g#La2bpa2", +"a2#ga2#g.jas#g#g#gas.j#ga2a2as#ga2aja2.j#g.j#La2#g#g.j#gas#g.j#g.jas#g.jas#g.jas#gas#ga2#g#La2#L#L#g#La2a9a9#D#D#Da9#Da9.7a9#L.7a2.j#g.ja2aja2#L#L#g#ga2.j#L.j#g#La2#Laj#L#La9.7.na9.na9a9a9a9a9#L#Lajafaja9a9.naf.n#s#s.N#I#x#U#I#x#x#I#x#I#x#I#x#I#x.Wamao.5.8ao#v#u.Garaz#ua#.y.0#u#u#aau#3alaza#b##I#xaw#D#sa9#s.7a9.7a9aj#L#La2aj#L#Laf#La2#L#La9aj.7#L#Laja2#L#g#La2#L#g#Laj#L#La2#L#La2#L#ga2#ga2#g#g#L#gas#g#gas#gasasasas#g#g.jasas.j#g#gas#g.j#g.j#ga2.jbpa2bpa2bpa2bp.jbp.jbp.jbp.jbp", +".j#g.ja2#g.j#ga2.j#ga2.j#g.j#g.ja2#ga2a2a2a2a2#g.j#gas#g.j#gas#gas#gasas#gas#gasa2.j#gaj#g#Lbp#La2#La2#L#La9#Dblbl#Da9bja9#L.7#L#L#Laf#L#L#Laf#Laj#L#L.7#L#L#L#L#L#L#L#L#La9#L.7a9#Da9a9.7a9.Ea9#Lafaf#Lafa9.na9.na9.E#D#s#x#I#I#I#I#x#I#x#I#x#I#x#I#x.WaC.5.8.8.5aBa5#a#TaPaPbk.U#3al#3#T.G.w.0aFaC#x#x.N#D#Dbj#Dbj.7.7aj#L#L#La2#L#La2#La2aj#L.7#L#L#L#L#Laf#Lbp.j#La2bpa2aja2#La2af#L#Laja2#L#g.jbpa2bpa2#g.j#gas.jasas.j#gas#gasasas#g#gas#ga2.jas#ga2#g.j#g#L#gaja2aj#gaja2bpa2#L#L#L#g#La2", +"a2#ga2#ga2a2#g.j#ga2#ga2a2#g#g#g.j#L.j#L.j#La2a2#gas.j#gas#g.jas#g.j#g.j#g.j#gas.j#ga2a2#gaj#L#L.ja2#g.j#g#L#Dbl#Da9a9a9.7a9.7a9a9a9a9a9a9#sa9#Da9a9.na9a9a9#Laf#Laj#L.7a9.E.7a9.n.7.n#Da9a9a9a9#Lajaf.Eaf.na9.naf#Ma9.s.s#I#x#I#x#I#x#I#x#I#x#I#x#I.CaCaq.8am#vaO#u.G.Uay#3#3bv.M#C.O#u.y.5am.C#UaYaYaw.N#D.7.7.7.7aj.7#L#Laj#ga2#ga2a2.ja2a2a2ajaf.7#L.7aj.7#La2a2bpa2aja2bpa2#L#Laja2#La2#L#ga2bpa2.j#g#ga2#gas#gas#gasasas.jas#g.j#gas.j#g.j#ga2a2.ja2a2#gas.j#L#g#L#g#L#gaj#Laj#L.j#La2aj#g", +"#g.j#g.j#g.ja2a2#ga2.j#g.j#g.j#ga2a2a2a2#g.ja2#g.j#gas.j#gas#gas#gas#gas#gas#g#ga2#g.j#L#g#La2bp#La2#gas#g#La9bl#D#Da9bja9.7.n.7a9b.#D#s#D#D#D#s#p.nbl#p.na9a9a9#L.7#L#L#La9.7.7a9#Da9.na9.n.7a9#Laf#Laf#Lafa9.na9.n.E#s.N.s#x#U#I#x#x#I#x#x#I#x#I#xaC.Wa0.8.8.8.yaB#T#4beaM.Y#T.fa7#uaOa0bf.s.N#Mbl#s#D#D.s#DaW.E#L#L#Laj#L#g#ga2a2.ja2a2a2aja2.7#Laj#Laf#L#L#L#L#ga2#L#g#La2#L#La2#L#L#L#La2aj#ga2#g#g#ga2#ga2as#gas#gas#g#gas#gasas.j#g#gas#g#g.ja2#g#g.ja2.j#L#g#L.jbp.j#La2aj#L#Lbpaj#g#L#g", +"a2a2a2#La2a2.j#ga2.ja2a2a2a2#ga2#ga2#ga2a2a2#ga2asaa#ga2#ga2#L.j#La2#L#Lajafa2#L.ja2#ga2#La2#L#L#L#Laf#Laj#L#L#La9bl#Da9blaYaYaYblbl#DaYaYawaYaYblblblblblblbla9#Da9#D#sa9#Da9#D.na9.7a9.7a9a9.n#Laf.Eaf.Eaf.naf.na9#M#D#saY.saw.N#s#s#D#s#s#D#s.C#I#I.C#Iao.5#v#u.OaVadbi#3#1aBbdaO.W.C#IaYbf.N#D#s.7#L#L#Laj#L#Lbp#Lbpbpa2bpa2.j#g#g#Lbp#Lbp#L#L#L.7.7.E#L.7#La2a2a2.ja2#ga2.ja2#L.3a2a2#g#g#g#L#ga2#ga2#g#ga2#ga2#ga2.j#ga2#g#gas#gas#g.jas.ja2#g#L.j#L#g#g#L.ja2a2#L#L#L.7#L#L#L#La2#L#Laj#L", +"a2a2.j#L.j#La2a2a2a2a2a2#ga2a2a2.ja2a2.ja2#ga2a2asa2asa2.j#L#g#La2#L.jaf.3#L#La2aa#ga2a2#L#Laj#Lafaj#L#L#Lbpaj#La9#D#p#Dbl#DaYaYbl#DblaYaw#xaYaYbl#Dbl#Dbl#Dbl#Da9#sa9#D.7#D.7#D.7a9a9a9a9a9.7a9.n#Laf#Laf#La9a9.n#s#D#M#DawaY#I#s#D#s#s#D#s#D#sbf#Ibf#I#Ia0bc.y.G#zad#4aXbk#v.8bgao.C#x.N#x.N.s.7bj#L.7aj#Lbp#Lajbp.j#L#gaj#g#L#gbpa2bp#L#La2#L#L#L#Laf#La9#L#L.j#ga2#ga2a2a2a2a2#La2aj#L#g#L#ga2#g#ga2#ga2#ga2#g#ga2#g#ga2bpa2as.j#g#g.j#ga2#g#L#Laj#Laj#Laj#L#gaja2ajafaj#L.Eafaj#L#Lajaf#L#L", +"a2#La2a2a2.j#ga2.j#L.j#ga2a2#ga2#ga2#ga2#ga2a2asa2.jasa2#ga2#La2#La2#L#L#Laf.j#L.j#L.jafaj#Laf#Lafafaf.7#L#L#Lbpa9#pa9#D#Dbl.sbl#D#MblaYaYaYaYawbl#D#M#Dbl#D#Mblbja9bja9#D.n#Da9.na9.7a9.7a9.na9#Laf.Eaf.Ea9.n.n#D#M#saYaw#IaY#IaY.s#D#s#D#s#D#s#I#x#I#I.Cao.y#1#T#rbq.G#u.yaOaCamaC#xawaY.s.N.N.7aj#Lbp#Lbpa2#ga2#Lbp#L#g#L#g#L#ga2#gaja2bp#Lbp#Laj.7aj.7aja9#L#L#L#L#L#Laj#L#L#L.j#La2#ga2#g#g#L#ga2#g#g#ga2#g#ga2#g#ga2#g.j#g#gas#g.jasa2.j#gaj#L#Laj#L#Laj#La2a2a2#L#L#La9#Lajaf#Lajaf#Laj#L", +"a2.ja2.ja2a2a2#ga2a2#ga2a2#g.ja2a2a2a2a2a2.ja2a2asas#ga2a2#L.j#La2aja2a2a2#Laf#Lafa2af#Laf#Lafajaf.E#Laj#L#Lbpa2a9.na9#Da9a9#D#Dblbl#DaYaYaYaYaY#Dbl#Dbla9#D#D#Da9#Da9#Da9bja9bja9.7a9a9.na9#Da9#D.na9a9a9a9#D#sbl#saYaw.s#x#I#I.saw.saY.s.Naw.N.s.s#IaCaoao#u.G#z.UaX#uaOaOao.W#x#IaY.N.N.N#D#D#L.7#Laj#La2#ga2#gbpa2bp.jbpa2bp.ja2#g#L#Laj#L#La9.7a9.7a9.7.7a9#L#L#Laj#L#L#La2af#La2#L#L#g#L#ga2#g#ga2#ga2#g#ga2#g#ga2bpa2bpa2#g.ja2#ga2#g.ja2#Laj#Laj#Laj#L#La2.j#Lajafaj#L.E#L#Laf#L#L#Laf#L", +"a2bpa2#La2.j#ga2aja2a2a2.ja2#ga2#g.j#ga2#ga2#ga2a2aa#ga2#ga2bpa2#La2afaja2afa2#Lajafajafajafa9a9af#Laf#L#L#L#Lbpafa9a9a9a9a9#D#D#Dbl#DblawaYaYaY#D#Dbl#D#Dbl#D#Da9b.a9.7a9#Da9#Da9.na9.7#D.na9.na9a9#D.n#D#s#D#M.NawaY#I#x#I#Ia0#IaY#Iaw.Nawbo#x.s#x#I.WaF.yaz#3.a#4a5#v#vaoaC#IaYaY.saYaw#D#sbj#Laj#Lbp#L.j#g.jbpa2aj#g#L#g#L#g#g#L#g#L#g#Lbp#L.na9a9.na9a9.na9#Lajaf#L#L#L#Laj#Lafa2#L#g#L#g#g#L#ga2#g#ga2#ga2#ga2#ga2.j#ga2#g.jas#g.j#g.j#ga2aj#L#Laj#L#Laj#Laj#La2#L#Laf.7af#Laj#Lajafaj#L#L", +"a2.ja2.j#L#ga2a2a2#ga2#ga2#ga2a2a2a2a2a2a2a2.ja2as.jasa2.j#La2#La2#La2a2#La2afajafafafafaf#pa9.n#Laf#L#L#L#L#g#Lafa9a9a9a9a9a9a9a9#DblaY#DaYawaY#D#M#D#D#M#Da9#Da9#Da9bja9.7#s.7a9.7a9.na9a9.7#D#s#D#s#D#Dbl#s.N#M.Naw#I#I#IaC.W#I#xbo#xbo.N#IaYbo.W.Wa0#vaz.Y#.aVapaOaO#O#I#I#xawbl.N#D#D.7a9.E#L#L#L#gaj#g#g#ga2bp#gbpa2bp.j#La2#g.j#L#La2#Lbpa9.7#D#D#s#Da9#D#L#L#L#L#L#L#L#L#L#La2#L.j#Lbpa2#ga2#g#g#L#ga2#g#g#ga2#gbp#g#L#g#g#g#ga2a2#g.ja2aj#Laj#L#Laj#Laja2#Lajafaj#Laj.7aj#Laf#L#L#Laf#L", +"a2#La2#ga2.ja2#ga2.ja2a2a2a2#g.j#ga2#g.j#ga2#ga2#gaa#ga2#ga2aja2#L.j#La2#L.jafaf.3ajaf.n#p.n#pa9afajaf#L.7#L#L#L#L#La9a9#D.7a9#Da9a9bl#DblaYaYaY#D#D#D#D#D#D#D#Da9bja9a9.7#Da9#Da9a9a9#Da9#sa9a9#D#D#D#D#s#D#saYaw#I#x#IaC#x.WaC#I#I#x#I#x#I#I#xa1ao#Q.8.w#4.P.4#u#Sao.WaCa0bobfbl#s#D.na9#L.7#L#Lajbpa2a2#g.jasbpa2#L#g#g#L#gbp#ga2#g#Lajbp#Laja9a9#M#Dbl#D.na9.7a9.7a9.Ea9a9.7af.jaf#La2#L#L#g.j#ga2#ga2#g#L#ga2#ga2bpa2a2.j#g.j#g.j#g.ja2#g.j#Laj#Laj#L#Laj#L#Lajaf#L#Laf.7af#Laj#Lajafaj#Laj", +"a2.j#L.j#La2#L.ja2a2#ga2#g.ja2a2a2a2a2a2a2a2a2a2asa2asa2a2a2bpa2af#La2afa2#L#Lajaf#pafafa9#p.n#p.7af#L#L#Laj#Lbpaf#La9.7a9a9bja9a9#D#Dbl#DaYaYaY#D#D#D#Da9#Da9#D#sa9a9bja9a9bja9.Ea9.7a9.Ea9a9a9#s#D#s#D#Dbl.s#Daw#x#IaC.WaCaCao.Wav#Ia1#I.Ca1#I.Cav.8aO.G#dbs#BaLaB.8aC#I.WaYbf#sbl#Da9a9.n#L.E#L#L.jbp.j#gasasa2bp.j#L#ga2bpa2#g#L#g#L#g#L#L#La9#Da9bl#s#p#Da9.7a9.E.7a9.7.7.n#Laf#L#L#gaj#L#g#ga2#g#gbp.j#ga2#g#ga2#g.jbp#gbpas#ga2#ga2#g.ja2.E#Laj#L#Laja2#Laja2aj#Laj#L.E#L.Eafajaf#L#Laf#L", +"#L#L#L#L#La2bpa2#Laj#L#La2bpa2bp.L.L.jasaa#ga2#gaja2a2a2a2#La2#La2a2#L.j#La2afa2.3aj#p#Mbl#D#D.7ajaf#Laj#L#Lbp#Laj#Laf.n.7a9a9.7#pa9#p.NaYaYbl#Dbl#D#Da9#Da9.7a9a9a9a9afa9.7a9.7#Dbl#Dbl#D#D#D#D#xaYaYawaYaYaY#Ubn#I#I#I.Wao#v#vaC#I#x.W#Ibo.C.WavaoaZ.o.Yab#3.QaOaoaC.W#I#x.s.Nbl#sa9a9aj#La9#L#L#g#L#ga2#g#L.j#g#g#g#ga2bp#ga2.ja2#L#Laf#La9.7bl#DblblaYaYaYaYaj#L#L#L#L#L#L#L#L#L#L#L#L#L#L#La2#ga2a2a2#g#La2#La2#g#La2a2#L#L.ja2.ja2.j#L#Laj#L#L#Laj#Laj#Laj.3#Lafajaf#Lajafa9.na9a9.na9.na9", +"#L#Laj#L#Laj#La2bp#L#gaj#L#L#Lajaa.jaaaaa2#ga2bp.3#L#L#La2#L.j#La2a2a2#La2#La2#L.3af#pblbl#Da9a9afaja2#La2#La2#L#Laf#L.7a9a9bja9a9#p#DblaYaw.Nbl#Dbl#Dbl#D#D.7a9a9afa9a9a9a9aj.7bl#D#D#sbl#Dbl#MaYawaY#xaY#xawaY#x#U#x#I.Cao.8aBaxav.W.C.Waoao.8aO#vaPay#daVbk.0#OaoaC.W#x#I.N.N#Dbl.na9a9#L.7aj#g.j#ga2bpa2#g#gasas#g.j#g#ga2#g#La2.ja2#Laja9a9a9a9bl#DaYawaYaY#La9.Eaf#L#Laj#L#L#Laj#L#L#L#L#Lbpa2#L#g#La2#g#L#gaja2#ga2#ga2#La2a2a2#La2a2.3#L.jaf.jaf.j#L.3#Laj.3aja2#Laj.3#Laja9af.n#L#Laf#L", +"a9ajafaf#L#L#L#L#L#L#L#L#L#L#L#Laa#ga2#g.j#gbp#La2#L.ja2#La2#La2a2#La2a2a2#L.j#L.jaf.n#pbl#sa9.Eaf#Lafaj#Laj#L#Lajaf#La9a9bja9a9#Ma9bl#DaYaYbl#DaYbl#Dbl#Da9a9a9a9#p.naf.7a9.7a9.n#Da9#D#D#s#D#DaYblaY#MaY#MaYaY#MaYaw#I#IaC.8aObgaoaoao.8ambc#v#uar.M#d#4.G.y.8bgaoaC#x#I.N.N#s#pa9a9.7ajaf#L#La2bpa2.j#g#gaj#g#g#gas#ga2#g#L#La2a2#Laf#Laf#La9a9a9a9#D#Dbl.Nbl.E#L.7#L.7af.7#La9#L.7#L#L#L#L#La2#ga2#ga2#g#La2#L#ga2#L#g#L#Laj#L#Laj#Laj#Laj#Laf#L#La2afaj#Lajaf#Lajaf#Laj#Laja9afajaf#Lajafaj", +"afaf#Lafajafajafajaf.Eaf#Laj#L#L#La2#L#L#gbpa2bp#La2#L.3#L.jafa2#La2a2#La2a2#L.3afaf#p#Mbla9a9.7afajaf#L#L#L#g#L#La9aja9a9#Da9.7#pbl#DaYaYaYbl#DaYblaY#Dbl#D#D#Dafa9afa9a9a9.7.7.7#Da9bja9#D#D#s#D#D#saYbl.NblaY#M#D.saw#I.WaOaB#vaO#v.8aOaO#v.y#3ad.Z#.#T#vav.haoaC#x#IaY.s#D#D.n#Dajaf.7#Laj#L#ga2#g#gbpa2#ga2a2as#ga2#ga2bp#La2a2a2a2a2#L#L#La9afa9#M#DblawaY#L.7af.E#Laj#L#L#Lajaf#L#L#L#L#Lbpa2#L#g#La2#gaja2#L#ga2#g#La2a2aj#L#L#L#L#Laf#L#Laj#Laj#L#Laf#Laj#L.7aj#L.Eaf.7.na9#D.n#Da9#Da9", +"a9.na9a9a9a9#pa9a9a9a9a9a9a9a9.nafaj#L#L#L#Lbp#La2aja2#La2#La2a2#La2a2a2a2a2#La2aj#p#pbla9a9#Lajaf#Lafajafaj#L#Lajaf#La9.7.nbj#Da9blaYaY#x.N#DblaYblaY#DaY#Dbl#Da9a9a9a9.7a9.7.7a9.7.E.7.7.7.7a9#D#D#D#D#s#D#s#D.sbl#s.s#xaoaO#S.yaBaB#u#u#ubk#E#.ab#4#3.G.y.8bo#U#I#x.s.N#D#s#Da9#L.7aj#L#La2bp.jbpa2#La2#g#L#g.jas#g#ga2#Laja2#L.j#La2af#L#L#La9.7a9bj#Daw.Nbl.E#L.7#La9#L.7#L.7#L.7#L#L#L#L#La2#ga2a2#ga2#L#g#La2bpa2#La2bp#L#Laf#L#Lafaj.7ajaf#Laf#L#Laj#Laja9.na9.7afa9.Ea9a9a9a9a9a9.na9a9", +"a9a9a9a9a9a9a9.n#paf#paf#p.n#p#pbl#D.na9a9#L#L#L#La2#La2#La2#La2a2a2a2#La2#La2afa9#p#M#pa9.nafa2afajaf#L#Lbp#L#L#Laf#La9a9#Da9a9#D#DaY#x#xaYaY#DblaYblaY#Dbl#Dblafa9afa9#Da9.7a9#L.7a9#Laf.7.n.7a9a9#s#D#D#D#D#D#s#D.s#x#I.8#Saz#u#u#uaZ.w.GbiaV#4.U#3ara5#vao.W#x#IaYaw#D#sa9a9#L.n#Laf#L#gaj#L#ga2#g.ja2#g.j#gas#gas#gaja2bp#La2a2a2a2#L#Laf#L#L#La9a9#Dbl.NaY.7#L.n#L.E#L#Lafaj#L#L#L#L#L#L#Lbpa2#L#g#L#ga2#ga2#ga2a2#gaja2#L#L#L#Laj.7#La9#L#L#Lajafaj#Laf#L.n.7a9.Ea9.Ea9.n#D#s#D#s#D#D#s#D", +"a9.n#pa9.n#pa9#pa9.n#p.n#p#p#p.nblblbla9.na9#Laf#Lafa2aj.3#L.j#La2#La2#La2aja2#La9.nblbl#pa9#L.j#Laf#Laja2#La2aj#L#Laja9a9.7#D#s#p#DaY#x#x#xaY#DblblaYaYbl.Nbl#D#Dbl#D#Da9#Dbj#D.7#L.7#L.7af.7#L.7.na9a9.na9a9.n.NaYbobfaoaFaBazaz.w#uaP#3#4ad#4ap.O.O.O.w#S.8.5#Uaw#x.saY#s#D.n.7#L#Laja2aj#gas#L#gbp#gbpa2bpa2#gas.j#g#g#L#La2#La2#La2#L#L#L#L.7#L.7.7.E#D#s#D.na9#L.7af#L.7#L.7#La9#L#L#L#L#La2#ga2a2#ga2#L#g#La2bpa2#ga2#ga2.7a9.7#La9.7.7a9ajaf#L#Laf.7.na9#D.Ea9.7a9.7a9b.#D#D#D#D#D#D#D#D", +".n#pa9#paf#p.n#p.n#p#p#p#p#p.n#p.b.R#Mbl#p.nafajafaja2#La2#L.3#La2a2aja2#L.3#L.ja9#pbl#Mbl.nafa2afajaf#La2#Lbp#L#Laf#La9.n#D#s#DblaYaY#xbn#xaY#DblaYblaYblaY#Dbla9bla9#D#D#D#Dbja9#La9#La9.7.7a9.7a9.7.7.7.E.7#D.N.sbf.Wam.y#uaz.Oar.Gal.Mbxadalbkbkbkbkbka7.yaF#I#IaY#s#Da9#s#Daj#Laj#L#g#L#g#g#gaja2a2a2#ga2#gas#gas#ga2#g#gaja2a2a2af#Laf#La9#Lajaf.7a9#D#s#Da9.Ea9.E#L.E#Laj#L#L#L#L#L#L#L#L#L#g#L#g#La2#ga2#ga2#ga2#L#g#La2#L#L#L.7#Laf#La9#L.E.7.7.Ea9.n.7.n.7a9.7.n.7.na9#D#D#s#D#s#D#s#D", +"#Lafaj#L.7#L#L#Lafafajafaja9#pa9aYawaYaYawblblblafafaf#Laf#L#L#L.jaaafa2#L#Lafaf.n#F#M#pa9afaj.7#Lbp#Lbpbpaj#L.Eaf#Laj#D#D.N#D.N.naYaYbna0a0bnaY#DblaY#x#xaYaYblbl#D#Da9a9.7#L#L.7.7.7.7.7.7.E.7#Dbj#D.s.N.N#DboaY#MaY.W.8aZal#P#PaT#P#.a.ad.ObkaX.G.O#Taz#SaoaC#x#x#I.N.s#D.E.7af.7#L.E#L.Eaf#Laj#g#gbp.jbpa2aj#ga2#g#L#ga2#ga2#L#L#L#L#L#L#L#L.7#L.7a9.E#Da9#D.Ea9.7a9.7a9#La9#L.7aj#L#L#L#L#L#L#L#L#L#Lbpa2#L#L#g#L#ga2a2#ga2bpa2#La2#L#Laj#L#Laf#Laj#L.7#L.7af.7.E#L.7#L.7#L#sa9.7a9.7#L.7#L", +".E.7.7#La9aj.7#Lafajafafafa9a9.nblbl#MaYblbl#Dblafajafaj#L.E#L#Laaa2a2aja2afajaf#p#p#pa9.naf.7#L#gaj#Lajbp.7#L.7ajafa9#D#D.NaY#xblaY#x#xama0a0aY#p#Dbl#xbnaYblaY#Dbl#Da9a9.7af.7.7.7.7.7.7.7.7.7#D#s#D.N.N.N.N.N#IaY.N#Iamanay.P.PaDaD#..M.O.G#u#u.w.GaP#u.ybgaCaC#x#IaY.N#s.7a9.7aja9#La9#L.E#L#L#ga2a2#ga2#ga2#g#L#ga2#ga2#g#g.7#L.7#L.7#L.7.7af#L#L#La9#Db.#Da9.7a9.Eaf.7a9.7#L#L#L#L#L#L#L#L#L#L#L#L#La2#L#L#ga2a2#g#L#g#La2#ga2#g#L#ga2#La2#L.7#L.7a9aja9#L.E#La9aja9#L.n#L.na9aj#Laja9aj.7", +"#L#Lafaj#L#Laf#Lajafaf.Eaf#sa9a9a9a9#pbl.nbl.n#p.nafa9#Laf.7#L#L#L.ja2#La2af#L.n#p#Mbla9a9aja9#Laj#Lbp#L#L#L.7.7#D#D#saYaw.N#xbf#MaYaw#xbna0a0aYblaYaY#xbn#xaYaYbl#D#D#Da9#D.7#L.7.7.7.7.7.7.7bj#s.7#D#s#D.N.sbfa0#UaoaO.yan.2.g#m.AbA#4ar#u.0#u#S#vaBaB#uaB#v.5aoamaC#x#IaY.N.na9.7.E#L.7af#L#La2#g#L#g#L#gbp#ga2#ga2#g#g#ga2#g#L#L#L#L#L#L#L#L#L.E#L.7.7a9#Da9.Ea9.7a9.7.7#L#L#L.7#L#L#L#L#L#L#L#L#L#L#Lbpa2#La2bpa2a2#ga2#ga2#L#ga2a2a2#g#La2#Laj#L#L#L#L#L#La9#L.7#L.7aj.7#La9.7#La9.7#La9#L", +"#L#L.7#L.7#L.7#Lafaf#Laf#La9a9.na9#Da9.n#Da9#D#Dafaf#Lafaja9aj#La2a2af#Laf#Laja9#p#D#p.na9.7aj#L#L#L#L#Laj.7.7b.#D#saY.NaYbf#x#x#DaYaYaY#xbna0#xaYaYaY#xaYaYaYaY#Dblbl#D#Da9.7.7a9.7.7.7.7.7a9.7af.7#D.N.s.N#x#IaF.8amaF.0#uaybe#.ba#aaz#ua##vaOaOaO#v#v.y#uaBa#b#bga0a0awaYbl#D.Ea9a9a9.E.7a9.7#Laj#L#gaja2a2a2#ga2#g#ga2#ga2#g#L#L#L#L#L#L#L#L#L#L#L#La9.Ea9.7.7.n.7.n#La9.n.7af#L#L#L#L#L#L#L#L#L#L#L#La2bp#La2#ga2#g#La2bpa2#ga2#L#g#L#ga2#g#L#L#Laf.7#L.7#L#L#Laj#L#L#Laf#L.7#L.E#L.n#L.E#L", +"#L#Laj#L#L#Laj#L#L#Laj#L.7.7a9.7a9a9a9#Da9a9.na9.naf.Eaf#L.7#La9ajaf#Lajaf#La9a9#M#pbla9a9#L#L.7aj#Laj#Lbjbj#sbjaY.N.Naw.N.Nawbf#DblaYaYaY#xbn.CbnaYaYaYaY#xaYa0bl#D#D#Da9#D.7#L.7#La9#La9#L.7.7a9#sblaYaYbnaCa0.5amaFaB#u#a#4abarazaBa#aO.5ao.5aoaoamaOaB#u#uaZaCa0bn#xaYaY#Dbla9a9.na9a9a9#La9#La2a2#L#g#g#L#g#g#ga2#ga2#g#ga2#ga2a2#ga2a2#La2#L#L#Laf.7.7.7a9a9.7a9.7.7.7#L.7#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#g#La2bpa2#ga2a2bpa2#ga2a2#g#La2#L#L.7#Laj#L#Laj.7af.7#La9#L.7ajaf.7#L#L#L.7af#L", +"#L.7af.7#La9#L.7a2#L#L.7#L.n.7.na9a9.na9a9a9a9a9afaf#Laf#Laf.E#Lafajafaf#La9.na9#D#p#sa9.n.7aj#L.7#L.7a9.Ea9#Da9.NawaY.N.NaY.N.N#D#D#D#MaY#x#xa0ama0#xbnaYaYbn.CaYaYaY#D#D#D#D#Da9a9a9a9.7#Da9#s#D.NaY#x.Ca0amamaFaB.f.Oau#aazan#v#vaFam.5aCav.CavaoaoamaOaB#uan.Ca0#xawaY.s#D#s#Dbja9bja9.7a9a9a2#La2#La2a2a2a2#ga2#ga2#g#ga2#ga2#ga2a2#ga2#ga2#L#L#L.7a9.7a9.7.Ea9.Ea9.7af.7af#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#La2a2#ga2#ga2#L#ga2#g#La2bpa2a2bp#L#L#L#L.7#L.7af#L#L#L#Laj#L#L#L#Laj#L#La9aj.7#L", +"#L#L#L#Laj#L#L#Lajaf#Laja9.7.7a9.7a9a9a9a9.na9a9aja9#Laja9#L.7#Laf#Lafaja9a9#D#D.nblbla9b.#L.7.E.7.n.7.n#D#D#s#D#D#D#D#s#D#D.n#D#D#D#s#Dblawa0.Cama0a0aYaY#xa0amblaY#D.N#D#Dbj#Dbj#D#D#D#D#D#D#D.N#x#x#xbg#vbmaBbk#a#Ea7a7aZ#va#amb#ao.C.W.Cbf#IaqaoaoaoaO#SaZ#ubn#I#xaY.Na9a9.7a9a9a9a9a9a9a9a9#Lajaf#L#L#L#La2a2#g#g#ga2#ga2#ga2a2#ga2a2#ga2a2#L#L#L#L.7.Ea9.7a9.7a9#La9#L.7#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#g#L#g#La2bpa2#g#La2#ga2#ga2#ga2#L#L#Lajaf#L#L#L.E#L.7#L.7#L.7#L.7af.7aj.7af.7#L", +".E.7.n#L.7#L.7af#L#L#L.7aj.7a9.Ea9a9a9.7a9a9.7a9afafafafaja9aj.7afaja9#La9a9#s#D#p#M#D#s#D.n.E.7a9.na9#D#sa9#D#D#D#s#D#D#Da9a9.n.N#D#D#Dbl#xa0ama0ambnaYaYbnama0aYaYaY.N#D#D#Dbj#D#D#D#D#s#D#Daw.C#I.Caobm.G#faG.yaBbh.l.taFb#.5a0a0aoa0#xbo#xboaqavaoamaC#Sa7an#I#x.N.s#Dbjaj#L.n#Da9#sa9a9a9a9#Laf#L#Laf#Laf#L#ga2#ga2#ga2#g#g#ga2#ga2#ga2a2#g#L#L#La9.7a9.7.7.7.n.7.7.7#L.7#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#La2#ga2a2#ga2#ga2a2#g#L#g#La2bpa2#L#L#L#L.7#L.7#L#Lafaj#L#Lafaj#L#L#L#La9#L.7aj#L", +"#L#L#L#Lajafaj#Laf#Lafaf#Lafajaf#L.jafajaf#Laja9aj#Laj#L#L#L#Laj.7.7.E#Laj#L.7.7bl.NawaY.NaY.N.s#s#D#sa9bj.Ea9.Ea9.na9.n#D#s#D#Da9.n#D#D.saY.s#x.R.Rbn#x#x#xaY.NbnaYblbl.na9.7.7#D.N.N.N.Nbfbfbfavama#aSaG#z.G.0aoa0aC#xaCbn.Wbn#I#xaY#I#x#x#I#x#Ia0avao#v.0aBa7#IaYa9.7.E.7#D#Da9a9a9a9.7a9.7afa2a2a2a2a2#g#ga2#ga2#g#ga2#g#ga2#ga2#g#ga2#g#ga2a2#g#L#L#L.7a9.7.na9a9afaj#La2a2#L#Laf#L#L#La2#L#L#La2#La2#La2#La2#L#L#L#L#L#L#La2a2a2a2#g#ga2#g#La2#La2#Lajafa2.7#L.7af.7#L.7afaj#L#Lajafafaf#L", +"#Lafajaf#L#Laf#Lajafaj#L#Laf#Laf#Laf#Lafajaf#Da9.7a9.7.7af.Eaf.7.na9a9a9.7.7.n.7awaYawaYaw.s.N#D#Da9#D.na9.7a9.7.n.7.7.7#D#D.7.7#Da9#s#D.N#x.N#x#Ua0a0bna0bn#IaYb#am#xaY.N.N.N.Nbj#D.N#I#xaqaoa0a0a#a7#fa6az.0.5bnaCbnbn#x#x#x#xaYboaYbfaw.NaY#I#x#Iao.8.5#v#u.T#I.N#sbja9bj.7bj#sa9.Ea9a9.7a9a9#L.ja2a2.j#ga2#g.j#ga2#g#ga2#ga2#g#ga2#g#ga2#g#g#ga2#L#L#La9aja9a9af.7af#L#L#L#gafa2#La2afa2#La2.3#La2#La2#La2#La2#La2a2a2a2a2#La2a2#L#g#La2bpa2bpa2#ga2#L#La2#L#L#L#L#Laj#L#L#La2a2afafaj#Lajaf", +"#L#L#L#L#L#Laj.7af#Laf#Lajaf.Eafajaf#Lafa9a9.n#D#D.n#Da9#s#D#D#D#D#s#D#s#D#D#D#sbl#s#D.s#D#s#D#s.7aj.7#L.7aj.7#L.7af.Ea9#L.7a9.7.na9#D#D#D.NaY#xa0.Vaoamama0ambna#b#amambn#x.C.Cawbf#xa0amamaF#v#vaBazaSa7a#aq.W#x#x.s#xaw#xaw#x.N.NaY#xaY#x#I.N#I#xavam.8.yana7#U#x#D.7b..7a9#Da9a9a9a9.7a9af.7a2#La2#L#ga2#g#g#ga2#ga2#g#ga2#ga2#g#ga2#g#ga2#ga2#L#L#L#L.7a9.7a9a9a9#La2#La2a2#L#Lafa2#La2#La2#L#L#La2#La2#La2#La2#L#L#L#La2#La2a2a2a2#g#ga2#g#La2bpa2a2#Laj#L#L#L#L.7#L.7#L.7af#L#Laf#Laf#L#L", +".7#L#Laj#L#La9#La9a9a9a9a9a9a9a9af#L#D.n#D.7#D.7#D#D.N.s.N.N.N.sbl.NblaYblaYawaY#M#D#Ma9#D.nbj.7#L#L#Laj#L#Laj#Laj#L#L#L.7a9.E.7a9a9a9#DaY.s.N#xaCb#a#aFa#amamam#vaFamam#xa0#xam.CaCamamaObma7aza7aZbm.tam.C.Cbfaw#xaYaY.NaY.NaY#DaY.s#xawbfaY#x#x#Iaqao.8aZ#ua7ao#xaw#Da9b..7#Da9#s.7a9af.7a9a9a2#La2#La2#ga2#ga2#g#g#ga2#g#ga2#g#ga2#ga2#ga2#ga2#g#L#L.E#L.7afa9afa9#Laf#L#ga2#La2#La2#La2#La2af#La2#La2#La2#La2#La2a2a2#La2#La2a2#La2#La2bp#g#L#ga2a2#g#La2#L#L#L#L#L#L#Lafaj#Lafaj#Laf#Laf#L", +"a9a9a9a9a9a9a9.n.7a9.n.7a9a9.n#D.na9#s#D#D#D#D#D#D#D.sblaY#saY#DaY#MaY#saYblaY#D#D#s#D.7.n.7bj.E#L#Laj#La2#La2#L#L#L#L#L.n.7a9.7a9.E#D#D.NaY.N#Iamam#v.0a#aFa#a#bmbgamaCbna0aoa0amaF#vaBa7a7.l.TaFb#b#amam#x.Nbj#x.N.s.NaY.NaY.N.N.NaY#x.N#IaY#I#x#Iaoaq.8.ybhazb#bn.N.N.7a9#D#s.7a9a9a9.7a9#La9#Lajaf#L#L#Lbp#L#ga2#ga2#ga2#g#ga2#g#ga2#g#ga2#ga2#L#L#L#L.7a9.Ea9a9a9a2#L#La2#g#La2#La2#La2#La2#La2#La2#La2#La2#La2#L#La2#La2#La2a2a2#ga2#g#ga2#ga2bpa2a2#L#L#L#L#L#L#L#L.E#L.7a9a9a9a9a9a9.7a9", +".7a9a9a9.n.7a9a9#s#Da9#Da9#D#D#D.7#D#D#DaY.Naw.Naw.NaY.NaY.NaY#s#D#D#D#D#s#D#s#D.na9a9.n.7.7.7#L#g.ja2#g.j#g.j#g.j.3aj#L.7aja9.Ea9a9a9#D.N.s#x#x.Cb#aF.yaZa#a##Sa##SaFamamaOa#aZazazaza7a7bmaFaFa0a0a0bn#IaYaY.Naw.NaYaY.N.N.Naw.NaY.Naw#x.N#x.N#x#I.Cao.5.ya7az.5aoaY.s#D.E#D#Da9.na9.7.na9a9a9#Laf#L#L#L#L#Lbpa2#g#ga2#g#ga2#ga2#ga2#g#ga2#g#ga2#g#L#L#Laf.7#La9afa9#L#L#La2a2#La2#La2#La2#La2#La2#L#L#L#La2#La2#La2#La2#La2#La2a2#L#g#L#g#L#g#La2a2bpa2#g.j#L#L#L#L.7af#L#L#La9.7a9a9.Ea9a9a9", +"a9a9a9a9a9a9.na9#D#D#s#D#s#D#s#D#D#D.saY.s#xaY#x#D#M#D.nbl.nbl#Da9.Ea9.7a9.7a9.7#Laj#Laj#Laj#Laj#gas#gas#g#gas#ga2#L#La2af.7#L.7a9#s#D#D.NaYaYboa0a0aOa#a#a#aBbh.GaPa7az#uaS#TalbaaGa7aZaFaoambnaCa0#x#I#D#DaYaw.N.N.s.N.N#D.N.N.N.N#I.NaY.saY#I.N#I.C.8.5.ya7azaOb##x.N#Da9a9#sa9a9#D.na9.7a9.7a9a9.7#L#L.7bp#L#ga2#g#ga2#g#ga2#g#ga2#ga2#ga2#ga2#L#L#L#L.7a9.7.na9.7a2af#L#ga2#La2#La2#La2#La2#La2#L.3#La2#La2a2#La2#La2#La2#La2a2a2a2a2#g#ga2#ga2bp.ja2bpa2#L#Laj#L#Laj.7#L.7.na9a9.7a9a9.7a9", +"afa9afa9.na9a9a9#s#D#D#D#D#D#D#D.saY.NaY.Naw.NaY.n#Da9a9a9a9a9#Daj.7#L#Laj#Laj#Laj#L#L#Laj.7bp.7as.jas.jas.jas.ja2.ja2#L#Laja9aja9a9#D#D.Naw.N#x#xa0am#va#a#bmaB#l#0.2.2.2#0ab.4arazaZa#aFa0.W.C#x#x.NaYaYaYblbl.N.N.N.Nbj#Dbj.NaY.NaY.N.NaY.NaY.NaY.Waqao.0#ua7aBaO.Waw#D.na9#Da9.na9a9a9a9a9af.7afa9.7#L.7.7bpa2#g#ga2#ga2#g#ga2#ga2#g#ga2#g#ga2#g#L#L#L.7.Eafa9afa9#L#L#La2#g#La2#La2#La2#La2#La2#L#L#L#La2#La2a2#La2#La2#La2a2#La2#L#g#L#g#L#g#La2#Lbpa2#La2#La9#L.7#Laf#L#La9.7.na9a9a9.na9", +"#D#Ma9#Da9bl#M#DaYaYawaYblawaYaYaYawaYaYbl#D#D#s.7af.E#L.7aj.7#L#Lajbp#Lbp#L#L#L#ga2.j#g#g.j#g.j#g#g#g#g#g#g#g#g#ga2a2aj.7a9.7.7a9.na9#M#DaY.Nawbn#UaoaF#v.8am#va6a6ba#V.Z#oab.I.TbmaFaoam.C.C#I#x.s.N.N#D#D#D#DaY#DaYbl.NaY.N.s#D#M#D#D#s#D#D#s#Daw#x.CaC.5bc.yaBaZ#vam.Nbj#Db.#D#D.7a9.7#D#D.Na9a9.7a9#L#L#L#La2a2a2#ga2#ga2a2#L#L#L#L#L#L#L#L#Laf#L.na9a9#D#Da9a9a9a9#L#L#L#La2#La2#L#L#L#L#La2#La2a2a2a2#L#La2#La2#La2#La2#La2a2a2a2a2a2a2a2#L#L#L#L#L#L#L#L#L#L#L#L#L.7a9.7af#La9.7a9bja9#D", +"bl#D#D#M#D#Dbl#D#MaYbl.saY.NblawaYaYaY#M#D#s#D#D.7#L.7#L#L#L#Laj#g#L#gaja2aj#gajas.jas#gas#g.j#gas.jas.jas.jas.ja2.j#L#Laf.E#D#Daja9a9#DaY.s#x#IaCamama##uazaz.G#.a..Z#Valarak#aaZ#Sa#ama0#U.C.CaYaY.NawaY#D#D#DaYaY.sbl.N.s.N.Na9a9a9a9#D#D#D#D#s.N.N#I.CaobybcbhaB#vaF.WaY.s.Nbl.s#D.na9#D#DaYafa9a9a9#L#L#L#L#ga2#ga2#gaaa2as#L#L#L#L#L#L#L#L#L#L#La9a9#D.7#D.na9#D#L#L#L#L#L#L#L#L#La2a2a2a2#L#La2#L#L#La2#La2#La2#La2#La2#La2a2#La2#La2#La2#L#L#L#L#L#L#L#L#Laj#L#Laja9.7.Eafaja9a9#sa9#D#D", +"#D#M#Dbl#D#M#DblaY.NaYbl.NawaYaYaY#M#D#D#D#D.7afaja9#Lajbp#Lbpbp#Lajbp#Lbpbpa2bp#g#g#g.j#g#gas#g.j#g#g#g#g#g#g#ga2a2aj.7a9#Da9#Da9a9#s#D.s#x#I.Ca0aO#uazal.Y.A.1a.aHaGaz.Ta#bma##SaFaFbgama0.C#x.s.NaY.N.N#s#D#Dblbl#Dbl#D#D#D#D#Da9#D#D.7.E.7a9#D.saY#x.Wa0.8.5#S#uaB#S.5.C#x#x.NaYbl#Da9#D#D.Na9a9.7a9#L#L#L#La2asa2aaa2#ga2a2#L#L#L#L#L#L#L#La2af#L#La9.7a9#Da9a9.7#La9#L#L#L#L.3#La2#L#L#La2#Lafa2#La2a2#La2#La2#La2#La2#La2a2a2a2a2a2a2a2a2#L#L#L#L#L#L#L#L#La2.7#L#L.7af.7a9a9a9bja9#D#D#D", +"aYaYaYawaYaYaY.saY#M.NawblaY#Daw#Dbl#D#s#D#La9.7#L#L#L#L#L#L#Lbpa2bpa2aj#ga2bpa2as.j#gas.j#g.j#g#gbp.j#L#gaja2bp.j#Laf#L.7#s.N#sbjb..N#Ibf.Waq.8#vaz#zaHbs.m.B.BauaSa#aFaFbgama0ambga#aFamam.W.CaYaY.NawaY#D#D#D#sbl#D#D#D#D.Nb.a9a9.n.7#La9.7b.#Da9.s.Nbo.C.Cava#aZaBaBaOaOb#ao#x#IaY#D.n#Da9#Da9a9a9#L#L#L#L#La2a2#ga2#ga2#ga2bpa2#ga2a2#ga2a2#La2af#L.7a9a9.7a9a9#D#L#L#L#L#Laf#L#L#La2a2a2#La2#La2#La2#La2#La2#La2#La2#La2#La2#La2#La2#La2#L#L#L#L#L#L#L#L#L#L#Laf#L#La9.7.7a9.7a9#D#D#s#D#D", +"aYboaY#x#x#I#x#x#I#xaYawaY.NaYaY#D#M#Da9.7.7aj#L#L.E#L#Lbp#L#L#Lajbp#Lbp#Lajbpaj#gas#g#gas#gas.j#L#Lbp#Laj#gbp#L#Laj.7a9.7#Dbj.N.N.sbo.Caq.8#v#u#3adbe.A#Y#9.PbranaBb#amamaYaYaYa0am#vbmaOb#.C#x.s.N.NaY.N#Da9#D#pa9.na9#Da9.7a9.7a9.7a9.7.7.7.7a9#D#D.N.N#xbo.Cb#aOaF#vbma##vbmamam#xbl#D#D#D#Da9a9.7#Laf#L#L#L#g#La2bpa2#L#ga2a2bp#Lbp#L#Lbpa2#L#L#La9a9.7a9.7a9af.7af.7#L#L#La2#La2a2#L#La2a2#La2#La2#La2#L#La2#La2#La2#La2#La2a2a2a2a2a2a2a2#L#L#L#L#L#L#Laj#Laj#L.7aja9#L.na9#D#s#D#D#D.N.N", +"#x#x#x#I#x#x#IbnaYaY#IaYaY#MaY#M#D#D#Da9.7#L#L#L#L#L#L#L#Lbp.E#Lbpa2bp.j#L#g#L#g.j#gas.j#g.j#g#g#Lbpajbp#Lbp#Laj#L#Laj.7.n.N.N.sbf.C.Caoa#.w.ObB.u#.#oa8aMabalanaBa#a#a0#xaYaYaY.Wamb##Sa#b#a0.C#xaY.NaY.s#D#D#D.nbla9a9#D.n.7a9#L#L#L#Laj#L#L.7.E.7b.a9.s.N.N.s.Camam.8aF#vaZ#uaFb##xaYaY#D#D#sa9a9a9.7#L#L#L#La2a2#ga2#ga2a2#g#L#L#L#L#L#L#L#L#La2af.7a9a9.7a9a9a9#D#L#L#L#L#La2#La2#La2#La2a2a2a2a2#La2#L.3#L#La2#La2#La2#La2a2#La2#La2#La2#L#L#L#L#L#L#L.7#L#Laf#L#L#L.7a9.7bja9#D#s#D.N.saY", +".CaC.Ca0.Ca0#x.CawaYaY.Nbl.N#D#D#Da9.E.7aj#Lbp#L#L.7#Laj#L#Lbp#Lajbpaj#Lbpaj#Lbp#gas.j#gas#gas.jbpaj.7#Lajbp#Lbp#La9a9#D.N.s.N#x.WaqaO#ubk#zaHbA#Pbsbeab#a#ua#ambm.Fa0bn#xaY.N.s.Nbnb#bmaBa#aC.Caw.NaY.NaY#D#D#D#pa9a9a9a9.7a9#Laj.7#L#L#L#L#L#Lbja9bjbj#D.7.N.Nbo.C.Ca0a##vana7an#Sa0aYawbl#D#Da9a9.7af#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#Laf#La9.n.7#Da9.7afa9#L.7a2#L#g#La2#La2#La2#L#L#La2a2#La2#La2#La2#La2#La2#La2#La2a2a2a2a2a2a2#L#L#L#L#L#Laj#Lafaj#L#L.Eaf.7#La9#s#D#DaY.NawaY#x", +".C#xa0#x.W#x#x#x#DaY#Dbl.sblaY.Na9#D#L.7#L#L#Laj#Laj#L#Lbp#L.7#Lbpa2#L#g#L#g#L#g.j#gas#g#g.j#g.jbp.7#La3#La3aj.7.7aj.7#s.N.N#Ibf.8aF.y#3ad.A.MaT.P#V#P#Tan.5.C#Ia0b#bga0#xbf#xbf.N#xa0bm.T#Sao#x#x.NaY#s.N#D#D#D#p.nafa9.na9#L.7#L#L#L#Lbpaja3#L.Ebj.E.7#sbj#sbjbf.s#xavama#aBana7aZbgbnaY#D#D.7.na9a9.7#L#L#L#L#L#L#L#Lbp#L#L#L#L#L#L#L#L#L#L#La2a2#L.7a9a9a9.7a9a9a9#L#L#L#g#La2#La2#La2#La2a2#La2#La2#La2#La2#La2#La2#La2#La2a2#La2#La2#La2a2#L#L#L#L#L.7#L.7afaj#L#L#L.7a9#LaY.Naw.Naw#x#x#I", +"aY.saY.NaY#DaY.N.na9.na9a9a9a9aja9a9a9a9.7a9.7a9#Laf#L#Laj#L#gaj#Lajbpaj#Lajbpaj#Lafaj#L#L.7.Ea3#L.Ebj#D.s.N#Db..7.7.N.N.WamamaOakaybs#Y.maDbaaHaga7#SamamaC.C.CaYamb#aFb##xaY#D.n.Nawa0#vaZaZa##xaw.N#Daf.na9#s#Da9a9a9.7af#Laf#La2#g#g#L#Lbp#L#L#L#L#L#L.7.7.7.7bj.N.Caoam#vaZaz.fanama0aY#Ma9aY#D#Da9a9.7.7#D#L#La2#La2#L#L#La2a2a2a2a2a2a2a2.7afa9a9#D.7#D.7af#L#L#L#La2#ga2a2a2a2a2#ga2#ga2a2a2a2a2a2a2a2a2#La2#La2#L#L#L#La2#La2#La2a2a2#La2#L#Lafa9a9a9bja9#D#D#DaY.s.N#x#Ibn#x#x#x#x#U#x", +"aY.Naw#D#D#s#D#Da9a9a9a9a9afa9a9a9a9.Ea9a9.na9a9afajaf#La2#L#L#Lbp.7bp.7bp.7bp.7a2a2#Laj.7.E.7.E#L.E#D.s.N.Nbjbj.N.s.N#xa0aO#u#E#V#2....#KaD.YaGa7bmaFaFaoama0.CbnaCb#aOama0.N#D#Dbl#xa0bmaB#ua##x#xaY#sa9.7a9.7#D#D.7a9a9aj#L#L.j#La2bpa2#Lbp.E#Laj#L.E#L.7b.#Db.#D.s#xa0.8a##v.6azbhaOam#xaYbl#Dbl#Da9#Da9.7.7#La2#La2a2a2a2#La2a2a2a2a2a2#La2#L#L#L#D.7a9#Da9#L.3afa2#La2bpa2bp#g#L#g#La2#L#g#La2#La2#La2#La2a2#La2#La2a2a2#La2a2a2aja2#L#La2#Lafaj#La9.E#Da9#s#D#Daw.NaY#IaYaYaYawaYawaYaYaY", +"a9a9a9a9.na9a9.na9.na9.na9.na9a9a9.7a9a9.7a9.7a9#L#L#L#L#Laj#L#Laj#Laj#Laj#Laj#L.jbp#L#L.E#L.Ea3.n#D.Nbf.Cbo.Caobf.CamaOaBaz#EaraQ#.#o.Abzay.Gana#aFaFaOamam.C.Wbna0a0b#ama0#I.N#D#M#x.CaoaZbhaBa0#IaY#Da9#s.7a9#sa9#Da9a9#Laf#L#L#ga2#g#L#Lbpbp#L#L#L#L#L.7.7.7.7#D.NaY.Cambga#a7.6#ua#b#aoa0#xbl#D#Da9.7a9#Laf#L#La2#La2a2a2a2#L#L#L#L#La2#La2.7afa9a9#D.7#D.7afaf#L#La2#L#L#ga2a2#ga2#ga2#ga2a2a2a2a2a2a2a2a2#La2#La2#L#La2#L#L#Laf#L#Lafajaf#L#Lafa9a9a9#Db.#D#DaY#DaY.N.N.N.s#D.N#D.N#D#s#D", +"aj.7aj.7.7.7.7.7#Da9#Da9a9a9a9.7a9#Da9#s#D#D.n#Da9a9.na9.7.7bj.7bp#L#L#L#L#L#L#Laj#Laj.E.Ebjb..N#MawaCaoaoama0.Cb##va7#a.Oaz#uaZaZanaz#e.6anaZaFaBaOaF.5amama0a0#xaCa0ama0a0#xaYbl.NaY#xa0#vaZ.lama0#x#Mbl#D.7#D#Dbja9.Ea9af#L#La2#L#La2bp.j#Lbp#Laj#Lbpaj.7bj.7#s#D.s#x.Wa0amamanaB.0a##va#bgamaYaY#Da9a9a9#L#L#L#Laf#L#L#L.7#La2a2#La2#L#La2#L#L#L.7a9.7a9#Da9#L.3#La2#L#L#La2bpa2#g#La2bpa2bpa2#La2#La2#La2#La2#La2#La2a2#La2.3#L#La2#Laf#L#Lafaja9a9.7#s#D#D#Da9.s.N.s.Naw#Dbj.7b..7b..7bjbj", +"#L#Laf#Lajafaj#Laf.7.7.7.7.7a9.Ea9bja9#D.7a9bja9a9.7a9.7a9.7.Ebjaj#Laj.7.E.E.7.E.7.E#D.s#xbo.C.WaCamb#a#.y.0.yaB.Gazazazbhbma#aFaFa#a#aZaBa#.5.5#SaFambgama0amam#x#xbna0a0aCa0#xaYawaY#Ia0aO.lbh#vb#bnaY#s#D#s#D#Da9#Da9.7ajaf#Laja2bp#g#L#Lbp#Lajbp#L#L#Lbj.7.7#Da9#DaY#x.CaCam.5a#aOa#a##va#a##xawaY#Da9.7#L#L.7af.7#La9#Laf#L.7af#Laf#L#Laf#Laf.7a9.7a9a9#D#Daf#L#La2#L#L#L#La2a2a2#ga2a2#ga2a2a2a2a2a2a2a2a2#La2#La2#L#L#L#L#Laf#Lafa9a9a9a9a9a9a9bj#D#D#D#D#D#D#Da9#Da9#D#s#L.7#L.7#L.E#L#L", +"#Laj#Laj#L#L#L#L.7.n#La9aja9#L.7a9#s.7#Da9#Da9bj.n#Da9.7.E#Dbj#D#D#D#Da9#Da9#Da9.N#I#x.Wam.8.5#va#aBaP.G#a.U#4.Uaza7aZa#aFaFbmb#a#b#aFa#.8ama0ama0a0a0a0a0aC.Ca0#I#x#xa0b#a0a0a0aYaY.N.N#Iambm.lbmaFaobnaYaY#Dbj#D#s.7a9a9af#L#L#La2aj#ga2bp#Lbp#L#L#Lbp#L.7.E.7#D#D#D.saY#x.C.CaC.5am#v.5a#.0#va0bn#x.N#D#D.7.7a9.7a9.7a9.7.7a9#L#L#L.7af.7#L.7#L#L.7a9a9bja9#Da2afa2#La2#L#L#L#L#g#L#g#L#g#La2#La2#La2#La2#La2a2#L#L#La2afa2af#L#L#L.7a9.Ea9.7.n.7#Da9#s#D#D.N.N.sbj#sbjb..7bj#Laj#Laj#L#L.7#L", +"bjbj.7bj.7.E.7.7.7.7a9.7a9.7a9.7#D#D#D#D#s#D#D#D#D#D#D#D#D.N.s.N.sbfbobf#Ibf#xboa0.8.5#v.yan.w.G#TabaMa8#cabalaZa#aFa#b#b#a0b#b#ama0aoa0a0#x#x.CawaYaY#Ubn#xaYaY#x#x#x.Rbna0a0amaYaY#D#DaY#UaF#GaZ#S.V#UaY.s#Dbj#s#Da9.n.7#La2af#L#La2#g#gajbp#L#Lbp#L#L#L.7bj.7a9#s#Dbl.N#x#x#x#x.C.Cam#va#a#.0aF.8a0#x#x#D#D#Da9#D.7#Da9a9.7.7#Laf#L#L#L#Laf#Laf.7a9a9.7a9#D#Daf#La2#La2#L#L#L#ga2#ga2a2#ga2bpa2a2a2a2a2a2a2a2#Lafa2#L#L#L#L#Laf#La9a9#La9a9a9a9#D.7#D#D#D#D#D.s.Nbja9.7.7a9.E#L.7.7.7.7aj.7aj", +".7a9b..7.7bjbj#D.Eaf.7#L.7af.E#L#D#D#D#D#D#D#s#D#D#s#Dbj#D.s.N.N.C#x.C.C.C.W.C.Wby#vaBaz#T#4aH#..ga8bsbr.2al#TaZaFaFb#b#ama0a0a0.Cama0#xaY#x#x#xaYbl.NaYaYaYblaYbf#x#x#xbna0a0aobn#xaw#D.sa0.t#SbmbmaOa0#U.N#D#D#D#D#Da9a9#Laf#L#L#La2#L#g#L#Lbpa2ajbp#Laj.7.7.7#Dbl#DaY.N.N#Ibf.Naw.Cao.5.5a#a##va#ama0bf#D.N.N.7#Da9#D.7a9.7a9#L.7#La9#La9#L.7#L#La9.7a9bja9#Da2af#La2#L#L#L#L#g#La2bpa2bpa2#La2a2#La2#La2#La2#L#L#Laf#L.3#Laf.7a9af.7a9a9.7a9.7#D.n#D#D#D#D#Dbjbj#Dbj#s.7.E#La9.n.7.na9.7a9.7", +"#Laj#Lafajafaj#La9#D#s#D#D#D#DaYaYaYawaYaY.NaY.N.C.C#x#IaYaY#M.namav.8.5#v.0.w.G#aau#4#4#z#3.Ga7#Z#0aM.gaTayaZa0a0a0a0#xbn#x#U#xawblawaY#D#M#D#D#D#Da9#D#sblaY#Mbl#Mblbl#DaYaYaYa0#IaY.N.NaY#Ua0.t.tbm.Fam#x.Nb.#Da9a9.7af#L#La2aj#L#L#L#L#Laj#L.7#L#L#L.7#L.7af.7.7a9.7.n#D#D.NawaYaY#x.CaCamao.0a#aB.0.taFb#.VaY#Da9a9af.7#D.N#Laf#L#L#L#L#Lafa9a9a9a9a9.7.7.7a2#La2a2a2a2a2a2a2a2a2a2a2a2a2a2#g#L#ga2a2#ga2a2a2a2a2a2#L#Laf.7#pa9a9a9#Dbj#D.N.na9a9a9b.#D#D#D#D#s#D#D#D#s#D#D.n.7#L#L#Laj#L.7", +"aja2afaj#L.7.7#L#sa9#D#D#s#D#D.N#D#D#D.N.N.N.N#DaY.N#x#xaCamb#aF#SaZanaz.Galba.4.O#aaz#uaB.0aBan#Tbz.mab.2az.5#xa0bnaYaYaYaYaYaY#DaY.NaYbl#D#D#D#D.n#D#Dbl#Dbl.Na9bl#Dbl#DawaYaYbnaYaY#D.s.N#xaCbm.Fbm.tb#aC.N.Nbl.na9a9aj#L#L#L.7#L.7#L.E#L.7#L#L#L#L#L#L#Laj#La9aj.7.7.7#D.N#D#Dbl.N#xbn.Ca0ama##va##v#vbm#vaF#x#x#Da9a9#D#D#D#L#La9#L.7af.7#L#pa9afa9.7#D#La9#La2a2#La2#La2#La2#La2#La2#La2#La2#ga2a2bpa2bpa2a2a2a2a2a2#La9afa9.na9a9#D#D#Dbja9.nbj#D#D.NaY.saY.Nbl.sblaYaY.Na9.7#Laj.7.7#L.7", +"#Laj#L#Laja9.E.7#La9.Ea9#D#D#s#Db.#D#D.Nbo.Caqaq.bbnbga#aZaS.G#q#t.HaQauaGar#a#a#vaOaF.5b#.8#vaB.2.A.1aDaka#amaYaYaYaYaYaYaY#D#D#D#D#s#D#D#D#D#D.7.7a9#D#D#D#Dbla9a9.n#D#D#D#Dblaw#xaw.N#DaYaYbnb#aF.taOb#.C#I.Na9a9.7a9a9#L.7#L#L#L#L#Laf#L#L#L.n#L#L#L#L#L#L#L#La9a9.7a9.Ebj#D#D#D.s.N#x#x.W.Ca0amamaFa##vbmaBb#bnaY#D#D#Da9bjaf#L#L#Laf#L#L#La9a9a9a9a9a9.7.7a2af#L#L#L#L#L#L#L#La2#La2#L#L#L#L#L#L#L#L#L#L#La2#L#Laf#La9.7a9a9afa9a9bj#s#D.Nbl.NblaY.NaY#xaYawaYawaYbl.sbl#M.7.E#L.7#L.Ea3.E", +".7.7.E.7.Ebj.7.7.n.7a9.7#s.N.N#DaY.N#x.Cam.5a#aZaF#SaZa7arala6ay#W#W#kbhbmaFa#.5#x#x.CaCaoamaOaB#P#obsba#uam.C.NaYaYaY#D#D#D#D#Da9#Da9#D.7#Da9a9#La9.7.7a9bl#s#Da9a9a9bla9bl#D#DaY.NaYawaYaY#IaYa0aCb#.Va0a0#U.N#D#Da9.7a9.7aj#L#L#L#Laj.7#L#L#L#L#L#L#L#L#L#L.7#L#L.E#La9.7.7.7#D#D#DaY.s#x.C.C#x#Ia0aCama#a#aZa#.8a0#xaY#Da9af.7#Da9#D.7#Da9#Dafa9afa9.7a9#La9#L#L.3#L.3#L.3#L.3#Laf#L#L#L.3#L#L#L#L#L#L#L#L#L#L#L#L#La9.7a9a9a9#D.na9bl#DaY#s#x#x#x#Ia0#I#x#xawaYblaw.NaYaYaY.7#D.7.Ebja3.7.7", +"#Db.#D#D#s.N.s.NaY.Naw.N.NaYbo#xa0b#a#bmaS#aa6.Kbaba#a.faZaFb#amb#b#ama0.C#xbf#xbobf.NaY#xao#v#u.q.qaGanamaYaY#DaY#sbl#Da9.7#L.7.7.E.7a9.E#L.7.E#L#L#La9.nbjbl#Da9a9.7a9.7#D#D#DblaY#xaYaY#IaYaY#xbna0bnbna0aCbn#sbl#Da9.7af.7a9#L#L.7#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#La9.7af.7a9aj.7#D#D.N.Nbo#x.Nbl#Ia0am.5aO.0aB.0b#.CaYbla9a9a9.7a9.7a9.7a9a9a9#pa9a9a9bj.7.7#L#L#L#L#L#L#L#L#L#L#Laf#L#L#L#L#L#L#L#L#L.7#La9#Lafa9bja9#D#D#D#Dbl#DaYaYaYaYaY.C#xama0.CaC.C.C#x#xboaYaY.NaY.N#s.N#D.N.s.NaEaW", +".N.N.s.N.Nbf#xbfaCa0a0a0a0amam.8aZbhazaGau#j.e.e.6ana#.5ambn#xaY#I#x#xbo.N.N#saW#x#Ibfaw#x.5aZ.G.q.KaBam#xaY.s#D.7#Da9.7.E#L#L#L#Laf#L#L#L#L#L#L#Laj#L#L.7#Da9#Da9.7a9#D#D#Da9#D#DawaY#IbnaYaY.Naw#xbnbnbna0bna0aY#D#D#Da9.7#L.7#L#L#L#La9#L#L#L#L#L#L#L#L#L#L#Laj#L#L#L.n.7.7.7#La9.E.7#D.N.N.N#saY.N#x.Wa0.5aF.0aZ#v.5a0aY#Da9.7#Da9bja9#D.7#Dafa9afa9.7a9#La9#La9#La9#La9#La9#La9#L.7a9af.7af.7#L.7.7#L.7af.7.7a9.7#D#D#D#D.N.saYaY#x#I#xbnbnaOaoaoamaCa0a0bn#Ibn#x#x#x#x#I#x#xaYboaY.N#xbf#x", +"#x#xa0.CaCa0aoa0aFa##v#vaZ#uaZaZarazazanbmaF.5a0.C#x#x.N#D#D#D#D#D#D.Nblbj#D.N.sbf#x#I.CbgaBaz.2baazaF#x.n.7#Dbla9.7.7#L#L#Lajbp#L#L.E#La9#L.7#L#Lbp#L#L.7#L#D.E#L#L.E.7.7.7.7#Dbj.N#xbna0#I.N#DaYawbna0bnbn.V#U#D#D#D#D#D.7a9.7#Laja9#Laj#L#L#L#L#L#L#L#L#L#L#L#La2#L#L#L#Laf.7#L#L#La9.7#s.N.N.7#D.N.N#x.CaCaq#vaZaBa#aF#xaYbl#D#D#D#D#D#D#D#Da9a9a9a9a9a9.7.7#L#La9.7a9a9#L#L#La9a9a9.7a9.7#L.7af.7af.7a9.7.7#D#D#D#D#D.N.NaY#x#x.Ca0b#ambgamaOb#aCa0.C#I#xaYa0a0#xbn#x#xbna0aCa0a0a0ao.CaCaq", +"aoa0aoaO.5.8aFaO#u#uaSazaG#3araza#a#amam.C#x.s.Nafaf#La9bjaWbfbf.N.NaY#xawaYaYaY#x.C#xaCamaB#aaT.GaF.C#D#La9#L#D.7#Laj#L#Lbpbp#Lajaf#L#La2#L.j#Lbp#L#Lbpa9.7#Da9.7#La9#La9.7a9.7#Dbl#xaCbn#xaY.s#D.N#Ubnbnbnbna0bl#D#D.7a9.7#L.7a9#L#L#L#L#L#L#L#L#L#L.7#L#L#L#L#L#Laj#L.7#L#L.7a2.7#L.7.7#D.N.Nbj#D.s.N.N#I.Ca0aFaZaBaZ#vam#xaY.7#Da9#D.7#Da9#Dafa9afa9.7a9.7a9#L#Lafa9#La9#L#La9af.7a9a9a9afa9a9#L.7.7a9#L.7af#D#D#D.N.N.NaY.s#xama0.8aF#Sa##va0a0a0#xbnaYaYawbn.WbnaCbnaCa0aCaFb#aO.5aOaF.8aF", +"aZ.ya#amaoaFaB.Taka6aGaraBaFa0#xbnaYaYaw#D#Da9#D#L.Eaf.7a9aj.7.7aja9.n.7#D#D.sbfaw.N.Wam#v.w.Ga7.C#IaY#D#s.7.n#Laja2#L#ga2#ga2#g#L#Lajafaj#L#L#Laj#L#L.na9a9.na9a9a9.na9a9#L.Ea9a9#saYaY#x.C#x#xaYbn#x#U#x#xa0aCbn#D.7#L.7a9a9#paj#L#L#L#L#L#L#L#L#L#L#L#g#L#L#L#L#L#L#L#L#L#L#Laj#Laf.Ea9.7.7a9#Da9#D#D#DaY.NawaY.pa#.0.0a#ambn.N.N#D#D#D#D#D.7a9af#L#L.7#L#L#L#L#L#La9a9.7a9#Da9a9#Da9bja9bj#D#D#D#D#D#D#D#D#D#s#D.saY#xbn.8aFaZaBaZa#aFama0aqaC#x.N#MaY#x.Ca0aFb#b#amamb#.5aFaoaOaFaOa#bmaZ.y", +"aZa#aOa##v#vaB.T#4#z#a#uaFa0aC#xaYawaYbl#Da9#Da9.7a9.7#L.7a9.7a9af.Ea9.7#s.N.N.N#D#Ia0.8a#bkaraZ#IaY.s#D#Da9.7#Lbpa2bpa2#g.j#ga2ajaf#L#L#Laja2#Laf.7#L.7a9.7#Da9afa9a9a9a9.7a9#La9#Dbl#x#x#I#x#xawaY#U#xbn#Ia0.CbgaYa9#L#L#Lafa9#Laj#Lbp#Lbp#Lbp#Lbp#L#ga2#g#La2#L#L#Laj#Lbpaj#L#L.7#La9.7.7a9.7.E#D#D#D#D.saY.N#Ua0#va##S.0aOamaY.N#D#D#Da9#D#Dafa9a9af#L#L#L.7af#Laf#La9#Da9.7a9a9.7#D#D#D#D#Da9bja9a9#D#D#s#D.N.N#x.Ca0aoaF#vaZbmbmaOa0.W.C#x.C#xbl.NawaY.CamaCamaCamamambgamb#.5aOa##Sa#.yaZ", +"#vaFaO#v.ybmaZazbaauazb#a0#x#xaYaYaY#D#sa9#D.E.7aj#L.7aja9aj#L.7aja9.n.7#D#D.sbfaY.WaCam#u#3a7aFaYaY#D#D.n.7ajafaj#gaj#g#L#g#Laj#L#Lajaf#Laf#Laj#L#L#La9a9#Da9a9.na9a9.7.n.7.7a9.na9aY#x#x#x#x#xaYaY#x.R#IbnbnaC.t.VaYa9.7aj#L#L#Lbp#L#Laj#La2#L.j#La2#g#g#g#gajbp#Lbp#L#L#L#Lbp#L#L#L.7a9.7.7.7a9#D#s#D#DaY.NaYaYa0ama#a#.yb#a0.N.N#D#Dbj#D#Da9a9a9.7a9bja9.7.7a9a9a9#D.7#D#D#D#D#Da9#Da9#D#D#Da9a9.n#D#DblaYaY.8b#.8aOaFaOaFaOb#bgama0#x#x#x.N#U#x#I#x#x#xaoama0bna0bnaoam.5amaOaFaFaF#va##vaZ", +"aOaOaF#va#a#az#faS#ubmb#a0#xaY#Dbl.n#Da9a9.7#L#L#L#L#L#L#L#Laj#L#L.Ea9a9#s.N.N.s#x.Wb##v#Ebk#va0aw#D#D#Da9#L#L#Lbpa2#L#ga2#ga2#g#Laf#L#L#Laj#Laf#L.7#L.n.7#D.na9a9a9a9a9a9.7a9#La9#sbl.NaY#xaYaYblaYaw#x#x#x.C.C.Fb#bnbl#Da9.E#L#Laj#L#Lbp#Lbp#Lbp#Lbp#L#g#L#g#L#Laj#Lbp#Lbp#L#L.7#L.n#L#L.7af.7#Da9#D#D#D.NaY.saY#Ibn.5a#a#aFambf#x.NaY#D#D#D#Da9a9a9.7a9.7.7#L#D.nbj#D#D#D#D.Na9b.bl#Daw#xaYaYaYaYaY#Ia0a0aoam#uanaBa##vb#bgb#bnbnaYaYaYaYblaw#x#x#x#Ua0.Wa0a0.W.C.Wama0ambg.5aFaFa##va#a##va#", +"b#ao#vbmaB#uaz.Gb#b#ama0#xaw.N#D#Da9a9a9.E#L#Laj#L#Laj#L#L#L#L#L.Ea9.n#D#D.N.N#x#Iao.5#u.Oazam.C#Dbl#sa9ajaf#La2.jbp.j#L#gajbpaj#Laj#Lajaf#L#Laj#L.n#La9a9a9a9#D.na9a9.Ea9.n.7a9a9#DaYaw#x.sbl#D#sblaYbl#I#x#Ua0b#bgb#bn#D#D.7#Lbj.7.7.7.7.E.7.7#L.j#La2#g#L#La2bp#L#Laj#L#Laj#L#L#L#L.7af.7.7.7a9.7#D#D#s.Nbl.NaYaY.CaCby#va#.8#xbfaY.N.s#D#Dbj#D#D#D#D#D#D#D#D#D#D#D#D.Naw.NaY#D.NaYaw#x#xa0aoamamaFaF#v.0bbanaBaZ#vaFb#am#x#xaYaYaYaY#IaY#D#D#x#x.Ca0avamama0.C#x.Ca0aoamaFa##uaZaBaZ.y#S.0.y", +".8aOa##Sazar#ua#a0am#x#x#x.N#D.7.na9#L#L#Laj#Lbp#L#Lbp#L#Laj#Laj#La9.7.n#D.sbo#x.Wao#v.f#f.ya0bf#M#D#Da9a9#L.ja2#La2bp.j#L#ga2a2#Laf#Laf#Laj#Laf#L.7aj#Da9b.bl#Da9.na9a9a9a9.7.n#D#MaYbfaYaY#Da9#D#D#Daw.NaY#x#Ib#b#bg.VaYbl#s#L.Ebj.7b..7.7.7.7#Lbp#Lbp#L.jbp#L#L#Lbp#Lbp#Lbp#L.7aj#La9.7a9#L.7a9#s#D#D#DaY.Naw.N.s.CamamaOa#a#.W#xbf#xaY#D#D#Da9#Da9#Da9bj#Dbj#D.N.Naw.N#x#xbfaYaw#x.Ca0a0aFbma#aBaZbbaZ#uaZ.0bgb#a0am#x#x#xaYblaY#MaYaY#Dbl#DaY#xaCamamaoaqaC.C.Wamao.5a#a#.yaSazaZ#uaZ.yaOaF", +".5aF#Sbhaza7aFa0a0bn#xaw.N#D.7.7af#L#L#L#La2#L.j#g#Lajbp#Lbp#Lbpaja9.n#D#s.N#I#I.WaF#uarazaF.W.Nbl#D.n#Laj#La2a2aj#g#L#g#L.jbpaj#Laj#L#Lajaf#Laj.7afa9.na9#D#D#Ma9#p#s#D#sa9.na9#DblawaYaw#Da9a9#D#D#saY.Naw#x#xaCb#.VaC.V#xaY#Dbj.nbja9bj#s.7.7aja2#L.j#Lbp#La2ajbp#L#L#L#L#L#L#L#L#L.Ea9.7.7a9#D.7#D#D#D#DaY.N.N.N#I.CaoaFa#aB.C#x#xbf#x.N.NaY#Dbl#D#D#D.N#D.NaY.saYaY.C.W.C.W.Caqa0.8a#aZaBan#u#uan#Sa#b#ama0bnaY#xaYaY.NaY.N#s#DaY#DblaY#Dbl#I#xam.8.5aOam.Cama0aoaFbmaBbha7#a#ea7an.y.yaF.8", +"bc.y.wara7b#a0aoaYaYaYbl#Da9.7.7#Laja2#L#g.j#g#ga2bpa2bp.jbpaj#Laf.Ea9#s#D#I#I.C.WaOaz#EaZb#.C.N#sbla9afafaj#L.j#L#g#L.jbpa2bpa2#Lafajaf#L#L#Laf.E.7.n#Da9#D#sbl.n#D#M#s#D#s#D#s#DawaY.NaY#Da9.n#D#D#D#DaY.NaY#I.CaCam.Vb##U#xawa9bj.7b..7bj.7bj#Laj#Lbp#La2#L#Lbp#L#Lbpaj#Lbpaj.7#L.7af.7a9.7.Ea9#D#D#s#D.N.saYb..Nbf.Wa0aF.0#ua0.W.C#Ibfaw.NaY#saY.N.N.N.N.N.N.N#xaY#I#x.W#x.C.Wam.8aZ.waz#ubha#aFaFb#ambn.bblawaY#MaY.N.s.N.N#D#D#D#DaY.saY#I#xaCam.8aFbyaoaCaoamama#a7azararaya6.G.Gaz#u#v.8", +".J.far.laobn#xaY#D#sa9#D.7a9aj#L#L#L#L#L#Lbp#Laj#g.j#ga2#L#L#Lbp.na9.7#s.N#I.Caobh#EaBaCbn.s#IaY#Ma9.n.7#L#L#L#Laj#Laj#L#Laj#L#L#L#L#L.7aja9.Ea9bl#M#D#M#DblaYblaYawaYaYawaY.NaYawaY#Mbl#D#D#D#Da9.n#D#s.Nbl.saY#x.RaY.N#xa0aFbm#IaYaY.N#s.7.E#L#L#La2#L#L#Lajbp#L#La2#L#L#L.7#La9a9a9.7#L.7.7.7#Da9#D#D#DaY.N.NaYaY#Ia0.5.8a#an.0.5bn#xbl.N#x.C#Dbl.sblaY#I#x.W.R#Ibna0aOa##vaZazararaz#ua#aFaO#x#I#x#Ibn#x#xaYaYaY#DblaY#Dbl#Dbl.NblaY.NaY#x#xaoaobnaY#xaCa#.0aOaOaOaFaFaFaFaF.l.Ta7bh.G.G#q#e", +"araza7aFam#xaYawa9#Da9a9a9#L#L#L#L#Lbp.j#L#La2#Las#ga2#gbp#Laj#L.7.7.n#D#M#xaCaFbk#iaOaC#xblaY.Na9a9a9afaja9aj#L#L#Laf#Laf#Laf#Lajafaja9#L.7a9.Ebl.n#D#M#DawaYawbn#Ubn#I#x#I#xawaYawaYaY#D#s#D#D#D.n#D#DaY.s#x.N#U#IawaY#xbna0aF#x.W#xaw.N#D.7b.afajaf#L#Lbp#L#La2#L#L.E#L.7a9.7a9a9.na9.7a9.7.7#D#s#D#D#D.Nbl.Naw.N#x.CamaF.0.y.yaF.CaYaw#x.Caq#Ibn#x#x#x#xbna0aoamaF#vana7.wazaZan#uaZaOamamamaY.RaYaYawaYaYaYaYblaY#D#Dbl#DaY#DblaY.N#xaY#I#xbnbnawaYbnam#va#ama0a0aoamamaoam.taFbmaZ.6ar.2#4", +".faBb#a0aY#xbl#Da9a9#D.E.7#L#L#L#g#ga2#g#g#g#g#g#g#g#ga2#L#L#L#L.n.7a9a9.N#Iam.8#f.Gb#bn#UaYaw.Na9.na9.7af#Laf#Lajafaj#Laj#Laj#Laf#Laf#L.na9a9#D#Mbl#M#DawaYaw#x#I#U#x#U#Ibn#I.NawblaY#s#D#D.N.sa9#s#D#M.NaY.s#xawaY#D.s#D.Nbnama0a0aC#x#xbl.NaY#La9#L.E#L#L#L#Laj#L#L#La9.7aja9a9a9a9#D.n.7a9.7#s#D#D.Naw.N.NaY#Dbl#I#xaC.5#va#aBaFa0aC.C.Caoa#ama0a0ambgaF#va##uan.w.wan.wanaZ#vaFb#ama0a0#x#xaYbfaY#xaY.Nbl.Nbl#D#D#Dbl#D#D#D#DaY#saY.N#x#x#xaYaYaYaY#Ia0bg.5bn#xbn#xbna0a0amaCb#ao.t#SaZar#a", +"aFama0aY#xaY#Da9#D#Da9a9#L#L#L#g#ga2#gbpa2bpa2bpa2#ga2#gbpajbp#L#Da9.7#saYaY.W.5#EaraFa0#U.NblaYa9a9a9ajaf.E#La2#L#L#L#Laf#Lafaj#Lafaja9#D.n#D#D#s#DblawaY#I#x#Ibnbn#I#U#x#IaY.N.Rawbl#D#D#D.s.N#D#D.saY.saY#I#x.N#s#s.7bj.N#xa0aob#amaoa0#I#xaY#D.na9.7a9bpaj#L#L#L#La9.Ea9#D#D#D#D#D#D#D#Dbj#DaY.Nbl.N.N#x#xbfaw.NaY#xama0aOa#aBa#bgama0.5a#.0aFaOaF#SaZan#ua7bhazaBbhaBa#aFb#b#aCbnbn#x#xaYaw.Nblaw#D#Dbl#D#D#s#D#p#Da9#D#D#Dbl#DaY#x#xaw#x#xaY.NaY#x#x.C.C.CawaYaw#xaw#x#Ibn#x#Ua0a0amaFbmbm", +"bn#xaYaYaY#Ma9af.7.n#L#L.7#L#ga2bp#ga2#g#ga2#ga2#ga2#L#L#L#L.7.7#s#D#s#D.N#xamaoaS.OaBam#xaYaw.N.na9a9#Laf#L#La2ajafaj#L#Laj#Lafaf.na9a9a9bl#D#Mbl#saYaw#x.b#x#x#U#Ibn#I#xawaY.saYaYbl#D#D#D.N#D#M#sblaw.N#I#x#I#D#sbj#Db..N.N.Camamb#am.pa0a0bn#D#Da9.7.7aj#Lbp#L#La9.7a9a9#s#D#MaY#D#Dbl.saY.N.N.N.s#x#xbf#I#x.NaY#I.CaCamam#vaBbm#SaF#va#a#aB#ubh#uanaBaBbmaZ.FaFb#b#a0aCbn#I#x.RaYawaYawaY.N#D#D#D#D#D#D#D#Da9#Da9#Da9#Da9a9.saYaw.Naw.N#xaY.N#x#xaY#xaC#xaYblaYaYaYaYaYaY#xaYblaY#Ua0a0.Vbn", +".NaY#D#Da9a9a9#La9.7.7#L#L#g#L#ga2bpa2bpa2bp#gbp#g#Lbpaj#L.7.Ebjbj#D#Dbl.s#xaoa##TalaBam#x.NaY#Da9a9a9af#L#L#L#L#L#Lafaj#Laf#Lajafa9a9#p.n#D#M.NblaYaYawaY#x#I#x#Ibn#U#Ibn#I.NaYawaY#sbl#saY.s.N#sbl#s.NawaY#I#x#I.N#D#s#D.N#Ibnaoa0#Ia0a0b#aoamaw.N#Da9.7#L#L#L.7.n#L.7#s#DaW#DaYaYaY#I.NaY.N.N#I#x#xbf#x.C.C.C#x#I.Ca0amama#a#a7azaza7aZaB#uan#uan.laZ#SbmaFaF.V#Ubn#UaYaYawaYaYawaY.NaY.N#D.N.n#Da9#D.n#D.7a9#Da9bj.nbja9#s#DblaY#D#x#xaYaY#x#M.N#x#I#x#x#xaY#Dbl#DaYaYaY#xaw#x#IaYaYaY.baYaY", +"#D#D#Da9a9#Lafaj#L#L#Laj#Lbp#ga2#g#ga2#g#ga2#ga2#g#L#Lbp.7.7.7#D#D#s#D.saY.C.8aB#4#zaZa0#xaYaw#Da9.na9#L#L#Laja2#Laj#L#Lafaj#L#L#p.n#pa9blblaYaYawawaYaY#I#x#x#Ibn#Ibn#I#x#U#x#IaYblaYaY.Nbl.saY#s#Daw#Dawbf#I#x#I#x.s.N.s#xa0aC.C.Ca0.CaCa0ambg#x.N.s#D.7aj.7aja9.7a9#sa9#D.s.NaYawaYaYaY.NaYaYbf#x.C#x.W.C.Caqavaqa0ao.5#va##vaS#W#aazazanbm#SaFaFa#aFaOaFbgb#aCbnbnaw#x#x.N.N#sbl#D#s.N.N.N.N.7.7.7.7.7.7a9.7.7.7a9.7a9.7.7.7aY#DawaY.NbfaY#x.NaY#x#x.C.WaY#D#M#DaY.NaY#x#x#x#x#x#xaYaY#Da9#D", +"a9.7.7.7afaj#Laf#L#L#L#La2#La2#gbpa2bp#g#L#g#L#g#Lbp#L#L.7.7.7bj.s#D.NaY.Nao#v.QaD#za#am#xaY.N#D#pa9a9ajaf#Laf#L#Lafa2#La2#Lafaja9#p.na9#MblawblawaYaY#I#x#I#x#x#Ubn#Ibnaw#x#IaYaYawaY#M.saY.N.s#D#M#D.s.Naw#x#I.W#x#I.s#x.W#Ua0.Cava0.W.Ca0a0a0#I#IaY#D.7#L#L#La9.E#D#D#D.N#D.sbnbn#x#x#x#x#I#x.C#x.W.Caqamavam.C.5.5aFbya#.y.0.Gakar#e.TaBaFaF.5aFaOamb#a0aoambn#Ua0.C.Ca1bfbf.Nbl.N#D.N.N.N.Na9aj.7af#Laf#L.Eaf#L#L#L.7.n.7.n#DaYblbfaYaY#x#x.s#xbo#x.C#x.Na9#D#DaY.N#x#IaY#xama0bn#x#D#D.7#L", +"#Laj#L#L.7#L#L#Laj#L#Lbp#g#g#g#La2a2a2a2#ga2#L#L#L#L#L#L.7a9.7a9#Da9.s#Iama##u#.bA.faFaYawaYaYbfa9a9afa9#L#L#Lajafajafafajaf#Lafafafa9a9bl#Dbl#s.RawaYaY.R#U.R#Ubn#Ubn#Ibn#U#x#x#M#D#D#Daw#D#s#DaYaw#s.n#D.s#I.Caoaoam.8.5aO##am#va#byaFbcaqav.CaFaOaFaC#x.N.saW.N#D.N.s.N#I#xbn#U#xaw.R#x#xbna0#U.Vamb#b#aFa#bmaBaZ#vaZ#v.0aB.yaFaO.5bgamamamaobn#U.C#Ua0aCbnbnawaY#MaYblaY.saY.7.n.7.na9.E.7.7#La9#Laj.7#L.7af#Lafaja9a9a9#Da9.Nbl.Naw#x.s#xaY#x#xbn#x.baYaY#Da9.na9#DaY#x#x#x#IaYaY#sbla9.na9", +".7af.7#Lajaf.7#L#Lbp.j#L#g#L#g#ga2#ga2#g#La2#L#Laj#L#L.7a9.7.n.7#sbl.NaYaoa#azbAa6a7am.RaYaYaY#xafa9a9af#Laf#L#L#Lafaj#Laf#Lafajafaja9.n#D#M#DaYaw.R.RaY.baY#UaY#Ubn#UaYbn#x#I#x#M#D#M#D.s#D#s#D.s#Dbl#s#s#MbfavaCbgaCaoaC.5ao.5#vaOaOam.8.8amavb#b#aoaC#xaw.N.N#s.s.NaYaw#xbnbnaCa0a0a0amamaoaFaFaFa#.yan#u.G.6aBaBbmaO.5b#.5b#amaoa0a0amaCa0a0aY#xbn#Ibn#Ibn#IblawaYaY#M.Nbl.N.n.7a9.7a9.7afa9.7aj.7#L#L#L#L.7#Laf#La9a9#D.7#D#s#DaYaY.NaY#x#xbn#x#x#U#xaYawaYa9a9a9bl.NaY#x#x#xaYaYbl#Da9.7a9", +"#L#L#L#L.7#L#L#L#La2#L#L#ga2#g#L#ga2a2a2#ga2#L#L#L.7#Laf.E.7.7#DawaY#I.CaoaBazbaaSa#.VbnawaYaY.N#pa9afa9a9#Laja9af#Lafafajaf#Lafa9#pa9blblbl#MaYaYaYaw.R#x#UaYbnaw#x.R#I.R#I#x#xaYaw.NaYaw.N.N.s#D.s.saw#I.CaoaoaO.F#vaOaO.8#vbc#va#aO#vaO.5.8aCaFaO#SaOaOao#I#x#MaYawbnbnaCa0b#a##va#a##vaZaZ#uazazbh.Galay.2alaFaOaFamaCa0aC.C#I#x#x#I#x#xaY#IaY#I#x#I#x#x#I#xbl#D#M#D#D#s#D#D.n.7.n.7.n.7.7.Eaf#L#L#L.7aj#L#Lajaf#La9.7a9a9.7bl#DaY.NaYaY#x#xaCa0#x#xbnawaY#D#Da9#D#DawaY#x#I#xaYaY#D#Da9a9a9", +".7#L.Eaf#L#Laj#L#L#L#g#L#g#L#g#g.ja2a2#ga2bp#L#L#Laf#L.7.7a9.7#Dblaw#x.W.5az#aalaZb#a0bnaYaY#DaY#p#Da9afa9a9#L#Laja9aja9#La9aja9.na9#sbl.n.NblaYaw.R#xawbnaY#U#U#x.R#Ibn#I#x#I#xawaYaY.saY.s.N.N.s.saw.W.Waobc.yaBaB#u#S.y.y#va#aB#u.Qaz.waBaZ.yaZaB.0aBaB#vaO.5bn.Vb#am#Sa#aB#u.wbhazazbh.waz.GarazaSaz#a#a#a#ea0a0#Ubn#x#I#x#xaY#MaYblblawbl.NblaYaYaY#U#IaYaY#D#M#D#s#D#D.n#D.7a9.7a9.7a9.7a9#L#L.7af#L.7af.7af#L#L.na9a9bja9#D#D#DawaYbfaw#xbna0#x#UaYaYaYbl.n#Dbl#DaY.N#xaY#xaYaY#D#Da9a9.7", +"#L#L#L#L.7#L#L#L#g#ga2#g#g#ga2bpa2#ga2a2#ga2#L#L.7#Laja9#La9#sa9.NaYaY.Wambk#zaraFamambnaYblaYbl#Dbla9a9.7a9.7a9a9.7a9a9.na9a9a9#Da9bl#DblawaY.N.RaYbnbnbn#Ubnbn#I#U#x#x#x#I#x#Ibl.Naw.NaYbf#I#x.s#x.WamaO.y#uazal.U#z.U#T.G.GaP#Tal#z.U#3al.Ualal#T.G#T.G#e.w.wa7#ua7a7aS.G#e#TaS.w.wanaz.wazaS#vaOa##va#aFaFam#UaY#xaYaY.NaY.s#D#D#D#s#D#D#D#s#D#saY.saY.NaY#sbl#D#M#D#D#Dbj#D.n#L.E#L.E#L#L#L.E#L#Laj#L#L#L#L#Laf#La9.7#Da9#D#D#DblbfaY.N#xaY.C#I#x#xaYaYaY#Dbl#D#D#Dblaw.NaYaYaYaY#D#pa9#La9", +"#L#L.7aj#L#L#L#L#g#L#gbpa2bpa2#ga2asa2#g#La2#L#L#L#L#La9.7.7#D#sbl.N#Ia0#vaz#z#eam.Va0bnaYaYaYaY#Dbl#D#Da9a9.7.7a9a9a9.7#Da9#sa9bl#sbl.sbl.NblawaYbn#Ubn#Ibn.C#Ubn#x#U#x#I#x#IbfaYaw.NaY.N.saYboaYaCam.y#u#aau#4aH.4#..4aHbrbw#0.2bw.2aT.2ay.YaH#4#zal.o#T#Tal.U#aar.G.Ga4aPa4a4.ya#aZ.ya#a#a#aOa0bnaCbnaCbn#I#xblaYaY.s#D#sa9#Da9.na9a9a9.na9a9#D#D#D#D#s#D#s#D#D#s#D#D.n.7.E.7.n.7#La9#La9.E#Laf#La9#L.7#L.7afaj#L#La9a9.n#D.7bl#D#DaY.NaY#x#xbn#x.R#xaYaYaY#DaY#Dbl#D#D#DaYaYaYaYaY#D#Da9a9a9", +"#L#Laf#L#L#L#L#La2#ga2#g#ga2#g#La2a2#ga2#ga2#L#L#L.E#L.7.n.7a9#D#D#I#xaoby.w#zaSa0aCa0bn#x.Rblblbl#D#D#D#D.7a9.Ea9.7a9a9.n.7a9a9#sbl#DblaYaw#x#x#xa0#xa0a0a0aCa0#I#U#x#I#x#I#xawaY#x#I.Nawbf#x#IaCbgaBaza6aT#P.uaybaay#3#aar.Gazaz.Gazaz.Gar#aa6.w#u#uaBaZaB#uazazazaS.0#S.0aFa#am.5aoa0am.Wam.C#I#x#x#I#x#I#xaw.N.N#s.N.N#Dbj#s#D#D.7.7.7#D#s.7a9.Ea9a9a9a9a9a9#s#p.na9bj#Dbjbj#Lajafaj#L#L#Laf.E#L#L#L#Laj#L#Laf#Laf.7a9bja9#D#D#DawaY#x.s#xaY#x#x#x#IaYaYawaYbl#D#D#DblaY#s#DaYaYaw#D#Daf.7af", +"#L.7#L#L#L#L#L#L#L#gbpa2bp#g#L#La2#ga2a2#g#L#L#L#L#L.7a9#L.7#D#saY#x.C.8#va7albh.Ca0a0bnaY.RblblaY#Dbla9#Da9.7.7a9a9a9a9a9#D.n#Dbl#Dblaw#DaY#x#IbnbnaCa0#Ua0aCa0.CaC#x#I#x#I#Ibf#x#I#x#I#x#Ibo.C.paOa7#aay.K.K.K#Ear.faZa7#uaBaB#vbmaBaZa7an.TaZaOaF.FaFaOb#b##SaZ#va#aOama0.W#xavam.C.W.C#xaw#x#x#Ibfbf#xbf.N.N.saYaY#D.N.E#D.7a9#D#s.7#s#D#D#sa9.7a9.7.E.7.Ea9#s#D#s#D#s#D.Ea9.Eaf.E#Lajafaj#L.7#L.n.7#La9#L.E#Laf#L.na9#D.7a9#Dbl.NaY.NaY#x#x#x#U#x.RaYaYaYaY.N#xbl#D#D#D#DblaYaYaYbl#Da9a9.7", +"#L.3a2a2a2a2asa2#ga2a2#ga2a2#ga2#ga2#ga2a2#ga2#L#L#Laj#L#L.7b..7#x#I#x#xaC#uar#e#Sa0.CaYaY#DaYaYa9#p#pa9a9a9a9a9#s#D#sbj#D#D#D#D#saYaY.Naw#x#x.Ca0aoa0a0aCbn#Ibnaw#U#U.CaCamaCaCaw#Mbn#UbnaCbgaoaZanaral.2alaPan.y.0.yaB.0a#a#a#.8aF#v.0#u.0#v.5aCam.8amaOamaoam.F.tbg#x.C.C#xaY.NaY.saY.Nawbf.N.N.N#D.s#D.N#D.Nbl#sbl#s#D#D#D.7.Ea9.7a9.7a9.7.7a9#s#D#D#Da9#D#D.na9.na9.na9a9.na9a9a9.naf#Lafaf.E#L.7#L#L#L#L#Lafaj#L#L#La9.na9bl#MblaYaY.baYaYbl#Dbl#DaYawaYaY#M#D#DaY#Dbl#D#DaYblbl#D#p#Dafa9", +"afa2#La2a2#gaa#ga2a2bpa2#L#g#L#ga2a2#g#L#g#La2#g#L#L#Lbpaj#D.7bjaY.N.N#Iao#u#aayaFa0bnaYaYblaYaY#pa9a9blbl#D#M#D#Da9#Da9#Da9#s#Dbl#D#MaY#x#x#x.Wama0a0aCa0a0amao#Uaobg.8am.8amama0bgb#.8aFa#.0aZ#ua7#uaS#uanaBa#.8aFaOamaOamaCamb#ao.5a#.0#vaF.5a0a0aC.Ca0.Wa0am#ybgaC#xbf#I.NawaY.NaY.saY.NaYaw#D.s.N.N.N.s.N.sbl#sbl#D#D#D.n#D.7a9.7.n.7.n.7.n#D#D#s#D#s#Da9#Daja9a9.nafa9aja9aja9aja9af#L.n#L.7af.Eaf.E#L.7#Laf#Lafaf#La9.7a9blblblawaYaY.baY#Mbl#DaYaYaYaYaY.NaY#Dbl#s#Dbl#D#MaYa9bl#D#Da9a9", +"afaf#La2a2a2#ga2#ga2a2#ga2a2#ga2bpa2a2#ga2#ga2#g#L#g#L#L#Lbj.Ebjaw#D.s#xaoana6abaOam#xaYaY#DaY.N#pa9#p#sbl#Dbl#D.n#D.na9.na9a9a9#sbl#DaY#I#x.Wbnb#bgb#amamao.8aFamaO.yaZ#u#u#S#vaZan.yaZaZ.6aSa4aBaZbma#aF.5ama0aCa0.CaCa0a0a0.Wbna0a0aoam.5aoa0#I#x#xbn#I#x#x#x.p.Vbn#x#I.NaYbl.N.NaY.N.NaY.N.NaYaY#DawblaY#DaYblaYblawaY.s#D#D.na9a9a9a9a9a9a9a9#D#D#Da9a9bja9a9.nafa9.Ea9a9.na9.na9.n#Lajaf#L.n#L.7#L#L#Laj#Lajaf#L#Laja9a9a9blblblaYaYaYaYaYbl#D#MblaYaYaYaYbl#saY#D#D#D.NaYblaYbl#D#p#Dafa9", +"afajaf#La2a2a2a2a2#g#L#g#L#g#La2#ga2bpa2#La2bpa2aj#Lbp#Lajbj.7#s#D#Daw.C#v.GaTaD#vb#a0bnawaYaYaYaYblaYaYaYawaYaw#D#D#D#D#D#D#s#Dbl#saYaw#xa0a0a0bgamaOamaOa#a#a#.yan#u.G.Gaz.w.w#u#uan#uan.w.6.GaFaOaFaoaobn#I#x#I#x#I#x#x#I#xaY#x#I#xbn.CaC.Ca0#x#x#IaY#xawaYaw.R.bbnawblaYaw#DaY.saY.Naw.N#M.N#D#s#DaY.N.saY.NawaYaw#Dbl#DaYaY#D#s#D#s#D#s#Db.a9#D#s#D#s#D.n#Daf#L.na9aja9aja9afa9aja9afaf.7af.7#La9aj.7a9#L.7afaj#Laf#La9a9a9.na9blblaYawaYaYblbl#Dbl.saYaYawblaY#D#Dbl#DblblaYblbl#Dbl#Da9a9", +"a9a9#L#L#L#L.jbpa2a2aja2#ga2#ga2#L#ga2#ga2#ga2#L#g#L#L#L#Lbj#s#D#saw#Iaq.y#3aH#Pa#bga0#UaYaY#xaYaYawaYaYaY#x.N#x.Naw.Naw.N.NaY.s#DblawbnaCamb#bgaFbma##S.0aB#u.yaz.w.waz.w#u.0a##SaFbma##Sa##Sa#amamaoa0#x#IaYawaYblawaYawaY#M.NaYaYawaY#I#x#x#U#x#x#xawaYaY#D#MaY#x.b#x#UaYaY#Daw#DaY#D#D#D#D#Dbl#Dbl#sblblbl#MaY.RaYaYawaY.s.Nbl#Dbl#D#Dbl#Dbl#D#s#D#D#D.7#D#Dajaf#La9.na9a9.na9.na9a9.n#Lajaf.E#L.7#La9aj.7#Lafaf#Laf#La9.Ea9a9#p.nblblaYaYaY#Dblbl.NblaYaYaY.Nbl#D#D#D#DaY#DaYblblbla9#Dafa9", +"a9afa9ajafbpa2#L#ga2bpa2#L#g#La2bpa2a2bpa2#L#ga2#L#Lbp.7aj.7#Db.bl#x.Waobb.2a6ak#vb#a0#x.RaY#xaYaYaY.R#x#x#x#I#xawaYaYaYaY#xaw#xaYaw.Ca0b#aF#vaZaZana7.waz.G.Ga7#uaBaB.0a#aFamambnbnaCa0a0aCa0a0aoa0#IaYaw.Nbl.NaY#MaYbl#DblaY#DawaY.Nblbl#xbn.Ca0#I#xaY.N#Mbl#DawaY#Ibn#Ubn#I#x#D#D#D#D#D#D#s#D#D#saY#Dbl.s#DaYblaYaYawaYaYaYblbl.nbl.nbl.nbl.n#D#D#D#s#D#D#s#D#Lafaja9#paja9aja9af.naf.naf#Laf.7aja9aj.7#Laf.7afajaf#Laja9a9a9afa9#Dbl#sbl.Nblbl#sblaYaYaYaYaY#DaYaY#Dbl#DaYblaY#MaY#Dbl#Da9a9", +"a9a9afa9#L#L#La2#ga2#La2#ga2a2#ga2#ga2a2#ga2a2bp#L.j#L#L.7#sbj#saY#Iaq.y.waXaraS#vb#a0#UaYaYawaYaYaYbn#x#U.Cbn.Caqaqavaqavaqaqaq#Ia0ao.5#vana7bh.Ga6al#aarbkaz#uaOamam.Cao#x#IaY#I#x#I#x#I#x#xawbn#xaw#D#D#D.sbfaY.N.saY.saY#D#D.Naw.N#saY.s.Cava0am.C#IaYaY#D#M.N#x.bbnaCa0a0#x#s#D#s#D#Da9#Da9blblbl#Mblblbl#MaYawblaYaYawaY.saYaYaYaYblblblbl#s#D#D#D#D#s#D#Daja9af.nafa9.na9.na9a9.na9#Lajaf.7af.7#L.n#L.E#Laf#L#Laf#La9a9.7a9a9a9a9#D#D#M#Dbl#Dblaw#DaYawaYaY#saYbl.Naw#DaYawblaYblbla9a9af", +"afa9.7a9#L#L#L#L#La2#g#La2bpa2bpa2#L#g#L#g#L#ga2#Lbp#Laj.7bj.s#D.Waoao.waX#aazaSaFa0#xaYaYaYaYaYaYaY#xa0a0.Caoa0.8.8.5ao.5amaoamaCaoam#v#ubh.G#eayaTay.Gaza7aBa#aoaC.CaC.CaYaY#Mbf#x#xaY#xawaYaY.NaYaw#D#s.N#xaNaw.Nbl.Nbl.N.N#s#x.NaY#D.NaY#xaqa0aoa0#x.NaY#MaY#x#xbnbn.Vamaoam#D#D#D#s#D#sbja9.N#M.Nbl.N#M.NblblaY.RawaYaYaYaYblawblaYawaYawaY#D#s#D#M#D#D#D#Daf#L#La9a9.naf#La9af.n#L.nafafa9aj.7aj.7#L.7#L.Eafaj#Laf#La9a9a9aja9a9.na9bl#D#D#DblblaYaYaYaYaYaY#DaY#DaYblbl#DaYaYbl#sbl#Da9a9", +".7a9a9.7a9a9.7a9#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#L#Lafa9a9#D#sbl.s.Waoan.G#Ea7aBaZ#vaFama0aCamamamb#.Va0aC.VaO.0#uaSaSazazan.Gak#a.Iay.Iar.Xar.Gazaz#uaB.yaO.5aoa0#Iaw.NaY.saY.N.N#D#s#D.N.N.N.N.s.NaY.NaY.NaY.saYa9bl#sbl#sbl.nbl#D#s#DawaY.saYawaY#x#U.CaC#xbf.N.s#I#x#Ia0aoamambf#I.N#D#DaYaY#Dbl#D#Dbl#D#Dbl#D#M#Dbl#Daw#D#M#DaYaYawaYblblaY#D.na9a9.na9.najaf.nafajaj#L#L#Laj#L.E#L.n#L.E#Lajaf#Laja9aja9.7a9#Lafafaj#L#Lajafa9a9a9bja9#D#D#sblaY#MaYaYaYaYaYaYaYawaYaYaY#xaY#UaYaYbl#Dafa9#L", +"a9bja9a9.7a9a9.7#L#L#L#L#L#L#L#L.E#L#L#L#L#L#L.7aj#L#sa9#saY.saYbo.5.w.GazaB#San.l#vbgama0#xama0ama0a0bgaFbmanazak#aar#eazaz#aa6.e.e.XaraSazbhan#S#v#vaFaoa0aC.Cawaw.Naw.Naw.Naw#Da9#s#D.s.N.s.N.NaY.s.Naw.NaY.Nbl#saYblbl#Dbl#D#D#DaY#D.NaY.N#x#Ibna0a0a0.C#I#x#x#I#xaCamaFaOamaYaYaYaY.N.Nawbl#s#Dbl#D#sbl#D#Dbl#Daw#Dbl#Dbl#D#Mblblblaw#Dawbl.na9.na9.na9a9.naf.n#L.7aj#Laj#Laja9aj.7aja9aj.7#L.Eaf.7#L.7af.7afaj#L#Laf#Laf#La9.7a9a9b.a9#D#DaYblaYaYblaYaYaw.RaYbnaY#U#xbnbna0aYaYaYbl#Da9a9", +"a9a9a9a9a9a9a9a9#L#L#L#L#L#Laf#Laf#Laf#L#Laf#Lafa9a9a9#D#D.Naw.N#x.8.w#e.lbma#az#uaZaFa0aC#x#x#x#x.WamamaF.y#ealayaG.G#eanaS#e#a.I#a.X.JanaZ#Sa#aOambga0.W#x#x.saY#saY.NaY.NaY.N#D#D#DaY.NaYaY#xawaYaYaYaYaY.saY#Dbl.N#M.Nawbl#D#M#D#MaYawaY#x#xbnaCam.8.5amamaCa0a0aob#aOaObm#v#x#I#x#xaY.N.NaY#Dbl#Dbl#D#Dbl#D#Dbl#Dbl#Dbl.sbl.N#Daw.NblaYblaYa9.n#p#sbl#Ma9bl.na9.na9.7.E.7.7.na9.na9a9.Ea9.n.7aja9.na9.Ea9.7af.7af#Laf#L#Lafa9a9a9#Da9#D#D#DblaYblaYawaYaY.R#xawaYaYaYbn.Cbn#xaYaYaY#D#D#D#D", +"a9a9a9a9a9.7a9a9a9a9a9#Laf#L#L#La9.7.na9a9a9a9a9a9a9#s#D#s#D.Nbl#I#v.G.G#uaF#van#uaZ.8a0bnbnawbnavam.5#van#ealbra6#a#e.wana7#e#e.fakaz.TaBa#a#aFa0aoa0.Wbn.s#M.N#saY.sbl.saY.saY#s.Naw.Naw.N#I.N#x#I#x#x#IaYaY#IaYawaYawaYaY#xawaYaYaY.NaY#x#x#Iamb#aFa#a#aOamamamaob#b#aF#Sbmbmaoa0#x#xawbl#D#D#Dbl#D#sbl#Dbl#sbl#D#D#sbl#D#D#D#Mbl#DawblaY#saY#Mbl#Dbl#M#D#M#M#Da9#sa9.n#D#D#sa9.Ea9b..na9.7a9.na9.n.7.7a9.7a9aj#Lafaj#Lafaj#La9.Ea9.7#D.E#D#DblaY#MaYaYaYaYaYaY.R#x.R#xbn#U#xbnbnaYaYbl#Dbl#D", +"a9a9a9a9afa9afa9af.nafaf#Lafa9a9afa9a9a9a9.na9.n#D#D#D#D#D#Daw.N#I.y.GazaZb#aOa#anaBa#aoa0aCbna0a0.5.8an.G.2.K#P#q#e.6anan.wazakazbha7aZaFam.8am#xaC.C#I#IaY#D#saY#saY.NaY.NaY.NblaYblaYaY#I#x#x#x#x#I#x#x#x#xaYaYbn#xbn#U#x.baY#x.s#x#x#I.Ca0.CbgaF#vbma#a#aOambgamb#aoaFaFaOaF#va0#x#I#x.Na9#D#s#Dbl#D#Dbl#D#Dbl#Dbl#D#Dbl#Dbl#DaYblaY#Dawbl#DaYaY#MaYawaYawaY.nbl#p#sa9#sa9#D#s#D#Da9#D.n#D.na9.na9a9.n#Da9#D#Lajaf#Laf#Laf#La9a9a9#Da9#Da9#DaYblaYaYblaYawbnawaYaYaYaYbn.Cbna0.Cbn#xaYaY#Da9", +"#pa9a9a9a9a9a9a9a9a9a9a9a9a9a9.na9a9a9a9a9a9#Da9#D#s#D#s#DaY.NaYaCaZ.6az.0aOaF#van#uan#vamamamamaOa#analba.g#P#P#a#Tan.y#uaZaza7an.laZa#bgama0.C#U.C#U#I.N#s#s#D#s.Naw.N#M.NaY.saYaw.Naw#x#x#x#U#x.baYbnaw#xawaY#Ubn#U#x#Ubn#xbn#xbn#Ia0a0a0aCa0b#.t.tbma#aFaFb#amamamam.Vb#b#.V#Sbga0#x#xbl#D#Dbl#Dbl#Dbl#s#Dbl#D#M#D#Dbl#sbl#Dblaw#DawblaY#DaYawaYaYaY#Ibn#Ibn#Mbl#s#D#D#Db.#D#sa9#s#s#s#D#s#D.n#D.na9#D#D#s#Dafafaf#L#Laf#L#La9a9.7.nbja9bj#DblawblaYaYaYaYaYaYaY#x.R#x#xbnbnbnawaYaYbl#Da9a9", +"a9a9#pa9#pa9#pa9a9a9a9a9a9a9#pa9a9.n#p.nbl.n#pa9#D#D#D#D#D.Nawbfbn#vazaS#SaF.8#vaZ.6aBa##va##v.0a7.faG#PaD#V.Kay.XazanaB.0#vbm#SbmaZ#vamama0aC#xa0.W#x#x#I.N#D#s.N#M.NaY.NaY.saYaYaYaYaYawbn#x#x#x#xbn#Ibn#x#x#xbn#xa0bna0bnaCbn#xa0#x#xbn.Ca0am.V.Vb#aOaFb#bgamaC.C.CaCa0a0aCa0a#aFbgbnaY.N#D.7#D#M#D#Dbl#Dbl#D#D#Dbl#D#Dbl#D#D#M.NblaY#DawblaYaY#Ibn#Ibn#Ubn#IaYawaYawaYawaY.s#D#s#Da9#sa9#s#D#sa9#Dbl#s#D#D#Daj#L#Lafaj#Lafaja9a9a9#Da9#D#Da9blaYblaYawaY.R#xaY#M.RaYawbna0#IaYbl#Da9a9afafa2", +"#pafa9afa9a9a9a9#pa9#pa9afa9a9a9#p#p#D#pbl#p.na9#D#D#D#DaY.NaY#Ia0#v.Gaz.0#vaF#vanaz.w#u.0#u.waP#A.f.Xa6.Ia6akaSanaZa#aFaoaFaOaF#SaFaFama0aC#x#x.Wa0.W#Ibf.N#sbj#M.N.saY#s.NaY.NaYaYaw#xaY#x#I#x.R#x#x#x#xaYbnaY.Cbnbn#xbn#x#xbn#x#I#xbn#xa0.Ca0.pb#b#aFb#aFb#.V.C.C#x.CaCa0#xa0.FaFaOa0aYbl#D#sbl#D#Dbl#Dbl#s#Dbl#D#M#Dbl#D#M.Nbl#DaYblawaY.saY#UaYbn#x#U#x#Ubnaw.Rawblaw.NawaY#s#s#s#s#D#s#D#sbl#Mbl.n#Dblbl#Dafaj#Laf#Laf#L#La9.7a9.7#s.7#DbjblaYblaYaYaYaYaYblaY#xaY#x#xbnaYbla9#p#p.naf#La2", +"#L#La9a9a9afa9af.j#L#La2af#La9a9#sa9#s#D#DaYaYblawaYaY#I#xbn.Ca0#Ubg.laz#uaBanaBa6#a.Xa6#aak#ebh#Sbm.Fa#aFb#amaoa0aCa0aoa0amb#.8b#aoa0aCa0#xaC#x#I#xaY.N#M#D#D#s#D#sa9.7a9.7.n.7#D#D#D#s#DaYaYaY#sbl#Mbl#Dbl#D#Dawbl.Naw.NaYaYawaYaYaYaw#DaYbl#DaY.RaYaYbnbna0a0#Ubnbn#x#x#x#I#xa0bgaBb#a0.s.s#L.NaY.N.saY.N.NaYbl.NblaY#I#x#x#x#Mbl#MaYaY#x.b#x#xbn.Wambgamamam#Ua0bnaCa0a0amaoaw#x#x#x#I#Iaw#Mblbl#sblbl#D#D#Da9#pa9a9a9a9#Laf.na9a9a9a9#paf#pa9a9#MaYaY#x#xbnaw.RaYbna0a0a0aY#D#pa9a9#La9#L#L", +"#L.7#Laf.7a9.7a9#Laf#Laf#La9.7#Da9a9blbl.Nbl#DaY#xaYaY#xaCa0amam.t#uazar#e#T#a#zacbaayaraS#uaZa#aFaFaFb#amaoama0a0a0aCa0a0ama0amaoa0a0a0aC#xaC#xbn#I.saY.s#D#sa9a9#sa9a9.Ea9.7a9#D#s#DaY#D#D#s.Nbl#D#D#D#D#Dbl#DaY#DaY#Dblbl#DaY#D#Dbl#DaYbl.NaY.baYaYaYa0#Ia0a0#x#UaY#x#U#x#xaYbnam.FaOa0#x.s.7aY.saY.NaY.NaY.sblawaY.N#x#Ibn#xaYawaY#xawbnaY#U#x#IaCa0aCbg.paobn#U#Ua0aCaCaCb#aCaC.C.Wa0.C.baYawawaYblaw#D.s.Nbla9#p.nafa9ajafa9#pa9#pafa9a9a9#pa9blaYaY.b#xaYaYawa0#xa0a0#UaYbla9a9a9a9#L.7#L", +"#Laf#La9.7af.7af#L#Laja9.7a9a9bj#D#D#D#MaY.NaYaY#MaY#Ua0amam.5.5aSal#PabbrayaTaTaGara7aZaZaZbm#vb#amamaCa0#x.C#x#I#x#x.CaC.CaC.5b#aob#aCamaC#xbn#I#xaY.s#D#sa9#s#Da9.Ea9.7a9.Ea9#D#D#D#D#s#D#D#D#Dbl#D#M#Dbl#sbl#DaYblaY.saY#DaY#MaY.Nbl.sbl#D#DaYaY.baYaYbn.CbnbnaYaYbn#x#x#x#xaYbnam#Sama0.N#s.NaY.Naw.Naw.NaY.NblaYaw#x#x#x#IaYaYawbl#x#I#xa0#Ia0aC.pbgb#bgb#.pa0.V.pb#.Vb#bgbm.taOaFaFao#U#x.bbn#IaYaYaY.NaYbl#Dbl#Da9a9a9a9a9a9a9a9a9a9.na9a9a9bl#DblaY#x#xaY.R#xaCama0#x#xbl#s#Daf.7af.7#L", +"#L#L.7a9.7a9a9.7af#La9a9a9#D#D#D#D#MaYaY.N#x#I#x#xaY#x#xamaO.0bbaT#PaD#VaTaRar#eaBaZbmaFaFamb#ama0aCama0.C.C#x#I#xaY#I#x#x.W.CaCaOaFaob#aoamaC.C#I.b.NaY#s#Da9.7.n.7a9.7.n.7a9.7#D#D#D#D#D#D#D#D#D#M#D#Dbl#D#Dbl#D#D#sbl#Dbl#D#D#D#D#Dbl#D#Dbl#DaYaYaYbn#x#x#x#IaYbnaY#IaY#xaY#IaYbna0aBbmao#x.NaY.saY.NaY.NaY.saYaw.NaY#x#I#x#xaw#x.N#I.C.CavaCaFaOa#aBa##vbm#Sbm.taFbmbmaZaBbh#kbhbhaZ#Sa#b#a0aCa0a0#U#xaYaw.Nbl#Mbl.n#D.n.7a9a9.na9a9#sa9#Da9a9a9.n#D#D#xaY#xawaYbnama0ambnaYblbl#Da9#Da9#L.7", +"a9a9a9afa9#La9a9.na9a9bj.n#D#D#saY.NaY#x#x#x#x#x#Ubnambga#.0#u#uaH#4#aazanaBaZbm#SaFaOb#bgamamama0.C.C.W.C#Ibf#xbf#I#x#x.C.Cao.8a#aOaOamaoa0.Wa0aY#xaw.N#D#s.7a9.7.n.7a9.7#L.7aj#D#D#s#D#D#D#s#D#D#Dbl#D#Dbl#D#Dbl#D#D#Dbl#D#Dbl#D#Dbl#D#D#D#DblaY.NaYawaY#xbn#xaYaYaYbn#x#x#x#x#U#xamaBaBaBa0.Caw#xaY#IaY#xaY#x#x#x#Ibn#xa0.Wa0.CaoamamaCamao.5azaz.G.Gar#e.G#a#eaz#ear#e#a.X#a#jaGak.faSaZ#vb#ambga0a0a0#I#x#xaw#xblaY#Da9#Da9#D#D#Da9#Da9#Da9.na9a9#D#DblaY#x.Rbna0.Cama0#x#xbl#Dbla9#D.7.7a9", +"a9.7a9.7a9.na9.7a9.7#s#D#D#D#D.N#x#x#x#I#x#x.Ca0amaOa#.yanaBan#u.6aBa#amb#a0b#amamb#amamamaoa0aoa0aCambn.C.C#x#Ia0.C.CaCamao.5aO#vaFaOb#aoa0a0.WaYaw.NaY#s#D.7.n.7a9.7.n.7a9.7a9#D#D#D#D#D#D#D#Dbl#D#Dbl#D#Dbl#D#D#Dbl#D#D#D#D#Dbl#D#D#D#Dbl#D#D#sbl#D.NaYaYaY#xaYaYaY#xaYaYaY#xaYa0a0bmaz#uaOam.C.W.C.C.C.C.W#x.W#xamamamaoam.5aoaF#v.y.0#uaB.wal.2ayal.2aya6aTa6alaR.2ayayaT#P#t.K.e.X.GaSaZaBaFb#amaoa0a0bna0aYaYawblbl#sa9bj.n.7#D.7a9bja9#Dafa9afa9bl.Naw.N#U.CaCaFaoamama0aYaY#D#D#Da9#L.7", +"a9a9.na9.7a9a9a9a9#D#D.N#s#DaY.saY#x.C.Ca0aoamao.0aZaBaZaB.0aBa#amb#a0aCaC.pa0a0aob#ama0am.C.Ca0.5b#amaCam.W.C.CaCa0ao.5amaOaF#vaF.8amamama0aqa0aYaw.Naw#D#Da9.7.n.7a9.7.7af.E#L#Da9#Da9#Da9#Da9#Da9#Da9#Da9#Da9a9a9afa9afa9afa9a9a9a9a9a9a9a9a9bl#D#Dbl.N.NaYaYaY.RawbnaY#x#I#xawa0b##Sazbha##vamaqao.Cavamao.5ao.5.8.8aF#v.0.yaZaB.waza7az.G.G#aararar.X#a.Xar#eazazaralalalayayaya6.Ial.XaSaS#va#aFaO.5aC.CaC#xbnaY.N#M#D#D#D.7a9.7.Ea9.7.7.Eaf#La9#D#D.N.NaYbnbnamamb#aoama0aYawblaY#D#D#D.7", +".7a9.7a9a9a9.Ea9bja9#s.NaYaw.NaYa0.Wa0aCamamao.5a7az.waZa#aFaFaFamamaC#xbn#xam.5amamamaoama0aoa0aOaFaoambgamaCam.8aFaOaFaOaFaF#vaFaFaOb#aoamaCamawaY.Naw#D#D.Ea9.7a9.7.n.7.7a9.7#D#D#D#D#D#D#D#D#D#Dbl#D#Mbl#D#Ma9a9a9a9a9a9a9a9.na9a9.na9a9.na9#D#D#D#DblaY.saYaYaYaY#xaY#xaY#xaYbnaObmazaZ#Sa#.8.8.8.5am.8.5.8a##va#.ybbbb.w#uazarar#a#eazaSaz#ua7aZaZaZaZ.Tbm#SbmbmaZan#uaSaz#aalaR.2.IaGaraSaZaBa#aFaoama0aC.R#IawaYbl#D#D#Da9.7.7a9.7.7a9.7af#L.na9#D#s.N.NaYaCamaoaFamama0aYaYaY#D#D#Dbj#D", +".N.N.N.N#D#D#D#DawaY.Nbf#xaqaqavamamaF#v.0#u.w#e#va#b#.5amamamaF#I#x#x#x#Ia0#x#x#x#I#x#xa0ao.5amamaoaFa#a#aBaZaZ.TaBaZ#SaFaFaF.5ao.5aoam.C.W#x#xaYaY.saY.N#s#D#Dajafaja9a9a9.7a9#Da9bja9#D.7#Da9#Dbl#Dbl#D#Dbl#D#Da9.7a9.7a9a9bja9#Da9#D#D#Dbl.Nbl#Dbl#D#D#Dbl.NaYaYaYaYaYawaYaY.Nbfa0b#bmaBana#bma#bm#u.6#T.oaR.Gararal#aalalal#Taraz.6#uan.0.0b#.8b#aob#aoambgamam.8aoamaO.8aFaBbhaz.Gar.X.X#abhazan.TaZbmbma#aCa0#xaYbfaY#s#D.s.N#D#D#sa9.7.7#s.7.7.7a9a9#D.7#DaYam.5aOa#amambf.N.N#s#D.NaYbf", +"aYaYaY.saY#s#D#D#D.s#x.Wao.8aq.5.yaB#uanaBan#uanaFaOamaob#aoamaobn#x#U.Ca0.C.C.Wbna0a0aoaF.5#va#.ya#.yaBaZaBbh#u#SaBaZaOa#.8aFbg.5aoamaobn.Cbn#x.sbl.NaY#D#Da9#Daf#L#La9.7a9a9.7#D#D#D#D#D#D#D#Dbl#Dbl#DaY#DaY#D#Da9a9.7a9#D.7a9a9a9a9#Dbl#D#D#D#D#D#D#D#D#D#D#DaYaYaYaYaYaYaYaY.N#x#xbgaFaZ#ua#bgaF#vanaz#ealalazazaz.Garaz#q#ebhananaZaZa#a#a#aCama0a0aoa0ama0aqaoamamaFaoam.8a##SaZ#uana7aSbhaBaZaZbmaOaFaOaFb#ambnbn#IaY.NaY#D#D#D#D.7.7b..7#D#Da9.7#s#D.n#D#MaY#Iama#aFaoa0#x.saY#D#Dbl.N#x", +".Nbo.N.N#xbf#xbf#x#Ia0a0aOa#aBaz.GaP.wan.ya#a#a#aCamambgama0a0a0.Wa0.C#xa0a0a0amamaoaFama#a#.0#vaSazbh#uanaBanaZa#aOaFaO.5aOaqamaoama0.C.C#Ibn#IaYaYaw#D#s#D.E.7#Laf#La9a9.7a9a9.7a9.7a9.7a9.7a9#D#D#D#D#Dbl#D#Da9.7#Da9.7a9.7#Da9.na9a9#D#Dbl#Dbl#Dbl#Dbl#D#D#p#D#D#D#D#D#D#D#D.N#DaYa0b##SaBaZamamaF#v.0#u.6.wan#u#uaSananaZaBa##vaFaFaoamamama0a0aCa0bna0#xaCa0a0.Cao.CaoamaoaF.5aOaFaFa#aFaFaF.5aoamaFamaFaob#bga0aobnbn#x#x#M#Dbl#s#Da9.7a9.s#D#D#D.N#DaY.N#Daw#xa0aoaF.5b##IaYaY#DawaYaw#x", +".N.N#Ibf#x.W.C.W.5#v.yaZ.G#z.Kba.o#e.w.0a#a##va#amamaOaFaOaFbgamama0amaoam.8.5.5a#aFaFa#aBan#ubh#a.Xar.Gbh#uaZaBaO.5aoamamaC.C.Wa0a0.W.C#I#x#x#xaY#saY#D#D.7af.7af#L#La9a9.7#D.7#Da9.7a9.7a9bja9a9a9a9a9a9a9a9afa9.7a9.7#L.7a9afa9a9a9a9a9#Da9#D#Dbl#D#D#D#p#D#D#D#D#Dbl#Dbl#Dbl.s.NaY#xa0a#aB.0amamamaFa#a#a#a#aBaZaZaZ#va#.0a#b#b#bgamambn.Cbn.Wa0.C.C.C.Wa0.C.C.C.Wa0.Ca0.Ca0aoamama0a0bn#Ubn.Wa0.Ca0.W.C#U#xb#.Vb#b#a0ama0a0aYaY#D#D#D#s#D#saYaY.s.NaYaw.NawaYaY#Ia0amamaOam.C#x#xaYaw#x#x.C", +".C.W.Caqaq.5.5.5anaP.o.Ya8#obs.g#TaS.wan.0#va##v.0bm.0a#.0a#a#.yamaoaFamaOa#aOa##va##S.0aZ#uaSaz#aaG#a.Gaz#uan#u#vaOam.8aCaq.W.C.C.Wa0#x#x#x#IaYawbl#D#sa9a9#L#Lajaf#L.na9a9.7a9.7a9#D.7#Da9.7a9a9a9af.7afa9.7a9.7af#L#Laf#La9.7afafa9.na9a9bl#Da9.na9a9a9a9a9afa9.na9a9.7a9a9a9.N#D.N#M#xaOaZaBamaOam.8am.8a#.5a##va#aoaFaFamamaoa0a0bnaC#x#x#x#x#I#xaY#xaY#xaY#I#x#x#x#I#x#I#xa0bn#I#xawbl.Nbl.Naw.NaY.NaY#xaYaCa0ao.Vbgb#b#b#awbnaYaYblblaYbl.NawblaY.NaYaYaYawaY#x#Ia0bga#aOamaC.C#xa0.Wa0am", +"aoaFa#aOa##v.y.ya4.2#4.4a8aDaTaRanananaZaBaFaFaF#v.0#v.0#v.0#v.0amb#aob#amam.5aFamaOaFa##v.0.yaZaz.wanazaz.w.w.waO#vao.5aoamaCam.Wa0#x#xaw#xaYaY#D#M#Da9a9.E#L#L#L#Laf.7a9.7#Da9.7a9#L#L#L#L.7#L#L#L#L#L#L#L#La2#La2#L#L#L#L#L#Lafajafafa9a9a9afa9a9a9a9a9afa9a9a9.7a9.7a9a9.7a9.N#D#D#DaYam#SaZaF.5aFamamamamaoaFamamb#amamaoa0a0bnaC#x#x#xaY#IaYaYaYaYaYaYaYaY#xaY#IaYaYaYaYaY.s#xaY#D#D#D.7.n#D#D#D#M#D.N.saY#xa0a0amamambgambnbn#UaY#x#xaY.saY#x.NaYaw#x#I#x#x#I#xa0a0aF#vaZ.5a#amaCa0am#v.5", +"an#uan#uan#ua7#uaz#a.Gaz.GaSaZaZ#vbybca#.5aoamb#.5b#amb#amb#amb#aCama0amamaob#amaCa0a0aoaFaFa#byaOby#v.yaZaB#u#ua##v#S#v.5ao.5aoa0#I#xaY#x#IaYaw#Dbla9#s#L#L#La9#Laf#La9#La9.7a9#L#L.7af.7af#Laf#L#L#L#L#L#L#L#Laf#Lafa2af#L.3#Lafafafafa9afa9a9#Laf#Laf#L#Laf#L#L#L#L#L#L#L#L#L.s#D#s.7#DaCa##ua#.0.5.5amama0a0amaoamaCamaCa0#xbn#x#x#x#xawbfaY.N.N.N.s.N.N.s.Nbl.Nbl.NaY.NaY.Nbl#D#D#s.7.7#D.7a9.n#p#Dbl#DblaY#x#x#xbnbnama0am.Vama0b#aCa0#x#xbn#I#x#x#xbnbn#x.Ca0a0aCam#van.wan#vbyaF#va#.yan", +"alal.Ga7bhaZaZaZa##Sa#aFb#ao.5.8aFaFamama0amamaobn#Ubn#Ua0#Ibn#Ua0a0a0aCa0amamao#x#xaCa0aoamao.5avam.8.8#v.yaB#u#SaBaB#u#S#vaO.8amaCbn#x#I#xawaYbl#sa9a9#La9.7ajafaj#La9#L.7#Da9.7#Laf#L#L#L#L.7a2#ga2a2a2a2a2a2#La2#L#La2#L#L#La2af#Laf.na9a9a9af#Laf#La9af.7af#L#L#L#L#Laj#L#L#D#D.7#s#D.CaBbhbb.y.0aOama0aoa0ama0ama0bnbn#xaYaCbnbn#x#xaYaY.Naw.NaY.NaY.NaY.NaY#DaY#M#Dbl#M#D#Da9.7a9#Dbjb..7afa9.na9bl#DaY.N#Ibf.W#xaC.Ca0amamb#b#a0ama0ama0#xbn#x#U#x#U.C#UamaCama0ao.0.w.6.wan.yan.yan.waP", +"#q.6a#aF.5aCa0a0bnbna0aCa0amb#am#U.Vbnbn#xa0.C#x#x.NaY.NaY.N.N.N#D#s.NaY.NawaY.N#M.s.N#x.C.Wamaq#UaCaCb#bgaOa##vbg#v#v#u.w#uaZ.yaO.5aoama0.RaYaw#D#D.7.n#Laj#L#L#L#La2#La2#La2#g#Laf#L#L#L#La2#La2#L#La2#La2#L#La2af#L.3#Laf#Lafajaf#La2#La2#La2#L#L#Laf#La2#L#L#L#La2#L#Laf#L#La2#La9#D#x#xaoaO.Xbha#ama0#x#x.CaC.Ca0aC.C#x#IbnaYaYawaYaYaYaYaY.N#D#D#D#D#D#D#D#D#D#D#D#D#D#D#D.7.E.7.7.7af.7.7aj#L#L.7.E.N.N.NaY.N.N.N.NaY.NaYbl#IaYbna0aoaFaOamaoamamamaFaF.5b#aOa#a#aZ#u#a.2.waP.w.w.waZan#u", +".GanaB.5a0a0#xaCbn#Ibna0a0a0amam.Va0bnbn#x#x#I.C.NaY.Naw.N#s#D#D#D#D#s#D#D#D#saY#D#DaY.saY#x.W.Cbn#Ua0aCaoamaOaFaob##v#uaB.y#vaOa#aO.5bga0#U#x.R#D#D.n.7.7#Lbp#L#La2#L#g#L#g#La2#L#L#Lafa2a2#La2#L#La2#La2#La2#Lafa2#L#La2#La2#Laf#L#Laf#Laf#L#L#Laf#L#La2#La2#La2af#Lafa2#L.3#L.j#La9#DaY#xa0#v#aa7a#b#a0bn#x.C#x#x#x#x#xbn#x#x#IaYaYaYaYaYawaY#D#D#D#D#D#D#D#D#Da9#D#D#Dbj#Da9a9#La9af.E.7a9#Laf#Laf.7a9#D.N.N.saY.Nbl#DaY#D.NaYaYaY#xa0b#.5aFbga#aFaFbma#.ybm#vaZ#SaBan.G#q.2.w#u.6#uan.y.0.0", +".6#u.0b#a0#x#xa0bnbn#x#xbn#Ibn#x.RawaY#x#I#x#xbfaYaw.N#D#D.7.7.7a9#D#Da9#Da9#D#Da9a9#D#D.N.N#x#x#I#x#Ia0ao.8am.8aCa0bg#v#vaOb#aoaFaOaFama0a0#Ubn#s#D#Da9.E#L#Lajbpa2#ga2a2aja2#gafa2#La2#La2#La2#Laf#La2#L#Laf#La2#Laf#Laf#Laf#L#Laf#L#Laf#La2afa2#La2af#La2#L.3#La2a2#L#L#L#L#La2#La9#s.N#xa0bg.Xana#aFamam.C#xbn#xbn#x#x#x#xbnaYaYaYawaYaYaYaY#Da9#Da9#Da9#Da9.7#D.7a9.7a9a9.7.7.7.7.7a9#L.7.n#L#Laja9a9#D.saY#D.N#D#D#D#D.saY#DaYaYa0a0amb#aFbm#SbmaBaB#ubha7aB#u#uazaz#Tal#q#uanaB.0a#.0a##u", +"azaBa#aobn#x#x#x#x#x#Ibn#xaY#xaYaYaYaYaY.NaY.NaY#D#D#D#D#D.7a9.7#sa9a9bja9.7#D.Ea9bj.n#D#D.NaY.N#MaYaY#Ia0aoaoam#IaCa0ao.5ao.CaCbg.5b#aoa0aC#xa0aYaY#s.7a9#Lbp#La2bpa2#L#g#L#ga2#Laf#L#La2#La2#La2#La2#La2#La2#Lafa2#Laf#L#L#L.3aj#L#La2ajaf#L#La2#L#La2#La2#La2#La2#La2a2a2afa2#La2#L#DblaY#IamazaSaBaFama0#x.C#xaY#xaY#x#U#x#xaYaYaYaYaYaYaY#D#D#D#Dbj#D#Dbj#Da9a9a9.7a9a9bja9.7afa9aja9.7af.7#Lafa9a9#D#D#D#D#D#D#D#D#D#D#D.NaY#I#xbnaoamam.5a#bma#aZaZaZaZ#uaZanaz#q#TaR.o#q#uaB.0a#.0#uaZ#u", +"an#vb#a0#x#x#xaYaYblaYaYaYaYaYaYaYaYaYblaY.N.N.sbl#D#Da9#D.7a9#L#D.7#sa9.7a9.7#Da9a9#Da9a9#s#D.Naw#Daw#xaCa0.C#x#U#xaCaoaCa0#Ibna0a0aoa0aCa0a0#UaY#M#D#Da9.7#L.7a2a2#ga2a2#ga2#g#La2#La2#La2#La2#La2#La2#Laf#L#Laf#Lafaj#Laf#L#Lafa2af#L#La2#Lafa2#Laf#La2#La2#La2#La2#L#La2#L#La2#Laj#Dbl.NaY#UaZ.TaBaFam.C.C#xaYaYaYaYaYaY#x#xawaYaYaYaYaY#Dbl#D.Ea9a9.7a9a9.7#D.7#Da9bja9.7a9a9.n.7a9a9a9.na9a9a9a9.na9a9a9#D#D#D#D#D.7#D#D#DaY#x#x#xbna0aCamaFaOa#bma#bmaBaZaZaB.6.Gal.o#e.GazanaBaZ#u#u#uan", +"#vaFama0awbnaYaYaY.NaY#D#DaY#D#M#Dbl#s#D#D#s#D#D#Dbl#D.n#Daf.E.7a9a9.7a9a9a9a9a9.7a9.7a9.7a9a9a9#D.n#D.N#x#I#I.W.C#I.Caoam#U#xaw#Ia0#I#x#x#I#x#IaYaY#Dblbja9a9#L#La2bpa2bpa2#La2#Laf#Laf#La2#La2af#L#La2#La2afa2#Laf#L#Lafaj#Laf#L#L#La2#Laf#La2#L#La2#La2#La2#L#La2#La2#L#La2#L#L#Lafa9#sblaY#xb#bm#SaFambn#xaYaYaYaYaYaYaYaYaYaYaYaYawaYaY#Dbl.7a9bja9.7a9bja9#L#L#La9.7a9a9.7a9.7a9a9.7a9.7a9a9a9a9a9a9a9a9a9#D#Da9#D#Da9#Da9.N.NaYaY#x#x#xaYa0ama0am.5aF.5a##vaZan#TaR.Gazana7.wan#uaZan#uaZ", +"b#a0#xaYaYaYaY#x#DaY#D#D#M#Da9a9#D#D#D#D#Da9#D#p#Da9#D.7a9.7#L#La9a9a9.7#L#L.7a9.na9a9.7af#L#L#L#La9.7#s.N#I#x#x.C.CaCa0.W.W#xawaYawaYawaY.NaYaYaYawaY#sbl.7#D.7#L.ja2#ga2#ga2#g#La2#La2#Laf#L#L#La2af#L#L#L#Laf#Lajaf#Laf#Laf#Lajafaf#Laf#L#La2#Laf#Lafa2#La2#La2#L#L#L.3#Laf#La2#L#La9a9#D#MaY.b#yaFbgam#x.N#saYaYaYaYaYaYaYaYaYaYaYaYaYaY#Dbla9.7#L#L.7#L#L#L.7af#La9#La9#La9afafafafa9a9a9a9a9.na9a9a9.n#pa9.n.7a9.7a9.7a9.7#D#D#D#s#DblaYblaY#x#xaCa0aCa0amaOaZ#u#q.G.6#uaBana7azaZaZaZaZa#", +"a0a0a0aYblaYaY#xaYaY#Dbl#Da9a9af.7.7#Da9a9a9a9a9a9a9.n#Da9.7#L#L#La9.7af#L#Lafa9.7a9#L#Lajafa2aj#L.7.n#D.N#xbo#I#x.Waq.8aoa0#I.Nawbl#sbl#DaY#saYawaYaYbl#D#Da9a9#L#Lbpa2#L#g#La2#Laf#Laf#La2#L.3#Laf#L#Lafaf#Laf#Laf#L#Laf#L#Lafaf#L#Laf#Laf#Lafa2#La2#L#La2#Laf#L#L.3#L#L#L#L#L#L#L#L.na9a9blblbn#Hbga0#xaYaYa9blaYblaYblaYblaYaYawaYaYaYaYbl#Da9a9a9a9a9a9a9a9#L#L#L.7a9.7a9a9#La9a9a9a9af.nafa9#pa9#pa9#pa9a9#Da9#D.7#Da9bja9a9.7a9a9a9#D#Dbl#D#saYaY#x.Cbn.WaF#San.Ga4aZa#a#aZ#uanaZaBa#bma#", +"bnaYaYawaYaY#M.N#D#D#D#D#D#D#Da9a9#D.nbja9.7a9.7a9.7.7a9#La9a9a9.7a9#L#L.7af.7a9#Laf#Lafa9.7a9a9#L.7#La9a9#DaY#Ua0#UaCa0#I#x#I#I.N#s#D#D#sa9#D#Da9#D#s#D#Daw#DaYajaf#L#L#Laf#L#La2a2a2#La2#La2#L#La2a2a2a2bpaj#Lajaf#Lajaf#Lajafaja9ajafajaf#L#Lafafafafa2#L#L#La2#L#L#L.3#L.3#L#La2#L#Lafa9.na9aYbnb#b#am.C.NaWa9bj#D#Dbj#D.N.NaYaY#DawaY#DaY#D#D.7a9.7a9.7a9a9#Laf#Laf#Laf#L#Lafafaf#La9#D#D#D#L#Lafajaf#Laf#L#L#L#L#L#L.7.7.7a9a9.7a9#D#D#D#DaYaY.N#x#Ia0.Ca0aF#vaF#vaOb#aob#aoaFaBaZ.0a#.5am", +"#U#x.RaYaYaYbl#D#D#D#D#s#D#Da9#D#D.7#Da9.7a9bja9.7a9af.7a9a9.7a9af.7a9af#L#L#La9a2afaj#L#La9.7a9aj#L#La9.nblaYaY#Ia0aC.W#x#I.N.s#D#s#D.n#D#D#D#sa9a9a9#Dbl#D#D.Na9a9a9a9a9#La9#L#Laf#Laf#Laf#Laf#Laj#L.7aj#L#L.7afajafaf#Laf#Laf#Laf#L#Laf#L#Lafafafaf#Lafa2#L#L#L#La2af#L#L#L#La2a2af#L#La9bja9.Rawa0.8a0.C.Nbj#Da9a9#Da9#D#DaY#DaYbl.Nblaw#Dbl#D.7a9a9.7a9a9bjaf#Lajaf#L#Laf#Lafafafa9a9#Da9#D#Laf#Laf#L#L#Lafaj#L#L.7#L.7af.7#La9a9.7#D#D#D#D#D.NaY#x#x.C.CaoaFaFaOaOamamamamaCaF#v#v.0#vb#am", +"bnbnawaYaYaY#Dbl.n#D#D#Da9bja9bj.n#D.7a9#D.7a9a9a9.7a9a9#La9a9a9#L#L#L#L#Laf#L#La2a2a2af#La9a9a9#L#Laf.7a9#D#IaY#UbnaC#xaY.N.saY.s#D#Db.#D.n#D.7a9a9#Da9#D#D#D#Da9bja9#Da9#Da9#Da9a9a9a9a9a9a9a9#Laf#L#Lafafajaf#La9#Lajaf#Lajaf.7#Laf#L#Lajaf#Lajafaf.3#L#L#L#Laf#Laf#La2a2#La2#La2#La2af.Ea9.naY#xaCamam#x.Nbj#s.7#D#D#D#Dbj#D#Dbl#Dbl.Nbl#Dbla9a9a9a9a9a9a9a9afafafafajafafajafaf.na9a9a9#D#D#Lajaf#L#Lafa2#L#Laf#L#L#La9.7a9a9.7a9a9#Da9#D#D#D#MaY#x#x.CaCa0aFaOaFamaFaCa0a0bnaCb#aOaFaOama0", +"#IaYaYaYawaYaw#D#D#D#s#D#sa9#sa9.7a9a9a9.7a9#L.7#La9af.7a9a9.Ea9afaj#Laf#L#La2#La2a2a2#La2#La9#L#L#Laja9a9blaYaY#I#U#xaw.Naw#D#Da9#sa9#sa9.7a9.7ajaf.Ea9a9.7a9#D#D#D#D#Dbj#D#D#Da9#D#D#D#sbl#D#sa9a9a9a9a9#Da9#Dafajafaf.Eaf.7afajaf#Lajafaf#Lafafafajaf#Laf#L#L#Laf#L#L#Lafa2#La2a2af#L#La9a9a9aw#x.Vaoa0#x.Nbja9#D#D.7#D#D#D#Dbl#DaY#DblaYaY.Na9a9a9a9a9.7a9a9#La9afa9afa9af#pafa9#pa9a9a9.7a9#Laf#Laf#L#L#L#Laf#L#Laf.7a9#D.7a9.7a9.7#D#Dbj#Dbl.NaY#x#I.Ca0aqbgaFamaoambn.Cbn#U#xbna0aCama0a0", +"aYaY#IaYbl.N.N#D#s#D#D#D#D#D#Da9a9a9.7a9a9a9a9#Laf#L#Laf#L#Laf#L#Lafa2a2a2a2a2a2a2a2a2a2a2#L#Lafa2#L#La9a9#DaY#Ubn#I#xaYaw#D#s.sa9bj.n#Da9.Ea9.7#L.7#L#L.7a9.7#L#Da9#Da9#Da9#Da9#Dbl#Dbl#D#Dbl#Dbl#s#D.na9#s#D#Ma9a9.n#Laf#Lajaf#Laf#Laf#L#Lafajafafafaf#Laf#L#L#La2#L.3#L#L#Lafa2a2#L#Lafa9.na9#Dawa0bga0#x.N#s#Da9#D#D#D#D#D#D.Nbl#DaYaYaYawaYa9.na9#La9afa9afa9a9a9a9a9a9a9a9a9#pa9a9a9a9a9a9#L#Lafaj#L.3#La2afafa2af#La9a9a9afa9.7a9#D#D#D#D#DaY.N#x#xa0a0aoaFbgama0a0a0aCa0aYaY.baYbnbnaC#x", +"aYaYblbl#D#Da9.7a9a9a9a9.na9a9.7ajafaj#L#L#La2#L#L#L#L#Lafaj#Lafa2a2#L.j#La2#La2a2a2a2#La2af#L#L#L#L#L#La9#MaYaY#Ibn#MaY#D.s#D#s.7.na9.Ea9.7aj#La2aj#L#Laj#L#L.7.7a9.7.7a9.7a9.7#M#Dbl#MblblaYbl.sbl#Dbl#D#Dbl#Daf.Ea9af.Eafa9af#Lafaj#L#Laf#Lafafafafafaf#Laj#L#Laf#L#La2afa2#La2#L.3#L#L.7#Da9#DaYaCama0#Ibla9#Dbj#D#Da9#D#D.N#MaY#DblawaYaYaY#pa9a9a9#pa9a9a9afa9afa9#p.na9a9#Mbla9a9a9#La9.7afaj#Laf#L#Laf#Laf#Laf.7afa9afa9a9.7a9#D.7#D#D#D#Dblaw#x#x.WamamaOb#aOa0aC.Cbn.C#U.RaYaY.b#xbna0", +"aYaY#D#D#D#s.7.7a9.7a9.7a9a9.7a9#Laf#Laf#Laf#Lafa2a2a2a2#La2a2aja2a2.3a2a2a2a2a2aaaaa2a2a2a2a2#La2#L#La9a9#DaY#I.RaYaw#D#M#D#s#D.n.7a9.n#L.7af#La2a2a2#La2#L#L#La9a9.7a9a9.7a9a9a9#pa9a9a9.n#pblaYaY#IaY#IaYaw#x.na9af#Laf#Laj#Laf#La9afajaf#L#Lafafafaj#Laf#L#Lafa2#L.3#L#L#L#La2a2#L#Laf.na9.n#D.NbnaCaobn#D#s#D.n#D#D#D.N.NaY#DaY#Dbl.NaYaYaw#D#pa9#p.n#pa9#pa9a9.n#pa9#pa9#pa9#D#pa9afafajaf#Laf#L#Laf#L#Laj.3af.3afafa9a9a9.7a9.7a9#D#D#D#D.NaY.N#xa0ama0aob#ama0a0a0bn#Ibna0#x.bbnaY#Uamam", +"#MaY#s#D#D.7#La9#L.7.na9a9.7a9a9#L#L#L#La2#La2#La2a2a2aja2#La2afa2aja2#La2a2a2a2#gaaa2a2a2a2a2a2a2#L#La9a9blaYaYaY#MaY#M.N#D.n#D.na9.n.7#L.E#L#L.ja2a2a2#g#L#L#L#Lajaf#Lajaf#L#La9a9#pa9#pbla9.naYawaYaYaY.RaYaY.na9.na9aj.7af.n#Lafaj#Laf#Lajafafajafafaf#L#L#L#Laf#L#La2afa2af#L#La2af#L.7a9a9.7aw#xaCa0#IaYa9#D#D#D#D#D.NaY.saY#Dbl#DaYaYaYaY.na9#pa9a9#p.na9af#p#pa9a9a9#pa9#Dbl#Da9.na9#L#Laf#L#Lafajaf#Lafafafafafafafa9a9afa9a9bja9bj#D#D#D#DaY#x.Wa0av.5.pamaCa0#Ua0#x#xa0bnaYaw.R.Cb#am", +"amam#xbla9a9a9a9a9a9.7a9.7afa2#Laf#Laf#La2#La2#La2a2a2a2a2a2a2a2#Laf#Laf#La2#L.3a2a2a2a2asa2#La2#gafa9blaYawaYaYawbn#IaYawaw#D#Da9.Ea9#Lafaf#L#L#L#La2a2a2a2a2a2a2a2#La2af#L#Lafajaf#L.na9bja9#D#p#pbl#M#x#Ia0bn#I.NaY#D#Da9a9.7af.Eafa9aja9#Lafa9a9a9a9#Lafa9afajafafafaf#Lafafa2.ja2afajaf#L.na2a9aY.Cbgam#x#Ma9.n#Lajafa9.N.N#pa9bl.N#MaYaYaY#p#pa9#pa9#pa9#p#pa9#p.n#p#p.n#pa9#pa9a9#paf#pa9a9.n#pafafafafafafafa9afa9afa9a9.na9a9a9a9a9#D#D.n#paYaYa0amb#amb#a0a0a0.Ca0#I#xaw#xaY#x#xaCa0aC", +"ama0#xbla9.na9a9bja9#Da9a9ajaf#La2aj#Lafa2#La2#La2a2#La2#La2#La2af#Lafa2#Laf#L#La2a2a2asa2a2a2a2a2#La9blaYaYaYawaYaY#xawaY.N#s#Daja9#Lafajaf#Laf#L.j#La2#La2#La2#La2#La2#L#L#L#L#L#Laf.7a9#D.n#Da9.nblblaYaY#xaC#x#IaY.s#D#sa9.na9a9a9a9a9a9a9a9a9afa9afa9a9#La9afafaj#Lafaf#Lafa2#La2#Lafafaj#La2.naw.CamaC#xaY#D#D#La9a9#sbl.Na9#M#DblaYaYaY#xbla9#p#pa9#pa9#pa9#pa9#p#pa9#p#p#pa9.n#pa9a9a9af#pafa9afa9a9afa9#La9af.7afa9afafa9afa9a9.na9#Dbl#p#pblbn#U.5bg.5a0aoa0a0#Ua0#xbnaYaYaY#U#xbn#xa0", +"amaCaYaYaw#Dbl#sa9#D.7a9.7af#L#Lafaf#L#La2#La2#La2a2a2a2a2a2a2a2#L#L#Lafaja2#L.3a2a2a2#La2a2a2a2#ga9#D#MaYaY#UaY#xaw#Ibl.Naw#D#Dafafaja9#L#Laf#La2#La2a2a2a2a2a2a2.jafa2#Laf#Laf#Laf#La9a9.7#Da9a9a9#sblawaY#x#x#IaY.NaY#D#D#D#D#sbl#s#D#sa9a9.na9.na9a9.nafa9afafafafafafafajafa2#L.3#L#Laja9#Daj#DaY.Ca0aoa0aY#D#Ma9.na9#D#DaYblblblaYaYaYaYaYbl#pa9#pa9#pa9#pa9#p#Ma9bl#p#D#pa9a9#pa9#pa9#pa9#pa9#pa9#paf#pa9afa9afa9afa9afa9a9a9a9a9a9a9#Da9bla9awaYa0a0ama0b#a0a0a0#x#U#x#xaw#xaw#xbn#I#xa0", +"b#b#aCaYaYbl#Dblbja9#D.na9#Lajaf#L#L#Lafa2#La2#La2a2#La2#La2#La2afafaj#L#Laf#L#La2#La2a2a2a2#La2#La9blaYbnbn.R#IaY#U#xaYaw.N#D#s#L.Eaf#Lafaj#L#L#La2#La2#La2#La2afa2a2a2#L#L#L#Lafajaf.7.n#Da9b.afa9a9a9#DaY#I#x.NaY#saY#s#D#s#DaYaYaYblaY#DaY#Dbla9a9a9a9a9a9a9.na9a9.na9a9a9a9#La2aj#Lafa9a9a9af#Mawa0aCa0a0bn.NaYbl#D#M#DaY.NaYaYaYawaYaYawaYbl.na9#pa9#pa9#pblbla9#p#pa9#p.na9#pa9.n#pafa9af.naf#pajafafafafa9a9a9afa9af.7afaf.nafa9a9af#D#DblblaYaY#xaCa0.Ca0aobnaCbn#xawaYaY.RaYaYaY#xbn#x", +"a0bnbnbnaYaYbl#D.n#D#sa9a9#Laf#L#L.3#L#L#La2#Lafa2a2a2a2a2a2a2a2#L#Lafaf#L#La2#L#La2#L#L#La2#L#Laf.nblaY.bbn#U#x#Ubn#Ibl.NaYa9.7a9afaja9#Lafaf#La2a2aja2a2a2a2a2a2a2a2a2af#Laf#L#L#L#La9a9.7#Da9#Laja9#D#D.NaYaY#s#D#D#DaY.NaY.saY.saY.NblaY#DaY#sbl#sbla9#Da9#Da9a9.na9a9afa9ajafaf#Lafa9a9#D#sa9blaY#Ua0aob#aC#xaYaw#D#DblaY#IaYawaYaYaYaYaYaYbl#pbla9#pa9#pa9bl#M#p#D#p#M#p#pa9#pa9#pa9a9#pa9#p#pa9#p#pafafaf.nafa9a9#La9afafa9afa9a9afa9#Da9bl.NaYawbn#x#x#x#Ubna0#xbnaY#xaYawaYaw#xawaY#x#U", +"#Ubn#Uam#UaYaYbl#Da9bja9a9#L#Laf#L#Laf#Laf#La2#La2a2#La2#La2#La2af#L#L#L#Laf#La2af#L#La2#L#La2#Lafa9bl.Ra0.pa0bn#U#xawaY#M.N#s.7.na9#Lafaj#L#Lafa2a2a2a2#La2#La2a2a2a2a2#L#L#L#Laf#Laf.7a9#D.7#Dafaf#L.na9#Daw.N.n#D#D#s#Daw#DaYaYaYaYawaYaYawbla9bla9bla9.n#D#Ma9a9a9#Da9#sa9#p#Laf#La9.7.n#D#D#DaYawa0a0aob#amaCa0aYaYaY#DaY#xaYaYaYaYaYbl#Dbl#p#pa9#pa9#pa9#p#pbl#p#pa9#pa9bl#p.na9a9#pa9#pa9af#pafa9af.na9afa9a9aja9a9afa9#Laf.7afa9.7afbl#D#D#DaYaYaY#xaY#xa0bnbn#U.RawaY.baYaYblaY.R#IaYaY", +".Rbnb#a0a0#xaYbl#s#D#sa9.Eaf#L#La2#Laj#La2a2#L#La2a2a2a2a2a2a2a2#La2afa2afa2#Laf.7af#La9a9#Lafa9a9a9.R.Ra0.V#UbnaYaYaY#D#D#D#D.7afajaf.Eafaf#L#La2#La2#La2a2a2a2a2a2#La2#L.3.7#Lafaj#La9a9.n#Da9#Laj.7a9.7#D.N.Na9.n#D#DaY.NaY.sbl#Mblbl#Dbl#Dbl#D#Dbl#s#Dbl#Dbla9#Da9.nbla9a9#Dajaf.na9#D#D#D#sblawaY#x#Ub#b#aO.5a0aCaYaYawaY#x#xaYaYaY.sblbl.na9#pa9#pa9#pa9#pblbla9#M#p#Dblbl.n#p#p.na9#p.n#p.na9#pa9#pa9af#pa9afa9a9af#Laf#Lafafa9afa9a9#Da9bl#D#M.NaY.Naw#x#UbnbnaYaYaY#xaYbl#MblaYaYaYaY#I", +"#Fbn.Vaoa0bnaYblbja9#Da9a9#Lajaf#Laf#Laf#L#L.3#La2a2#La2#La2#La2af#L#L#L#Lafaj#La9#L#La9a9#L#Lafa9blaw.R#Ua0bnbn#IaYaw#D#s#Da9#s#La9#Laf#L#L#L#La2a2a2.j#L#La2#La2a2a2a2#L#Laf#L#Laf#Laf.7#D.7#s#L#L#La9.7#D.sbf.n#Da9#Daw#DaY.N#pbl#M#D#p.n#pa9#sbl#D#D#Dbl#D#D.na9#Dbl.n#Da9a9af#La9.7a9#s#DaYaY#x.baYbnaoamaFaFaoa0#IbnaYaY.R#x#xaYaYbl#Da9#pa9#pa9#pa9#pbla9#M#pa9#pa9#p#Mbl#pa9a9a9#pa9a9#pa9#paf.naf#pafafa9a9a9afa9af.7afa9#L#La9a9af#D#D#D#DaY#D#DaY.NaYbnbn#U#x.baYaYaw#paY#D#MaY#IaYaY", +"blaw#xa0ambn#xaYawblbl#D#pa9afafa2a2a2a2a2a2#La2#L#La2#La2#La2#La2a2a2afa2#La9a9a9a9a9#D#D#D#D#D#pbl#paY.Rbn#I#x#pa9a9a9a9.7.7a9afajaf.n#Laf#L#L#L#L#La2a2a2#ga2a2bpa2#L#L#L#L.7af#Laf.7a9a9a9#Da9a9#sa9#D#D#D.Na9a9a9#sbl#D#Ma9bl#Dblbl#Dblblbla9a9a9afa9a9a9a9a9a9afa9a9a9a9.nafa9a9.na9a9#D.naY.RaYbna0a0b#aobgb#bg.Va0aCaY#D#Mbl#Mbl#Dblbl#Dbl#Dbl#Dbl#Dblbla9#pbla9#p#pa9#p#p#p#p#p#pa9#pa9#p#p#p#pa9a9afa9aja9afaf#Lafaf#La9afa9#Lafa9a9af#sa9#Dbl#DaYbl.N#UbnbnbnaYaY#IaYaY#MaY#xaYaYaYaY", +"aYaYbn.Ca0a0#I#xaYaYblbl.naf#Lafaja2#La2#La2a2a2#La2#La2#La2#La2a2a2#L#L#L#L#L#Lafa9af#D#p#Dbl#D#F.nblblaYaYaYaYa9.n.7a9a9.7a9.7afafaf#L#L#L#L#La2#ga2#ga2bpa2#L#ga2a2#L#L#L#L#L#Laj#Laf.7a9bja9.7#D.7#D#D#D.Naw#D#M#D#p#D#p#D#Dbl#sbl#Dblbl#Dbla9.na9.naf#paja9afa9.na9a9afa9a9afajafa9a9a9blblaYawaY#Ua0aC.5am.V.Vb#ama0aYaY#xblaY#DaYbl#M#Dbl#Dbla9bla9bla9bl#D#p.n#pbla9bl#p#p.na9#p.na9#p.na9bl.na9afa9a9a9a9afa9#La9af.7afa9a9#Laf#Lafa9a9a9a9a9#D#DaY#saYbnbn#U#x#UaYaYaYaYaYaYawaYaYaY#x", +"aY#xbna0a0a0a0bnaYaY#Mbla9a9a9af#L#Laf#L#L#L#Lafa2#La2#La2#La2a2#La2afa2af#L.7#La9a9#D#D#D#D#DaY#pblbl#MaYaYbl.Na9a9a9.7a9#L.Eaf.naf#Laf#L#L#L#La2a2bpa2#ga2#ga2a2#L#L#L#L.7a9a9a9a9afa9a9#D#D#sa9.nbl#DaYblaYaYbl#D#D#D#M#Dbl#sblbl#Dbl#sbl#D#Ma9a9a9a9a9a9a9a9a9a9a9a9.na9a9a9.n#pa9a9#D#sbl#saYaY.RaY#xa0a0aCa0#Ua0aCbnaYaYawbl#sbl#M#Dblbl#D#pa9a9a9a9a9a9a9#p#p#D#p.n#pa9.n#p#p#pbl#pa9a9#p#pa9#p#pa9a9afa9af#Lafaf#Lafaf#La9a9afa9af#La9afa9a9bl#D#p#DaY#DbnaCbnbnaYaY#IaYaYaw#xaYaYbn#I.R", +".Raw#xa0aC.Ca0a0.baYaYblbla9a9af#Laf#L#La2afa2#L#La2#Lafa2#La2a2a2a2a2#L#L#Laf#L#D#p#Dbl#DblaYaY#pblblbl#Dbl#D#Dafa9af#L#La9#L.7afaf#Lajaf#L#L#L#L#ga2a2#La2bpa2#L#L#Laf#La9.7#Da9a9a9#D#Dbl#DaYblblaYaYaYawaYaY#xawaYaYaYaYaYaYaYaYaYaYaY.NblaYa9a9#pa9a9#pa9#p.n#Da9a9a9#Da9#D#pa9bl.na9blaYblblaYaY#IaYbnbna0#Ua0b#b#a0aYaYblblbl.Nblbl#Dbl#Da9a9afa9afa9afa9#Ma9#pa9#pbl#pbl#p#p#pa9#pa9#pa9a9bl#p.na9a9a9a9#La9af.7afa9#La9afa9a9af.7afafafa9a9a9#D#D#DblaYbnbn#Ibn#IaY.RawaYaYaYaYaYaY#x#x", +"bnbnbnbna0a0a0amaYaYaYaY#D.na9a9afa9afa9#L#L#Laf#L#L#La2#La2#L#La2#L#Laf#L#L#Laf#D#Dbl#DblaYaYaYa9.nblbl#D#D#Dblafaf#L#L#L#L#L#L.naf#Laf#L#L#L#L#ga2bpa2#ga2a2#gaf.3af.7afa9a9.n#D#Dbl#sblbl.NaYaYaYaYawaY#x#xaYaYaYaYaYawaYawaYaYawaYawaYblaYblblbl#Dbl#M#Dblbl#Dbl#D#Dbl#s#Dbl.n#pa9blawblawaYaw.RaY.RaY#U#xbn#UbnaCaOama0aYbl#Dbl#Mbl.Nblbl#Da9.na9a9a9a9a9a9a9#pbl#pa9#pa9#p#p#p#M#p#p.n#pa9.n#pa9#pa9a9afa9#Lafa9afa9#Lafafa9afafa9af#La9#La9af#Dbl#Daw.NawbnbnbnbnaYaY#xaYbn.baY.RaY#xbnbn", +"ama0bna0#Uambgb#aY.RawaYbl#Da9a9a9.7a9.7a9af.7#L#La2af#Laf#L#L#La2a2#La2#Laf#L.7#pblblaYaYblaYaYblblbl#Da9a9a9.7afajaf#L.3#L#L#L#Lafaf#L#L#L#L#L#L#ga2a2bpa2bpa2#La9#Lafa9af#D#D#Dbl#DaYaYaw#xaYaYawaYaY#xbnbnaYawaYaYaYaYbnaYaYaY.RaY.RaY.baYawbl#Mblblblbl#Mblbl#D#D#M#Dbl#D#D#pbl#MblblaYaYaY.RaYaYawbnaYbnawaYaYa0aO.Fa0#x.R#Dbl.Nbl#Mbl#sbla9a9a9a9afafafaf#p#p.na9bl.nbl#p.n#p#pa9#pa9a9#p#pbl#pa9a9a9a9a9#La9afa9a9afa9#Laf#La9afa9af#Lafa9a9#D#Dbl#DblaYbna0#Ubn#I.RawaYawaYaYaY#UbnaCbn", +".Va0bna0.V.Vb#.5bn#xaYaYaY#Da9a9a9#La9#La9#L#Laf#L#L#La2#La2afa2#La2#Laf#La9a9a9blaY#MaYaYaYaYaYbl#Dbl#Dafa9#L#Lafa2a2a2a2a2#L#Lafaj#Laf#L#L#L#La2a2bpa2#ga2a2#gafafafa9a9a9bl#pbl#DblaYaYaYaY#xaY.Rbnbn#Ua0a0a0aYaYaYaYaYaYaY#U.R.b.R.R#U.Rbn.RaYaYawblaYblaYbl.N#MaY#DaYblaYbl#sblblblawblaYaYawbnaY.RaYaw.RaY#IbnaCb#aOb#.Vbn#DblblawaYblbl#Da9a9a9a9.7a9.7a9#D#pbl#p#p#pa9#p#p#p#pbla9#pa9a9#pa9.n#pa9.na9a9afafa9a9afa9#Laf.7af#La9afa9#Lafa9a9a9bl#s#DaY#sbnbnbnbnaYaY#x.Rbnbnbnbnbn#xa0a0", +"a0.Vbn.bbna0b#b##UbnaYaY#D#Ma9a9.Ea9a9a9.7a9.7#Lafa2a2#La2af#L#La2a2#L#L#Laf.7.7blblaYblaYaYaYaY#DaYa9a9a9#La2#La2a2#La2#L#ga2#Lafafafa2#L#L#L#L#L#ga2#g#La2bpa2afafa9af#p#Da9#D#DaY#D#DaYaYaY#x.RaYaYbnbna0a0a0aYaYaY.RaY#UaYaYaYaYaYaYaYaYaYaYawblaYaYaYblaYblaYbl.NblaY#s.Nblblbl#MblaYawaYaY.Raw.RawaY.b#x.baY#xa0aob#bga0bnbl#sblaYaYbl#sbla9.n.7a9.n.7a9a9#pa9#pa9#p#D#pbl#p#p.na9#p.na9#p.n#pbl#pa9a9a9af.7a9afa9.na9a9afaf#Lafa9afa9af#La9.nbl#D#D#DblaYbnbn#UaYaYaYawaY.RaY.Rawbnbna0a0", +"aYaYaYaYaYaY.N#xaYaYawbnaYaYaYaYbl#Dafa9afa9.7#L#L#L#L#L#L#L#L#L.3a2afafa9#D#DaY.R.R#x.RaYawaYaYa9.7a9#L#L#Lafa2a2a2a2a2#g#L#L#Lafafajafafa2#L#L#L#L.7#L#L#L#L#L#L#L#Laf.7#La9a9a9.7a9#D#D#D#D#Dblbl#IaY#xaY#xaYaYaYaYawaYaYaYaYaYawaYaYawaYaYaw#Fbl#M#FblaYaYaY.R.R.R.R.R.R.R.RawaYaYaYaYaYaYawaYbl.NaYaYaYbn#Ibn.baY#Ua0aOb#.Vbg#HaY.bbla9a9.na9a9a9a9.7a9a9.Ea9#p.na9a9.n#pa9#pbl#p#pa9#p#pa9#p#pa9#pa9#pa9a9#pa9.na9afafaf#L#Laf#L#L#L#L#Lafa9a9a9#pblbl.Nbl#x.R#xaY.R#x#xaYaw.RaYaYaYaYaY#D", +"aYblaYaYaY#IaY.NblawaYaYaYaYaYaY#Dbla9a9a9a9a9#L#L#L#L#L#L#L#L#L#Laf#Lafa9#Dbl.N.R.Raw.RaYaYaYaY.7#Da9.7af#La2#La2#ga2#ga2#L#L#Lafafafaf#L#L#L#L.7#L#L#L#L.7#L.7a2a2#L#Laf#La9bja9#D.7#D#D#D#D#D#D#DaYaYaYaYaY#xaYaYaYaYaYaYaYaw#xaY#xaYaYawaYaYbl#FblaY#MaYblaw.R.b.R#MaY#FaY#FaYaYaYblaY#MaYaYblawaY.RawaYawaYbnaY#Ibnao#SaBaF.p#H#U.RaY#Ma9#Da9a9.7a9a9a9a9a9a9a9a9#pa9#pa9.na9#pa9a9#pa9#pa9#p#D#p#s#pa9a9afa9af#pafafafafaf#L#L#Lafaj#Lafaja9#pa9a9#Dbl#DblaY#UaYaYaw#x#xbnaYblaw.RaYaY#Dbl", +"blaYblaYaY#D.NaY#pblblaY.RaYaYaYbl#Dbl#Da9a9.7a9#L#L#L#L#L#Laf#Laf.nafa9#D#DaYaYbn.RbnaYaY.R#xaYa9.7a9#L#L#La2#La2a2#g#L#L#L#L.7afajafaf#Laf#L#L#L#L#L#L#L#L#L#La2#La2a2#L#L#L#L#L#La9.7#Da9bj#DblblaYaYaYaYaYaYbl#Dbl#D#Dbl#Dblbl#Mbl#MaYblaY#Mbl.nbl#pa9aYblaYblaYaYaY.RawaYaY#M#F#M#Fbl#F#F#M#p#p#p#MblaYaYaY#UbnbnaCam#SaBbm#H.p.p.RaYaYbla9.na9a9.na9a9a9a9a9#pa9a9#pa9#pa9#pbla9#pa9#pa9#pa9#p#p#pa9#pa9#pa9#pa9a9afafafaf.3afajafafafafafa9.n#pa9#p#Dbl.N.RbnaY.RaYbnaY#x.b.RaYaYblbl#Dbl", +"#DblblaY#Dbl#D#Dbl#DawaYaYawaYaYaYaYbl#Dbl#D#Da9#Da9#Da9#Da9.7a9a9#p#Dbl#DaYaYaw.R.RaYbnaYaY#xaY#D#Da9.7#L#L#L#La2#ga2#L#L#L.7afafafafafaj#L#L#L#L#L#L#La2#L#L#La2a2a2#La2#L.7#La9#L.7a9.7#D#D#D.N#Dbl.sbl#D#Dbl#D#D#D#Dbl#D#D#Da9#D#D#Da9#D.n#D#pa9#pa9a9blblblblaYblblblblblbl#p#Fbl#p#pbl#pbl#p#M#pblbl#Faw#FbnbnaCamaCaF#SaZ#Hb#bgbnaw.Raw#Da9a9a9a9a9a9.na9afa9a9#p.na9a9#p.na9#pa9#pa9#pa9#M#p#D#p.na9a9a9af#pajafafafafaf#Lafa9afa9a9afaf#paf#p.n#Dbl#DblbnaYbn#Ubn#x#U#xbn.baYblaY#DaY#D", +"blblaY#DaY#D#D#Dbl#Dbl#DblaYaYaYaYaYaYaY#M#Dbla9#D#D#D#D#D#D#D#Dbl#Dbl#DaYaYaYaYbn.R#U.RaY.R#xaY.7a9.7#Laf#La2#La2a2#L#L#L#La9.7afafafaf#Laf#L#La2#g#L#g#L#ga2a2a2a2#La2a2#La2#L#L#Laf.7a9a9#Da9#DblaYaYbl.Nbl#Da9a9a9a9a9a9a9a9.na9.na9a9.na9a9ajafa9.na9a9.na9blblbl#Dblblblbl#M#p#p#p#p#p.n#p#p#p#p#M#pblbl#MbnbnbnaCa0aF#SaZ.V.V.VbgbnaYaYaYbl#D#D#D#D#D#Dbla9#p.na9#pa9#pa9#pbla9#pa9#pa9#pa9#pa9#pa9#pa9af#pa9#pafafaf#Lafa9a9a9a9a9afa9a9afafa9#p#Dbl#saY#x.bbn#xbn#I#xbnbnbnbnawbl#Dblbl", +"a9#pa9bl#M#Dbl#Da9a9#D#D#D#D#D.Nbn#U.RaYaYaY#D#Dbl#D#Dbl#D#Dbl#DaYblaYaYaYawaYaYaY.RaYbn#xaw#xaY.7a9#D#L.7a2#Laf#L#Laf#La9a9#Da9afafajaf#L#L#L#Lbpa2a2a2#ga2a2bpa2a2a2a2a2a2#La2.3#L#L#La9.7a9.7bl.NaYaY#D#pa9#pa9a9a9afafa9a9a9afafafajafafafafafajaf#La9a9a9bj.na9#D.n#Da9#s#D#p#p#p#p.n#pbl#p#p.n#pa9bl#Mblbl#UaY#U#x#Ub#aB.l.V.V.V.VaCbnaY.R#D#Mblbl#Mblblbla9#pa9#pafa9a9#pa9#p#pa9#pa9#pa9#pbl.n#D#pa9#pa9afafafafafafafafafa9#p.na9a9a9a9afafafa9#p#DaYaY.Rbn#x#Ubnbn#xaCa0aCbnaYaYblbla9", +"#pa9#p#Dbl#Da9#Da9afa9bla9bl#DblaYaYbnaYaYaYaYaYblaYblaYblaYaYblaYaYaYaYaYaYaYaY.Rbn.R#xaY.RaYaYa9.7a9#Laf#L#L#Lafaf#Lafa9a9a9.nafafafaf#Laf#L#Laa#ga2#ga2a2#ga2aaasa2a2#La2a2#L#L#L.3#La9.7a9#DaYblaYblbla9a9ajaf#Laf#L#Lafajaf#Lafafaf#Laf#L#La2#L#L#L#L#L.7.7a9a9a9a9a9.na9a9.na9a9a9a9a9a9.na9a9.n#D#D#D#D#D#MblawawbnaC.F.t.Fb#.Vb#.Vbnaw#xaYaYaYaY.NaY#D#Da9#pa9a9#p.n#pa9.nbla9#pa9#pa9#pa9#p#p#pa9.na9afafafafafafafafafa9a9afa9af#pafafafafa9#p#Dblblaw#xbn#Ubn#x#IbnaCb#aCbnawaY#D.na9", +"#pa9#pa9a9#Dbla9a9a9af#D#Da9#D#D#xbn#xbnaYaYblaYaYaYaYaYaYaYaYaYbnaYaYaYaYaYaYaY.R.R.RbnaYaYaYaY#D.7#Da9#La2#Lafajafafa9a9a9a9#Dafafafaf#La2#L#La2a2#ga2a2#gaaa2asaaa2a2a2a2a2a2a2#L#L#La9a9.7a9#D.saY#D.n#pafaf#Lafaj#L#Laf#L#Laf#L#L#L#L#Lafaja2a2a2a2#L.E#L#La9a9a9.7a9a9a9a9a9.7a9.na9a9a9a9.E#L.7.7#D#s#D#s#Fblbl#M#xbnbg.t.F.t.V.V.VaCa0aY#DaYaYaYaY.Nblbl.na9#p.na9a9#pa9#p#pa9#pa9#pa9#pa9#p#D#pa9#p#pa9afafafaf#Lafafa9af#pa9#pa9afa9afafaf#pa9a9#D#DaYbnbn#xbn#Ua0bna0bg.Va0aYblbl#pa9" +}; diff --git a/tests/auto/gui/image/qimagereader/images/namedcolors.xpm b/tests/auto/gui/image/qimagereader/images/namedcolors.xpm new file mode 100644 index 0000000000..f6485d510e --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/namedcolors.xpm @@ -0,0 +1,18 @@ +/* XPM */ +static char *xman[] = { +/* width height ncolors chars_per_pixel */ +"8 8 3 1", +/* colors */ +"e g4 black c pale turquoise 4", +"f m white c light golden rod yellow g4 grey", +"g g white c lemon chiffon m black", +/* pixels */ +"eeeeeeee", +"ffffffff", +"gggggggg", +"gggggggg", +"gggggggg", +"gggggggg", +"gggggggg", +"gggggggg" +}; diff --git a/tests/auto/gui/image/qimagereader/images/negativeheight.bmp b/tests/auto/gui/image/qimagereader/images/negativeheight.bmp Binary files differnew file mode 100644 index 0000000000..875887acef --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/negativeheight.bmp diff --git a/tests/auto/gui/image/qimagereader/images/noclearcode.bmp b/tests/auto/gui/image/qimagereader/images/noclearcode.bmp Binary files differnew file mode 100644 index 0000000000..1a5ca9c9bd --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/noclearcode.bmp diff --git a/tests/auto/gui/image/qimagereader/images/noclearcode.gif b/tests/auto/gui/image/qimagereader/images/noclearcode.gif Binary files differnew file mode 100644 index 0000000000..27784d61b2 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/noclearcode.gif diff --git a/tests/auto/gui/image/qimagereader/images/nontransparent.xpm b/tests/auto/gui/image/qimagereader/images/nontransparent.xpm new file mode 100644 index 0000000000..00c21ef7d7 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/nontransparent.xpm @@ -0,0 +1,788 @@ +/* XPM */ +static char *dummy[]={ +"8 8 777 2", +"#R c #000000", +"fn c #000001", +".e c #000069", +".f c #00006d", +".g c #00006e", +"#d c #0042b4", +"aJ c #010101", +"g0 c #010102", +"dr c #010202", +"gd c #010203", +"#J c #0157bb", +"e. c #020202", +"du c #020304", +"fR c #030303", +"jJ c #040404", +"hf c #040608", +"fE c #040609", +"cO c #04070a", +"k# c #050505", +"gC c #050709", +"ka c #060606", +"br c #06080a", +"dY c #06090d", +"hI c #070707", +"in c #07090b", +"cL c #070a0e", +"cd c #070b0f", +"e0 c #080808", +"gZ c #080b0e", +"eu c #080b0f", +"dz c #080c10", +"hD c #090909", +"fq c #090d11", +"cH c #090e13", +"jB c #0a0a0a", +"#U c #0a0d0f", +"a4 c #0a0d10", +"g3 c #0a0d11", +"fu c #0a0f14", +"cj c #0a1016", +"kb c #0b0b0b", +"#n c #0b0d0f", +"a1 c #0b0e10", +"g8 c #0b0f13", +"f4 c #0b0f14", +"hE c #0c0c0c", +"bf c #0c0f12", +".X c #0c28a0", +"bT c #0d0d0d", +"ax c #0d1014", +"hr c #0d1217", +"dH c #0d141b", +"jy c #0e0e0e", +"aW c #0e1115", +"eH c #0e141b", +"bE c #0f0f0f", +"ar c #0f1317", +"g5 c #0f1419", +"hg c #0f151a", +"fh c #0f151c", +"dJ c #0f171f", +"gI c #101010", +".z c #101094", +"h. c #10161b", +"gm c #10161c", +"eL c #10171f", +"hK c #111111", +"at c #11161b", +"fC c #111820", +"dA c #111922", +"aj c #1163c4", +"bJ c #121212", +"#Z c #12161a", +"ba c #12171c", +"ho c #12181e", +"jK c #131313", +"iq c #13191d", +"cA c #131e2a", +"c7 c #141414", +"dR c #141e29", +"jr c #151515", +"aA c #151a1f", +"hq c #151c23", +"fl c #151e28", +"eV c #151e29", +"d4 c #161616", +"hw c #161e25", +"jk c #171717", +"bs c #171d23", +"g9 c #171f27", +"eC c #17212b", +"b9 c #172432", +"d5 c #181818", +"as c #181e24", +"bn c #181f25", +"bS c #191919", +"gr c #19232d", +"ed c #1a1a1a", +".d c #1a1a6e", +"gB c #1a242e", +"eK c #1a2531", +"dQ c #1a2633", +"hL c #1b1b1b", +"g1 c #1b242d", +"g# c #1b252f", +"eJ c #1b2734", +"d1 c #1b2937", +"bW c #1c1c1c", +"gW c #1c262f", +"ci c #1c2b3b", +"cs c #1c2c3c", +"e# c #1d1d1d", +"#3 c #1d232a", +"f8 c #1d2833", +"fI c #1d2936", +"eO c #1d2a38", +"cw c #1d2e3f", +"jR c #1e1e1e", +"a2 c #1e262e", +"eP c #1e2b39", +"dE c #1e2d3d", +"cF c #1e2f41", +"aO c #1e6ec9", +"c4 c #1f1f1f", +"gx c #1f2a36", +"c# c #1f3043", +"j2 c #202020", +"bk c #202931", +"ht c #202c36", +"eF c #202f3e", +"b7 c #203245", +"cB c #203246", +"hG c #212121", +"aE c #212932", +"bp c #212a32", +"hl c #212d38", +"cc c #213347", +".M c #214eb7", +"hF c #222222", +"#7 c #222a32", +"fw c #223040", +"eU c #223141", +"jC c #232323", +"bb c #232c35", +"ga c #23303d", +"cv c #23364a", +"cn c #23364b", +"jl c #242424", +"gj c #243240", +"cm c #24374c", +"c. c #24384d", +"bF c #252525", +"be c #252f39", +"gt c #253341", +"dU c #253649", +".Y c #256cc9", +"jG c #262626", +"h8 c #26333d", +"hb c #263440", +"gs c #263443", +"cr c #263b51", +"cW c #272727", +"aC c #27313b", +"a9 c #27313c", +"fk c #273748", +"eR c #27384b", +"cq c #273d55", +"jV c #282828", +"#5 c #28313b", +"b0 c #2877ce", +"gL c #292929", +"#Y c #29323c", +"hu c #293744", +"fK c #293a4d", +"jP c #2a2a2a", +"#w c #2a323b", +"bg c #2a3540", +"dF c #2a3f55", +"jn c #2b2b2b", +"a6 c #2b3641", +"jY c #2c2c2c", +"h5 c #2c3b47", +"hp c #2c3c4a", +"gp c #2c3c4d", +"cx c #2c445e", +"bU c #2d2d2d", +"h# c #2d3e4c", +"dS c #2d435b", +"e5 c #2e2e2e", +"cG c #2e4762", +"jF c #2f2f2f", +"aG c #2f3b48", +"gU c #2f3f4e", +"ck c #2f4966", +"j0 c #303030", +"a0 c #303d4a", +"he c #304251", +"cQ c #307ace", +"e4 c #313131", +"ew c #31465d", +"dW c #314862", +"ce c #314b68", +"jm c #323232", +"bm c #323f4d", +"k. c #333333", +"e3 c #343434", +"hi c #344757", +"eT c #344b64", +"b8 c #34506f", +"dj c #347fd1", +"bX c #353535", +"f9 c #35485c", +"ac c #363636", +"#V c #36434f", +"fv c #364c64", +"dV c #36506d", +"c2 c #373737", +"ev c #37506a", +"bI c #383838", +"bw c #384655", +"h4 c #384b5a", +"hk c #384c5d", +"ea c #393939", +"bh c #394857", +"gX c #394d5f", +"#e c #3981d2", +"e6 c #3a3a3a", +"eS c #3a546f", +"em c #3a81d2", +"#F c #3b3b3b", +"eQ c #3b5571", +"dT c #3b5776", +"cI c #3b5c7f", +"gJ c #3c3c3c", +"hX c #3c5060", +"fi c #3c546f", +"gG c #3d3d3d", +"jv c #3e3e3e", +"az c #3e4e5e", +"fL c #3e5772", +"bK c #3f3f3f", +"gD c #3f576f", +"fJ c #3f5874", +"d2 c #3f86d5", +"jx c #404040", +"#8 c #404e5d", +"bv c #405161", +"cf c #406389", +"jL c #414141", +"iG c #415561", +"im c #415663", +"gz c #415971", +"et c #415d7c", +"cz c #41658c", +"f# c #418ad7", +"jT c #424242", +"gy c #425b74", +"fs c #425d7a", +"#K c #4288d4", +"jQ c #434343", +"eX c #438cda", +"j8 c #444444", +".L c #44449a", +"eZ c #454545", +"#s c #455362", +"fx c #45617f", +"cK c #456b94", +"aP c #458cd5", +"ab c #464646", +".n c #46469f", +"aH c #46586a", +"gV c #465f74", +"d0 c #46678c", +"c9 c #474747", +"aF c #47596c", +"a3 c #475a6d", +"ex c #476687", +"jU c #484848", +"by c #485b6e", +"gq c #48627d", +"dI c #486b91", +"cC c #48709b", +"js c #494949", +"#2 c #495a6b", +"ih c #49606f", +"hm c #49637a", +"gk c #49647f", +"j7 c #4a4a4a", +"dt c #4a6e94", +"ak c #4a8dd7", +"b1 c #4a90db", +"c1 c #4b4b4b", +"bx c #4b5f72", +"fr c #4b698a", +"dG c #4b6e95", +"co c #4b75a2", +"fW c #4b91db", +"bD c #4c4c4c", +"hc c #4c687f", +"j6 c #4d4d4d", +"#Q c #4d5f71", +"ik c #4d6676", +"hH c #4e4e4e", +"#0 c #4e5f72", +"aD c #4e6277", +"b. c #4e6377", +"gN c #4e91dc", +"c0 c #4f4f4f", +"bj c #4f6378", +"dZ c #4f759e", +"cD c #4f7aa9", +"hN c #4f8dcd", +"kd c #505050", +"#S c #506275", +"#6 c #506376", +"ge c #506e8c", +"af c #515151", +"b# c #51667b", +"dk c #5195df", +"cT c #525252", +".c c #525280", +"bq c #52677d", +"iH c #526b79", +"fj c #527397", +"eW c #52769d", +"dy c #527aa5", +"hJ c #535353", +"#x c #536476", +"eG c #53789f", +"jM c #545454", +"#r c #546577", +"bz c #546a80", +"dM c #547ca8", +"fP c #5499e2", +"jp c #555555", +"iK c #556f7e", +"bM c #565656", +"fB c #56799f", +"dC c #567fab", +"gE c #569be2", +"cU c #575757", +"h7 c #57748b", +"gc c #577797", +"fN c #577ba1", +"dx c #5780ad", +"cg c #5787bb", +"i4 c #585858", +"iF c #587483", +"hy c #587792", +"g2 c #587893", +"fy c #587ca3", +"eA c #587ea7", +"jW c #595959", +"bu c #597087", +"ia c #5984b2", +"ae c #5a5a5a", +"#t c #5a6c7f", +"bd c #5a7189", +"ij c #5a7789", +"eI c #5a81ab", +"bR c #5b5b5b", +"ch c #5b8dc3", +"en c #5b9be1", +"ke c #5c5c5c", +"cP c #5c8fc5", +"j5 c #5d5d5d", +"iN c #5d7fa0", +"gl c #5d80a3", +"fp c #5d83ac", +"cl c #5d8fc6", +"b2 c #5d9de6", +"c8 c #5e5e5e", +"hh c #5e7f9c", +"hn c #5e809d", +"i3 c #5f5f5f", +"#1 c #5f758c", +"a8 c #5f7890", +"g7 c #5f819e", +"cJ c #5f93cc", +"jz c #606060", +"ct c #6094cd", +"bO c #616161", +"eN c #618cb9", +"jH c #626262", +"iW c #627c8d", +"hd c #6285a3", +"ey c #628dbb", +"dO c #6290c4", +"ca c #6297d1", +"jI c #636363", +"eM c #638fbd", +"jN c #646464", +"fH c #648db9", +"eE c #648fbe", +"cb c #649ad5", +"hA c #64a8e2", +"jw c #656565", +"#k c #65798f", +"fF c #658eba", +"fA c #658fbb", +"fa c #65a4e7", +"b3 c #65a6e8", +"jX c #666666", +"hW c #6688a3", +"gh c #668cb2", +"aI c #6696cb", +"dN c #6697cc", +"bA c #6699ce", +"cu c #669edb", +"#C c #676767", +"f3 c #678db4", +"dl c #67a6eb", +"kc c #686868", +"cS c #696969", +"dK c #699bd2", +"cN c #69a2e0", +"cy c #69a3e1", +"fX c #69a6e8", +"jD c #6a6a6a", +"av c #6a84a1", +"ds c #6a9cd3", +"dL c #6a9cd4", +"jt c #6b6b6b", +"fo c #6b97c6", +"cE c #6ba5e4", +"jS c #6c6c6c", +"aV c #6c88a4", +"ir c #6c8ea4", +"il c #6c8fa5", +"eD c #6c9bce", +"dB c #6c9ed7", +"dq c #6c9fd8", +"cM c #6ca7e7", +"cp c #6ca8e8", +"eo c #6cabed", +"i2 c #6d6d6d", +"#T c #6d869f", +"#W c #6d87a0", +"gY c #6d94b5", +"aa c #6d9bcb", +"eB c #6d9dd0", +"dw c #6da0d9", +"dD c #6da1da", +"b4 c #6dacee", +"h9 c #6dafe2", +"i6 c #6e6e6e", +"bt c #6e8aa7", +"fM c #6e9bcb", +"dP c #6ea3dc", +"b5 c #6eabee", +"jd c #707070", +"ix c #7088a2", +"hx c #7098ba", +"f7 c #7099c3", +"dv c #70a5df", +"b6 c #70adef", +"iy c #70aff1", +"dm c #70aff2", +"jE c #717171", +"#m c #7188a0", +"#u c #7189a1", +"aY c #718eac", +"gO c #71aced", +"jq c #727272", +"gb c #729cc6", +"hO c #72afee", +"ib c #72afef", +"e7 c #737373", +"#y c #738ba4", +"#A c #739eca", +".j c #747474", +"#9 c #748fab", +"hs c #749ec1", +"f6 c #749fca", +".i c #757575", +"#q c #758da6", +"a5 c #7593b1", +"bo c #7594b2", +"ii c #759bb3", +"fb c #75b3f4", +"ep c #75b4f3", +"is c #75b8e2", +"ag c #767676", +"fz c #76a6da", +"ez c #76a9e0", +"dX c #76adeb", +".h c #777777", +".m c #777794", +"iX c #77a6b3", +"dn c #77b1f4", +"gK c #787878", +"#4 c #7894b0", +"fG c #78a9dd", +"j# c #797979", +"bV c #7a7a7a", +"do c #7ab4f4", +"jA c #7b7b7b", +"io c #7ba3bc", +"dp c #7bb5f5", +".k c #7c7c7c", +"bc c #7c9cbd", +"gi c #7caad8", +"aQ c #7cb0e7", +"fY c #7cb8f9", +"iM c #7cbee2", +"j1 c #7d7d7d", +"aX c #7d9ebf", +"fm c #7db0e7", +"j4 c #7e7e7e", +".8 c #7ea5ce", +"#D c #7f7f7f", +"hv c #7facd3", +"gn c #7faedd", +"eb c #808080", +"er c #80bdf9", +"j3 c #818181", +"hz c #81afd6", +"gu c #81b0e0", +"eq c #81bbf9", +"fc c #81bbfc", +"#b c #828282", +"iE c #82aac0", +"i5 c #838383", +"ha c #83b1d9", +"es c #83bcf9", +"ad c #848484", +"go c #84b5e6", +".v c #858585", +"#p c #85a0bc", +"bN c #868686", +"hZ c #86b3d6", +"fD c #86bcf6", +"fO c #86bcf7", +"gP c #86c1ff", +"di c #878787", +"ft c #87bdf8", +"bH c #888888", +"iT c #88cfe2", +"jZ c #898989", +"#z c #89a5c3", +"g. c #89bbee", +"fg c #89c0fc", +"fd c #89c2fd", +"hP c #89c3ff", +"jb c #8a8a8a", +"#o c #8aa6c4", +"jc c #8b8b8b", +".S c #8baccf", +"iI c #8bb6ce", +"al c #8bb9e8", +"hj c #8bbde7", +"gw c #8bbef2", +"ff c #8bc3ff", +"fe c #8bc4ff", +"fZ c #8bc6ff", +"ec c #8c8c8c", +"gv c #8cbff3", +"jO c #8d8d8d", +"a# c #8dadce", +"ic c #8dc7ff", +"#H c #8e8e8e", +"a. c #8eaed0", +"#L c #8ebae8", +"hY c #8ebee3", +"g4 c #8ec1ec", +"iO c #8ecbff", +"ju c #8f8f8f", +"bi c #8fb5da", +"h6 c #8fc0e5", +"f5 c #8fc4f9", +"jf c #909090", +"bl c #90b6dc", +"i1 c #90dfe2", +"bC c #919191", +"aB c #91b5dc", +"aZ c #91b7dd", +"hV c #91c2e8", +"gf c #91c6fc", +"gg c #91c7fd", +"f0 c #91c8ff", +"i7 c #929292", +"gA c #92c8fe", +"iz c #92ccff", +"iU c #939393", +"a7 c #93b9e0", +"f2 c #93c9ff", +"gQ c #93ccff", +"e8 c #949494", +".y c #9494b0", +"h1 c #94c6ec", +"f1 c #94caff", +"j9 c #959595", +"#X c #95b7da", +"cX c #969696", +"ay c #96bbe3", +"#f c #96bde8", +"aR c #96c3ee", +"gR c #96cfff", +".J c #979797", +"hQ c #97cfff", +"fT c #989898", +"#j c #98b6d7", +"#l c #98b7d8", +"iJ c #98c7e1", +"g6 c #98cffd", +"jj c #999999", +"aS c #99c4ee", +"h3 c #99ccf4", +"gS c #99d0ff", +".l c #9a9a9a", +".b c #9a9aa4", +"aw c #9ac1ea", +"gT c #9ad1ff", +"dg c #9b9b9b", +".N c #9bbee8", +"aq c #9bc1eb", +"am c #9bc4ee", +"eg c #9c9c9c", +"au c #9cc3ed", +"ao c #9cc5ee", +"c5 c #9d9d9d", +"aT c #9dc7ef", +"hU c #9dd2fb", +"hR c #9dd3ff", +"dh c #9e9e9e", +"#v c #9ebee0", +".Z c #9ec3e8", +"#M c #9ec3ed", +"#N c #9ec5ed", +"ap c #9ec5ef", +"aU c #9ec7f0", +"h2 c #9ed4fd", +"id c #9ed6ff", +"df c #9f9f9f", +"an c #9fc5ee", +"h0 c #9fd5fe", +"aM c #a0a0a0", +"hT c #a0d6ff", +"jh c #a1a1a1", +"hS c #a1d7ff", +"ji c #a2a2a2", +"#P c #a2c7ed", +"i8 c #a3a3a3", +"#O c #a3c8ed", +"iA c #a3daff", +"j. c #a4a4a4", +"je c #a5a5a5", +"#g c #a5c8ed", +"ip c #a5dafb", +"iv c #a6a6a6", +".F c #a6bed4", +"de c #a7a7a7", +"#h c #a7c9ed", +"if c #a7ddff", +"ie c #a7deff", +"eh c #a8a8a8", +"#i c #a8caee", +"iL c #a8dbf8", +"ig c #a8deff", +"iP c #a8e0ff", +"iY c #a8e2e6", +"hC c #a9a9a9", +".0 c #a9caed", +"#B c #aaaaaa", +"fU c #ababab", +".5 c #abc9e9", +"iB c #abe3ff", +"e2 c #acacac", +".6 c #accaea", +"jo c #adadad", +".1 c #adcbed", +".7 c #adccec", +"iD c #ade2ff", +"iC c #ade3ff", +"fS c #aeaeae", +".4 c #aecded", +"db c #afafaf", +".A c #afbbe7", +".2 c #afccee", +".3 c #afceee", +"d6 c #b0b0b0", +"iQ c #b0e9ff", +"bG c #b1b1b1", +"jg c #b2b2b2", +"#E c #b3b3b3", +".O c #b3d1ed", +"gF c #b4b4b4", +"cY c #b5b5b5", +"iR c #b5ebff", +"hM c #b6b6b6", +"iS c #b6ecff", +"d9 c #b7b7b7", +".U c #b8b8b8", +".u c #b9b9b9", +"dd c #bababa", +".P c #bad4ee", +"bL c #bbbbbb", +".Q c #bbd4ef", +".R c #bbd5f0", +"e9 c #bcbcbc", +"c3 c #bdbdbd", +"f. c #bebebe", +"d8 c #bfbfbf", +".o c #bfc2e8", +"iZ c #bffdff", +"iw c #c0c0c0", +"iV c #c1c1c1", +"i0 c #c1feff", +"ei c #c2c2c2", +"ej c #c3c3c3", +"#a c #c4c4c4", +"el c #c5c5c5", +"d7 c #c6c6c6", +".r c #c6cbda", +"ek c #c7c7c7", +"aN c #c8c8c8", +"#G c #c9c9c9", +"aL c #cacaca", +"ai c #cbcbcb", +".B c #cbddf2", +"bZ c #cccccc", +".C c #cce0f3", +"dc c #cdcdcd", +"ah c #cecece", +"da c #cfcfcf", +".E c #cfe1f3", +".D c #cfe1f4", +"#I c #d0d0d0", +"cV c #d1d1d1", +"fQ c #d2d2d2", +"bB c #d3d3d3", +"#c c #d4d4d4", +"d# c #d5d5d5", +"aK c #d6d6d6", +"cZ c #d7d7d7", +"c6 c #d8d8d8", +"gH c #d9d9d9", +".W c #dadada", +"gM c #dbdbdb", +"bQ c #dcdcdc", +"e1 c #dddddd", +"cR c #dedede", +"d. c #dfdfdf", +"bP c #e0e0e0", +"i# c #e1e1e1", +"bY c #e2e2e2", +".K c #e3e3e3", +"ee c #e4e4e4", +"d3 c #e5e5e5", +"ef c #e6e6e6", +".p c #e6e9f6", +"fV c #e7e7e7", +"eY c #e8e8e8", +".a c #e9e9e9", +".q c #e9edf8", +".V c #eaeaea", +"## c #ebebeb", +"Qt c #ececec", +".w c #ededed", +".x c #eeeeee", +"#. c #efefef", +".# c #f0f0f0", +".9 c #f1f1f1", +".I c #f2f2f2", +".T c #f3f3f3", +"ja c #f4f4f4", +"i9 c #f5f5f5", +"hB c #f6f6f6", +".H c #f7f7f7", +".G c #f8f8f8", +"i. c #f9f9f9", +"kg c #fafafa", +"kf c #fbfbfb", +".t c #fcfcfc", +".s c #fdfdfd", +"it c #fefefe", +"iu c #ffffff", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt"}; diff --git a/tests/auto/gui/image/qimagereader/images/qt-gif-anim.gif b/tests/auto/gui/image/qimagereader/images/qt-gif-anim.gif Binary files differnew file mode 100644 index 0000000000..8bca4a8354 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt-gif-anim.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt-gif-noanim.gif b/tests/auto/gui/image/qimagereader/images/qt-gif-noanim.gif Binary files differnew file mode 100644 index 0000000000..b6a854067d --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt-gif-noanim.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt.gif b/tests/auto/gui/image/qimagereader/images/qt.gif Binary files differnew file mode 100644 index 0000000000..e0a5a80b13 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt1.gif b/tests/auto/gui/image/qimagereader/images/qt1.gif Binary files differnew file mode 100644 index 0000000000..0ce910cee0 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt1.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt2.gif b/tests/auto/gui/image/qimagereader/images/qt2.gif Binary files differnew file mode 100644 index 0000000000..993a315d0f --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt2.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt3.gif b/tests/auto/gui/image/qimagereader/images/qt3.gif Binary files differnew file mode 100644 index 0000000000..7391678a99 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt3.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt4.gif b/tests/auto/gui/image/qimagereader/images/qt4.gif Binary files differnew file mode 100644 index 0000000000..41109a9c3f --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt4.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt5.gif b/tests/auto/gui/image/qimagereader/images/qt5.gif Binary files differnew file mode 100644 index 0000000000..5a3fb54ff5 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt5.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt6.gif b/tests/auto/gui/image/qimagereader/images/qt6.gif Binary files differnew file mode 100644 index 0000000000..f22e7c980a --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt6.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt7.gif b/tests/auto/gui/image/qimagereader/images/qt7.gif Binary files differnew file mode 100644 index 0000000000..a315671417 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt7.gif diff --git a/tests/auto/gui/image/qimagereader/images/qt8.gif b/tests/auto/gui/image/qimagereader/images/qt8.gif Binary files differnew file mode 100644 index 0000000000..2a7d09e859 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qt8.gif diff --git a/tests/auto/gui/image/qimagereader/images/qtbug13653-no_eoi.jpg b/tests/auto/gui/image/qimagereader/images/qtbug13653-no_eoi.jpg Binary files differnew file mode 100644 index 0000000000..605e8a85da --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/qtbug13653-no_eoi.jpg diff --git a/tests/auto/gui/image/qimagereader/images/rect.svg b/tests/auto/gui/image/qimagereader/images/rect.svg new file mode 100644 index 0000000000..c56549a69a --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/rect.svg @@ -0,0 +1,462 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + width="128" + height="128" + viewBox="0 0 105.427 137.439" + id="Livello_1" + xml:space="preserve" + style="overflow:visible"><defs + id="defs2727"><linearGradient + x1="26.294399" + y1="11.6704" + x2="71.901901" + y2="133.0273" + id="linearGradient3352" + xlink:href="#XMLID_34_" + gradientUnits="userSpaceOnUse" /><linearGradient + x1="36.838902" + y1="7.7075" + x2="82.446297" + y2="129.0645" + id="linearGradient3354" + xlink:href="#XMLID_34_" + gradientUnits="userSpaceOnUse" /><linearGradient + x1="33.882301" + y1="23.583" + x2="39.972198" + y2="23.583" + id="XMLID_34_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2672" + style="stop-color:#ff5d5d;stop-opacity:1" + offset="0" /> + <stop + id="stop2674" + style="stop-color:#e20800;stop-opacity:1" + offset="1" /> + </linearGradient><linearGradient + x1="33.882301" + y1="23.583" + x2="39.972198" + y2="23.583" + id="linearGradient3368" + xlink:href="#XMLID_34_" + gradientUnits="userSpaceOnUse" /><linearGradient + x1="54.356899" + y1="1.124" + x2="99.964401" + y2="122.481" + id="linearGradient3370" + xlink:href="#XMLID_34_" + gradientUnits="userSpaceOnUse" /><linearGradient + x1="15.8457" + y1="15.5972" + x2="61.453098" + y2="136.9541" + id="linearGradient3376" + xlink:href="#XMLID_34_" + gradientUnits="userSpaceOnUse" /><linearGradient + x1="43.438" + y1="5.2275" + x2="89.045403" + y2="126.5845" + id="linearGradient3382" + xlink:href="#XMLID_34_" + gradientUnits="userSpaceOnUse" /><linearGradient + x1="8.1176996" + y1="14.9019" + x2="70.759598" + y2="117.2331" + id="linearGradient3792" + xlink:href="#XMLID_30_" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.9991,-4.18e-2,4.18e-2,0.9991,-2.4309,1.195)" /><linearGradient + x1="10.5708" + y1="10.1548" + x2="73.2117" + y2="112.4844" + id="linearGradient3794" + xlink:href="#XMLID_30_" + gradientUnits="userSpaceOnUse" /><linearGradient + x1="6.2178001" + y1="72.223602" + x2="79.360802" + y2="72.223602" + id="XMLID_26_" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(0,2.1512354)"> + <stop + id="stop2578" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop2580" + style="stop-color:#eeeeec;stop-opacity:1" + offset="1" /> + </linearGradient><filter + id="filter5869"><feGaussianBlur + id="feGaussianBlur5871" + stdDeviation="1.2254964" + inkscape:collect="always" /></filter><filter + id="filter5873"><feGaussianBlur + id="feGaussianBlur5875" + stdDeviation="1.3615922" + inkscape:collect="always" /></filter><filter + id="filter2854"><feGaussianBlur + id="feGaussianBlur2856" + stdDeviation="0.8944793" + inkscape:collect="always" /></filter></defs> +<filter + id="AI_Sfocatura_1"> + <feGaussianBlur + id="feGaussianBlur2545" + stdDeviation="1" /> +</filter> +<g + transform="translate(-3.2052027,3.2058836)" + id="g2547"> + <g + transform="matrix(0.9982563,0,0,0.9982563,-1.5492234e-2,0.2232388)" + id="g2549"> + <g + id="g2551"> + <linearGradient + x1="6.2178001" + y1="68.029297" + x2="79.360802" + y2="68.029297" + id="XMLID_24_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2554" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop2556" + style="stop-color:#eeeeec;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 9.542,121.224 C 7.713,121.224 6.217,119.728 6.217,117.9 L 6.217,18.16 C 6.217,16.331 7.713,14.835 9.542,14.835 L 76.036,14.835 C 77.864,14.835 79.36,16.331 79.36,18.16 L 79.36,117.9 C 79.36,119.728 77.864,121.224 76.036,121.224 L 9.542,121.224 z" + id="path2558" + style="fill:url(#XMLID_24_)" /> + </g> + <g + id="g2560"> + <linearGradient + x1="10.5718" + y1="15.3989" + x2="73.212097" + y2="117.7277" + id="XMLID_25_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2563" + style="stop-color:#77b753;stop-opacity:1" + offset="0" /> + <stop + id="stop2565" + style="stop-color:#00892c;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 11.204,18.159 C 10.29,18.159 9.542,18.907 9.542,19.821 L 9.542,116.237 C 9.542,117.151 10.29,117.899 11.204,117.899 L 74.375,117.899 C 75.289,117.899 76.037,117.151 76.037,116.237 L 76.037,19.821 C 76.037,18.907 75.289,18.159 74.375,18.159 L 11.204,18.159 z" + id="path2567" + style="fill:url(#XMLID_25_)" /> + </g> + </g> + <g + transform="matrix(0.9982563,0,0,0.9982563,1.05825,0.2232388)" + id="g2569"> + <path + d="M 11.639,126.468 C 9.811,126.468 8.314,124.972 8.314,123.143 L 8.314,23.403 C 8.314,21.574 9.811,20.078 11.639,20.078 L 78.134,20.078 C 79.962,20.078 81.458,21.574 81.458,23.403 L 81.458,123.143 C 81.458,124.972 79.962,126.468 78.134,126.468 L 23.696022,126.468 L 11.639,126.468 z" + transform="matrix(1.041449,0,0,1,-4.451967,3.1512354)" + id="path2575" + style="opacity:0.6;filter:url(#filter2854)" /><path + d="M 9.542,127.56924 C 7.714,127.56924 6.218,126.07324 6.218,124.24624 L 6.218,24.505236 C 6.218,22.677236 7.714,21.181236 9.542,21.181236 L 76.037,21.181236 C 77.865,21.181236 79.361,22.677236 79.361,24.505236 L 79.361,124.24624 C 79.361,126.07324 77.865,127.56924 76.037,127.56924 L 9.542,127.56924 z" + id="path2582" + style="fill:url(#XMLID_26_)" /> + <g + transform="translate(0,2.1512354)" + id="g2584"> + <g + transform="matrix(1.0276326,0,0,1,-2.2508995,0)" + id="g2586" + style="opacity:0.5;filter:url(#AI_Sfocatura_1)"> + <path + d="M 11.639,123.321 C 9.811,123.321 8.314,121.824 8.314,119.997 L 81.458,119.997 C 81.458,121.824 79.962,123.321 78.134,123.321 L 11.639,123.321 z" + id="path2588" /> + </g> + <linearGradient + x1="6.2178001" + y1="69.078102" + x2="79.360802" + y2="69.078102" + id="XMLID_27_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2591" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop2593" + style="stop-color:#eeeeec;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 9.542,122.272 C 7.714,122.272 6.218,120.776 6.218,118.947 L 6.218,19.207 C 6.218,17.378 7.714,15.882 9.542,15.882 L 76.037,15.882 C 77.865,15.882 79.361,17.378 79.361,19.207 L 79.361,118.947 C 79.361,120.776 77.865,122.272 76.037,122.272 L 9.542,122.272 z" + id="path2595" + style="fill:url(#XMLID_27_)" /> + </g> + <g + transform="translate(0,3.2268531)" + id="g2597"> + <g + transform="matrix(1.0368435,0,0,1,-3.0011994,-1.0756177)" + id="g2599" + style="opacity:0.5;filter:url(#AI_Sfocatura_1)"> + <path + d="M 11.639,120.175 C 9.811,120.175 8.314,118.679 8.314,116.85 L 81.458,116.85 C 81.458,118.679 79.962,120.175 78.134,120.175 L 11.639,120.175 z" + id="path2601" /> + </g> + <linearGradient + x1="6.2178001" + y1="65.931602" + x2="79.360802" + y2="65.931602" + id="XMLID_28_" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(0,-1.0756177)"> + <stop + id="stop2604" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop2606" + style="stop-color:#eeeeec;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 9.542,118.05038 C 7.714,118.05038 6.218,116.55438 6.218,114.72638 L 6.218,14.986382 C 6.218,13.157382 7.714,11.661382 9.542,11.661382 L 76.037,11.661382 C 77.865,11.661382 79.361,13.157382 79.361,14.986382 L 79.361,114.72638 C 79.361,116.55438 77.865,118.05038 76.037,118.05038 L 9.542,118.05038 z" + id="path2608" + style="fill:url(#XMLID_28_)" /> + </g> + <g + transform="translate(0,1.8317954)" + id="g2610"> + <g + transform="matrix(1.0184218,0,0,1.0158314,-1.4821779,-1.8527316)" + id="g2612" + style="opacity:0.5;filter:url(#AI_Sfocatura_1)"> + <path + d="M 10.639,117.029 C 8.811,117.029 7.314,115.532 7.314,113.704 L 7.314,13.964 C 7.314,12.135 8.811,10.639 10.639,10.639 L 77.134,10.639 C 78.962,10.639 80.458,12.135 80.458,13.964 L 80.458,113.704 C 80.458,115.532 78.962,117.029 77.134,117.029 L 10.639,117.029 z" + id="path2614" /> + </g> + <linearGradient + x1="6.2178001" + y1="62.785599" + x2="79.360802" + y2="62.785599" + id="XMLID_29_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2617" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop2619" + style="stop-color:#eeeeec;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 9.542,115.98 C 7.714,115.98 6.218,114.483 6.218,112.656 L 6.218,12.916 C 6.218,11.087 7.714,9.591 9.542,9.591 L 76.037,9.591 C 77.865,9.591 79.361,11.087 79.361,12.916 L 79.361,112.657 C 79.361,114.484 77.865,115.981 76.037,115.981 L 9.542,115.981 L 9.542,115.98 z" + id="path2621" + style="fill:url(#XMLID_29_)" /> + <linearGradient + x1="10.5708" + y1="10.1548" + x2="73.2117" + y2="112.4844" + id="XMLID_30_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2624" + style="stop-color:#73bdf2;stop-opacity:1" + offset="0" /> + <stop + id="stop2626" + style="stop-color:#3592ee;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 11.204,12.916 C 10.289,12.916 9.541,13.664 9.541,14.578 L 9.541,110.994 C 9.541,111.909 10.289,112.657 11.204,112.657 L 74.373,112.657 C 75.288,112.657 76.036,111.909 76.036,110.994 L 76.036,14.578 C 76.036,13.664 75.288,12.916 74.373,12.916 L 11.204,12.916 L 11.204,12.916 z" + id="path2628" + style="fill:url(#linearGradient3794)" /> + </g> + </g> + <g + transform="matrix(0.9961334,-6.5068755e-2,6.5068755e-2,0.9961334,-5.7493275,-6.3015051)" + id="g2630"> + <g + transform="matrix(1.0311837,0,0,1.0154411,-2.8218065,-1.9088007)" + id="g2632" + style="opacity:0.6;filter:url(#filter5869)"> + <path + d="M 10.744,123.615 C 8.917,123.691 7.36,122.259 7.283,120.432 L 3.118,20.779 C 3.042,18.952 4.474,17.395 6.301,17.319 L 72.737,14.542 C 74.563,14.465 76.121,15.898 76.198,17.725 L 80.363,117.377 C 80.439,119.204 79.007,120.761 77.181,120.839 L 10.744,123.615 z" + id="path2634" /> + </g> + <g + id="g2636"> + + <linearGradient + x1="3.7607" + y1="67.532204" + x2="76.909698" + y2="67.532204" + id="XMLID_31_" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.9991,-4.18e-2,4.18e-2,0.9991,-2.4309,1.195)"> + <stop + id="stop2639" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop2641" + style="stop-color:#eeeeec;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 9.695,121.518 C 7.868,121.595 6.311,120.163 6.234,118.335 L 2.069,18.682 C 1.993,16.855 3.425,15.298 5.252,15.222 L 71.688,12.444 C 73.514,12.368 75.072,13.8 75.149,15.627 L 79.314,115.28 C 79.391,117.106 77.959,118.663 76.131,118.741 L 9.695,121.518 z" + id="path2643" + style="fill:url(#XMLID_31_)" /> + </g> + <path + d="M 7.051,18.474 C 6.138,18.513 5.422,19.291 5.46,20.204 L 9.486,116.535 C 9.525,117.448 10.303,118.164 11.217,118.126 L 74.331,115.489 C 75.244,115.451 75.96,114.672 75.922,113.759 L 71.897,17.427 C 71.859,16.513 71.08,15.797 70.167,15.836 L 7.051,18.474 z" + id="path2652" + style="fill:url(#linearGradient3792);fill-opacity:1" /> + <path + d="M 9.5625,22.375 C 10.84375,52.927083 12.125,83.479167 13.40625,114.03125 C 32.885417,113.21875 52.364583,112.40625 71.84375,111.59375 C 70.5625,81.041667 69.28125,50.489583 68,19.9375 C 48.520833,20.75 29.041667,21.5625 9.5625,22.375 z" + id="path4189" + style="opacity:0.6;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:1.00000001, 1.00000001;stroke-dashoffset:0;stroke-opacity:1" /></g> + <g + transform="matrix(0.9982563,0,0,0.9982563,10.72193,-5.1454722)" + id="g2654"> + <g + transform="translate(-4.2156998e-8,1.0756177)" + id="g2656" + style="opacity:0.6;filter:url(#filter5873)"> + <path + d="M 10.854785,112.52047 C 9.0174891,112.09656 7.8676311,110.2731 8.2990859,108.46891 L 31.839177,9.9940152 C 32.271664,8.1888112 34.127539,7.0580233 35.964835,7.481942 L 102.78149,22.901224 C 104.61776,23.325142 105.76865,25.149615 105.33616,26.954819 L 81.79607,125.42768 C 81.364615,127.23289 79.507708,128.36368 77.671444,127.93976 L 10.854785,112.52047 z" + id="path2658" /> + </g> + <g + id="g2660"> + + <linearGradient + x1="16.688499" + y1="-8.9546003" + x2="94.108398" + y2="105.6356" + id="XMLID_33_" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.9735,0.2287,-0.2287,0.9735,14.4454,7.996)"> + <stop + id="stop2663" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop2665" + style="stop-color:#eeeeec;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 12.707,111.688 C 10.927,111.271 9.813,109.472 10.231,107.692 L 33.037,10.593 C 33.455,8.813 35.254,7.698 37.034,8.116 L 101.767,23.32 C 103.546,23.738 104.661,25.537 104.243,27.317 L 81.436,124.415 C 81.019,126.195 79.219,127.31 77.44,126.892 L 12.707,111.688 z" + id="path2667" + style="fill:url(#XMLID_33_)" /> + </g> + <path + d="M 33.925,25.17 L 35.435,25.3 C 35.369,25.76 35.413,26.134 35.567,26.422 C 35.721,26.71 35.941,26.887 36.226,26.954 C 36.538,27.027 36.832,26.947 37.114,26.715 C 37.396,26.483 37.594,26.116 37.712,25.615 C 37.821,25.149 37.805,24.759 37.661,24.445 C 37.517,24.132 37.298,23.939 37.004,23.87 C 36.811,23.825 36.571,23.817 36.281,23.846 L 36.797,22.386 C 37.187,22.487 37.522,22.455 37.801,22.292 C 38.076,22.127 38.26,21.847 38.353,21.451 C 38.431,21.12 38.41,20.843 38.291,20.618 C 38.172,20.392 37.984,20.25 37.729,20.19 C 37.473,20.13 37.226,20.187 36.987,20.358 C 36.749,20.531 36.562,20.825 36.427,21.24 L 35.104,20.624 C 35.455,19.78 35.886,19.208 36.401,18.909 C 36.915,18.61 37.492,18.536 38.131,18.686 C 38.85,18.855 39.36,19.244 39.663,19.853 C 39.967,20.462 40.045,21.076 39.9,21.695 C 39.802,22.113 39.618,22.468 39.35,22.758 C 39.081,23.049 38.726,23.276 38.287,23.439 C 38.699,23.661 38.996,24.004 39.18,24.471 C 39.362,24.937 39.383,25.471 39.242,26.073 C 39.036,26.949 38.604,27.613 37.948,28.064 C 37.29,28.515 36.601,28.655 35.88,28.486 C 35.189,28.323 34.661,27.944 34.297,27.347 C 33.931,26.751 33.808,26.025 33.925,25.17 z" + id="path2676" + style="fill:url(#linearGradient3368);fill-opacity:1" /> + <linearGradient + x1="26.294399" + y1="11.6704" + x2="71.901901" + y2="133.0273" + id="XMLID_35_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2679" + style="stop-color:#ff8080;stop-opacity:1" + offset="0" /> + <stop + id="stop2681" + style="stop-color:#e20800;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 32.977,38.964 C 33.619,37.58 34.903,36.55 35.811,35.945 C 36.752,35.319 37.49,34.55 37.729,33.53 C 38.094,31.979 36.471,30.257 34.621,31.997 C 33.74,29.616 31.507,30.433 31.143,31.984 C 30.903,33.003 31.223,34.019 31.786,35 C 32.329,35.946 33.021,37.439 32.977,38.964 z" + id="path2683" + style="fill:url(#linearGradient3352);fill-opacity:1" /> + <path + d="M 80.223,109.559 L 78.711,109.43 C 78.779,108.969 78.734,108.595 78.58,108.308 C 78.426,108.02 78.205,107.842 77.922,107.776 C 77.61,107.703 77.315,107.782 77.033,108.014 C 76.751,108.246 76.553,108.614 76.433,109.114 C 76.324,109.581 76.341,109.97 76.484,110.284 C 76.629,110.598 76.849,110.79 77.142,110.859 C 77.335,110.904 77.576,110.913 77.865,110.883 L 77.349,112.343 C 76.958,112.242 76.624,112.274 76.345,112.439 C 76.07,112.603 75.886,112.883 75.792,113.279 C 75.714,113.609 75.735,113.887 75.854,114.112 C 75.973,114.339 76.161,114.481 76.416,114.541 C 76.672,114.602 76.918,114.545 77.156,114.372 C 77.394,114.2 77.582,113.906 77.717,113.49 L 79.039,114.106 C 78.689,114.95 78.258,115.521 77.742,115.82 C 77.228,116.119 76.652,116.193 76.013,116.043 C 75.294,115.874 74.783,115.486 74.48,114.876 C 74.175,114.268 74.097,113.653 74.244,113.034 C 74.342,112.616 74.525,112.262 74.795,111.971 C 75.063,111.681 75.418,111.453 75.857,111.289 C 75.445,111.069 75.146,110.725 74.964,110.259 C 74.78,109.793 74.761,109.259 74.902,108.657 C 75.109,107.78 75.541,107.117 76.197,106.666 C 76.855,106.216 77.543,106.075 78.265,106.244 C 78.956,106.406 79.484,106.786 79.849,107.382 C 80.217,107.978 80.34,108.704 80.223,109.559 z" + id="path2694" + style="fill:#e20800;fill-opacity:1" /><path + d="M 81.063,95.83 C 80.422,97.214 79.138,98.244 78.23,98.85 C 77.29,99.477 76.55,100.246 76.311,101.264 C 75.947,102.815 77.57,104.536 79.419,102.797 C 80.301,105.178 82.533,104.361 82.898,102.811 C 83.138,101.791 82.819,100.776 82.255,99.795 C 81.711,98.849 81.021,97.355 81.063,95.83 z" + id="path2701" + style="fill:url(#linearGradient3382);fill-opacity:1" /> + <linearGradient + x1="54.356899" + y1="1.124" + x2="99.964401" + y2="122.481" + id="XMLID_39_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2704" + style="stop-color:#ff8080;stop-opacity:1" + offset="0" /> + <stop + id="stop2706" + style="stop-color:#e20800;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 63.174,42.222 C 64.361,39.656 66.742,37.748 68.427,36.625 C 70.171,35.463 71.54,34.04 71.985,32.15 C 72.66,29.274 69.651,26.081 66.22,29.307 C 64.585,24.892 60.448,26.406 59.772,29.281 C 59.329,31.172 59.921,33.055 60.965,34.873 C 61.97,36.628 63.253,39.396 63.174,42.222 z" + id="path2708" + style="fill:url(#linearGradient3370);fill-opacity:1" /> + <linearGradient + x1="36.838902" + y1="7.7075" + x2="82.446297" + y2="129.0645" + id="XMLID_40_" + xlink:href="#XMLID_39_" + gradientUnits="userSpaceOnUse"> + <stop + id="stop2711" + style="stop-color:#ff8080;stop-opacity:1" + offset="0" /> + <stop + id="stop2713" + style="stop-color:#e20800;stop-opacity:1" + offset="1" /> + </linearGradient> + <path + d="M 55.486,74.959 C 56.672,72.393 59.054,70.485 60.737,69.362 C 62.481,68.2 63.851,66.777 64.296,64.886 C 64.97,62.01 61.962,58.818 58.532,62.043 C 56.897,57.628 52.759,59.142 52.082,62.018 C 51.638,63.908 52.23,65.792 53.275,67.609 C 54.281,69.364 55.565,72.132 55.486,74.959 z" + id="path2715" + style="fill:url(#linearGradient3354);fill-opacity:1" /> + <path + d="M 51.37,92.488 C 50.182,95.054 47.801,96.961 46.117,98.084 C 44.373,99.246 43.004,100.67 42.559,102.561 C 41.884,105.436 44.893,108.627 48.323,105.404 C 49.958,109.82 54.096,108.304 54.772,105.428 C 55.217,103.538 54.623,101.655 53.579,99.836 C 52.573,98.082 51.291,95.314 51.37,92.488 z" + id="path2724" + style="fill:url(#linearGradient3376);fill-opacity:1" /> + </g> +</g> +</svg>
\ No newline at end of file diff --git a/tests/auto/gui/image/qimagereader/images/rect.svgz b/tests/auto/gui/image/qimagereader/images/rect.svgz Binary files differnew file mode 100644 index 0000000000..c2e193b989 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/rect.svgz diff --git a/tests/auto/gui/image/qimagereader/images/rgba_adobedeflate_littleendian.tif b/tests/auto/gui/image/qimagereader/images/rgba_adobedeflate_littleendian.tif Binary files differnew file mode 100644 index 0000000000..78868b0d48 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/rgba_adobedeflate_littleendian.tif diff --git a/tests/auto/gui/image/qimagereader/images/rgba_lzw_littleendian.tif b/tests/auto/gui/image/qimagereader/images/rgba_lzw_littleendian.tif Binary files differnew file mode 100644 index 0000000000..107eab74e7 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/rgba_lzw_littleendian.tif diff --git a/tests/auto/gui/image/qimagereader/images/rgba_nocompression_bigendian.tif b/tests/auto/gui/image/qimagereader/images/rgba_nocompression_bigendian.tif Binary files differnew file mode 100644 index 0000000000..c314bae4c0 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/rgba_nocompression_bigendian.tif diff --git a/tests/auto/gui/image/qimagereader/images/rgba_nocompression_littleendian.tif b/tests/auto/gui/image/qimagereader/images/rgba_nocompression_littleendian.tif Binary files differnew file mode 100644 index 0000000000..4f820f6649 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/rgba_nocompression_littleendian.tif diff --git a/tests/auto/gui/image/qimagereader/images/rgba_packbits_littleendian.tif b/tests/auto/gui/image/qimagereader/images/rgba_packbits_littleendian.tif Binary files differnew file mode 100644 index 0000000000..ddeec38fbc --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/rgba_packbits_littleendian.tif diff --git a/tests/auto/gui/image/qimagereader/images/rgba_zipdeflate_littleendian.tif b/tests/auto/gui/image/qimagereader/images/rgba_zipdeflate_littleendian.tif Binary files differnew file mode 100644 index 0000000000..50a3024246 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/rgba_zipdeflate_littleendian.tif diff --git a/tests/auto/gui/image/qimagereader/images/runners.ppm b/tests/auto/gui/image/qimagereader/images/runners.ppm Binary files differnew file mode 100644 index 0000000000..fda1c97073 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/runners.ppm diff --git a/tests/auto/gui/image/qimagereader/images/teapot.ppm b/tests/auto/gui/image/qimagereader/images/teapot.ppm new file mode 100644 index 0000000000..b8ab85f3a5 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/teapot.ppm @@ -0,0 +1,31 @@ +P6 +256 256 +255 +\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À[7 eOLjQLmSMoTMnSMlRMhPL_9 \À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀnSMtVMzYN~[N~[N\N\O€\O€]O€]O€]O€]O€\O€\O}[NyYNtVM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀG-wXN}[N€]O„^O†_O†`O‡`Oˆ`Oˆ`OˆaO‰aO‰aO‰aO‰aO‰aO‰aOˆaOˆ`O†_Oƒ^O\N\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀaMLyYN…_O‰aP‹bPcPŽcPŽdPŽdPdPdPdPdPdPdPdPeP‘eP’eP’eP‘ePdPcP…_OpUM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀwXN…_OdP“fP•gQ–hQ˜hQ˜iQ™iQ™iQšiQšiQšjQ›jQ›jQœjQœjQœjQœjQœjQ›jQœjQ™iQ“fP‡`O\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJiQL‹bP—hQkQ¡mR¤nR¥oR¥oR¥oR¥oR¥oR¥oR¦oR¦oR¦pR¨pS©qSªqS«rS¬rS«rS©qS¤oRœjQ€]O\KK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀfOLrUMcPŸlR©qS¯tS²uTµwT·xT¸xT¹yTºyT»zT»zU¼zU¼zU¼zU»zUºyT¸xT¶wT¯tS¡mR‰aOhPL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\Àa0 cNLqUM€\O”fQ¦pS²wVºzV¿|VÂ}VÄVÆVÇ€VÉ‚WÌ…[Õeæ w÷³‹êª…Ĉg§qT“fQ{ZNYIK9\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀO1{G#‘JkRMqUMtVN–iS¨v\·€d¹bµzZ±vU°uT®sSªqS¤nRœjQ’eP„^OrUMHh>!T4\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀG-V5wE"~I#†M%U+¥e7²l:°g2®b*a(`(©^(¥])¡^-›]1ŠS,qC$`9 R3G-\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À@)J/i>!pA"tD"wF$yH&xH&tE$wE#yG%}M+ƒT4S5mE*Z7!K/B*;'\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À‰aO¦oR½{UÇ€VÏ…X<(F-a: e<!h>!j@#k@$h>"d<!c=$hD-fF2[<)K0@);'5$Ë‚VÇ€V¿|U_LKYIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À…_O·xTÉ‚Wó«€ûµ‹Ö’k¼|X×>µf-¨^(¡Z'šW&–T&œN>)F-J/b; g>#nD(jB&c<!b=%jH2_A/I0!<(8&5$”J¥Y’S%8&;'?)E,<:HA=HE?IJAISFJYIKXIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À£nRÁ}UܘqÊŠe±vU²e,™V&¥V†C
€@|>y<u:r9o7l6 +j5 +h4 +g3 +5$D,K/b; h>"wM1tK.e="a<#cA,U8&E-<(9&.!a0 b1 c1 + ++3#@)46G<:HMCIXHK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀU*´vT¿~X¸{YÃk+›W&‰N$|>u:p8k5 +f3 +a0 _/ ]. [- I¡\*ª_(‘LkRMmSMmSMnSMnSMD,R3W5mA"|O0|P1j?"c<!a=%Y7"N1F,;'NCJNCJNDJODJODJODJh>!a: X/K% +g3 +a0 Z- \/T*Q(ŠHµm8kRMmSMnTMoTMpTMpUM15G15G05G04G04GpUMpTM5^9 d<!yF#O+€N,rC#qB"pB#k?"a: Z7 6ODJPDJPEJQEJQEJREJREJREJRFJSFJSFJSFJSFJe<!X/ +^/ V+Q(L&I$r9 TlRMnSM46G47G47G46G46G46G46G46G36G36G25G25G15G04G/4F.3F + +X&pUMuWMwXNxXN<:H<:H<:H<:H<;H<;H<;H<;H=;H=;H=;H=;H>;H>;H?<H@<HA=HC>HG@ILBIREJ[JKcNLjQL§pR±uTºzUÃ~VÈWË‚XÖŽcäsÒŽe¼{V²vT¨pSžkR•gQŒbP†_O‚^O]O€\O€\O€\O€\O€]O]O]O]O]O]O]O]O]O]O]O€\O€\O~\N}[N|ZNxXN•T%H$ +›W&rVMvWNyYNzYN|ZN}[N}[N><H?<H?<H?<H?<H?<H@<H@<H@<HA=HA=HB=HC>HE?IG@IIAIKBIODJSFJWHK—hQŸlR§pR°b(¾i*Én+Ù|7Û|6Ïr,Íq+Êp-Ãl+»g)±b(®sS§pS lRšiQ•gQePcPŠaPˆaO‡`O‡`O†_O†_O…_O…_O…_O…_O…_O…_O…_O„_O„^O„^Oƒ^Oƒ^O‚]O]O€\O~[N{ZN•T% + + +@%<-$G?@…pfdNLuWM\NdNL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀTFJvWN‰aP./01„E}[N]O…_Oˆ`O‰aP‹bPŒbPcPcPŽcPdPdPdPeP‘eP’eP’eP“fP“fQ”fQ•gQ•gQ–gQ–hQ—hQ˜hQ™iQšiQ›jQœjQkQkRžlRŸlRžY&¤\'¨^'µ^½bÀcÃeÇi ÄgÀc½b¼a¹`µ^´]¯X¢[' Z'žY&¢mR¡mR¡mR lRŸlRŸlRžkRkQœkQœjQ›jQšjQšiQ™iQ™iQ˜iQ˜hQ—hQ—hQ—hQ–gQ–gQ•gQ•gQ•gQ”fQ”fQ“fQ“fP’eP‘ePdPcP‰aP—O + B\À\À\À\À\À\À\À\À\À\À%7!!C*F#P){dYœze»p€\OgPL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ`LKvWNŠaPm6 + +$5 ¬`(¶e)£nRœjQƒ^OJAI\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀXIK^KKdNLhPLuWM‚]OŒbP”fQeP
m6 +†`OŽcP“fQ—hQ˜hQ™iQšiQšjQ›jQ›jQ›jQœjQœjQœjQœkQkQkQkRžkRžkRžkRžlRŸlRŸlRŸlR lR lR lR¡mR¡mR¡mR¡mRºg)³c(²c(±b(V¿cÂeÅi!Åi!Àd¼bº`¹`·_·_¶^¢Q§]'ª_(`(¹f)£nR£nR£nR£nR£nR£nR£nR¢nR¢nR¢nR¢nR¢nR¢nR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢nR¢mR¢mR£nR¢mR¢mR¡mR mRkR—hQˆGa0 ŠbP mRœjQ“fQ‰aP}[NrUMmSM…L$\À\À\À\À\À\À\À\À B B
#C, 8&H.Z7 §pR›jQ{ZN\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀQEJ[JK`LKdNLhQLqUM{ZN…_OŽcP–gQ—hQ +‹bP‘eP–hQšiQ›jQœjQkQkQkRžkRžkRžlRžlRŸlRŸlRŸlRŸlRŸlR lR lR lR mR¡mR¡mR¡mR¡mR¡mR¢mR¢mR¢mR¢nR£nRÀj*ºg)·e)¶d)Âd°XÅgÅhÂe¿c½b½b¾bªU`(®a(¯a(³c(¾i*¤oR¤oR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤oR¤oR¥oR¥oR¥oR¥oR¥oR¥oR¦oR¦oR¥oR¥oR¤nR¡mR›jQŽQ%Z- œjQ£nRŸlR—hQŽdP…_OuWMpTMnSMkRLa: \À\À\À\À\À\À\À B B&D2
@*S6#G@IPDJ˜hQmSM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀVGJ]KKbMLeOLiQLlRMvWN\OˆaO‘eP—hQœjQ•gQ +!C+E'0F.4F7%8%U/lG.SFJZIK]KKZIKB=H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀREJZJK`LKdNLgPLjQLlRMnSMpTMqUMtWMxXN{ZN~[N]O„^O†`O‰aO‹bPdP•gQ™iQœkQ lR¤nR§pSªrSsS¯tT²uT´vT¶wT·xT¹yT¹yTºyTºyT¹yT¶xT´vT¬rS¢nR—hQ¿|U¿|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ}UÀ}UÁ}UÁ}UÁ}UÁ}UÂ}UÂ~UÃ~UÃ~VÃ~VÄVÅ€WÆX®a(ŸlRªrS´vT¸yT¼zU¾|UÁ~VÃXÆ‚[Ɇ_΋dÓ‘jÔ“mÔ“nБlÊŒhĆd½_¶{[°vWªsU¦pS¢nRžkRšiQ˜hQ•gQ“fQ‘ePdPŒbP‰aO†_Oƒ^O€\O|ZNxXNsVMpTMnTMmSMjQL€C B)D&/F-3F47G6%>"Y7 kA$YIK]KK^KKSFJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀVGJ\KKbMLeOLhPLkRLmSMnTMpTMrUMuWNyYN|ZN\N‚]O„_O‡`OŠaPŒbPŽcPeP“fP—hQ›jQžlR¢nR¥oS©qT¬sT¯uU²vU´wV¶xV¸yV¹yUºzU»zU¼{U½{U¾{U¾|U¿|U¿|U¿|U¿|U¾{U½{U¼{U¼zU»zTºyT¹yT¸xTµwT³vT´vT´vT´vT´wT´wTµwT·xT¹yTºzT¼zU½{U¾{U¿|UÀ|UÂ}UÄVÅ€WÇ‚YÉ„\͈_ÑŒdÙ”láuç£|쩂ſtî‡ëª…æ¦ÞŸ{Õ—sËŽl†d¹^³yZuW¨qU¤oSŸlRžkRœjQšiQ˜hQ–gQ”fQ‘ePdPcPŠaP‡`O„^O]O}[NyYNuWMpTMoTMmSMkRLgPL&D#.E,3F46G;'<(D"iB(VGJ]KK`LK[JKB>H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJYIK^LKcNLfOLiQLkRMmSMoTMqUMsVMvXNzYN}[N€\O‚^O…_Oˆ`OŠaPŒcPdP‘eP“fQ•gQ—hQ™iQkR mS¤oT¨rU¬tW°wY´zZ¸}\»]¾€^À^Á‚^‚^Â\Á€ZÁYÁXÁ~WÁ~WÂ~VÂ~VÂ~VÃ~VÃ~UÃ~UÄ~UÄ~UÄUÄUÅVÅVÅVÅVÆVÆ€VÆ€VÇ€WÇWÈ‚XɃZË…[͇^ЊaÓdØ’iÜ—nâtè£zî©ó¯‡ø´û¸‘üº“û¹“÷¶ñ±Œé©…à¡~Ö˜vËmÇf»€`´z[®vX©rU¥pT£oS¢nS lRžkRœkRšjQ˜iQ–hQ”fQ’ePdPcP‹bPˆ`O…_O‚]O~[NzYNvWNpTMoTMnSMkRMhQLo7,2F36G99HC+@ ]8 nA"\JK`ML_LKSFJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ[JK`LKdNLgPLjQLlRMnSMpTMqUMtVMwXNzZN}[N€]Oƒ^O†_OˆaO‹bPcPdP‘eP“fQ•gQ—hQ™iQ›jRžlR mS£oU§rW¬vZ²{]¹€a¿…fÅŠjËnГqÓ•sÕ–sÕ–rÕ–qÕ”oÓ’mÑjÏgÍŠcˈaɆ^È„\Ç‚[ÆYÅ€XÅ€WÅWÅWÅVÅVÅWÅ€WÆ€WÇXÈ‚YɃ[Ê…\͇_ÏŠaÒeÕ‘hÙ•mÝ™qávä¡zç¤}ê§€ë©ƒëª„é¨ƒå¥€ß |Ù›wÓ•rÌmƉh¿„c¸~^²yZ®vX¬tWªsV¨qU¦pT¤oS¢nS mRžlRœkR›jQ™iQ—hQ•gQ“fPePŽcP‹bPˆaO…_O‚^O\N{ZNwXNsVMoTMnSMlRMiQL~I#26G99G?<HA*E$ i@$ZIKaMLbML[JK;:H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀWHJ]KKbMLeOLhPLjRLlSMnTMpTMrUMuWMxXN{ZN~\N]O„^O†`O‰aO‹bPŽcPdP’eP”fQ–gQ˜hQšiQœkRžlS mT£oU¦rWªuZ¯y]´~aºƒfŠlË’sÔšzÜ¡€ã§†è«‰ë®‹í¯Œí®‹ë¬ˆè¨„ã£~ßžyÚ™tÖ•oÒjÎŒfˈbÈ…_ƃ\ÅZÄ€YÃXÂWÂ~WÂ~WÂ~WÃXÀXÄ€YÅZƃ\Ç…^Ɇ`ˈbÌŠdÍ‹fÎgÎŽiÎŽjÎŽjÍŽjËŒiljgÆd¿ƒaº^¸}]¶|\´{[²yZ°xY®vX¬tWªsV¨qU¦pT¤oS¢nS mRžlRkR›jQ™iQ—hQ•gQ“fP‘ePŽdPŒbP‰aO†_Oƒ^O€\O|ZNxXNtVMpTMnSMmSMjQLgPL99G?<HG-E&b;!YIK`MLdOM`LKNCJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀŸlRºyTÄ~UÊ‚XʃYÄXº{WtUšW'¢[(—hQ lRcP€\OhQL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJYIK^LKcNLfOLiQLkRLmSMoTMqUMrVMvWNyYN|ZN\N‚]O„_O‡`O‰aPŒbPŽcPdP’fP”gQ–hQ˜iQšjRœkRžlS¡nT¤pU§sW«vZ°z]µb»„gŠlÉ‘sИyØžÞ¤…ã©Šèì±ï³‘ﳑëŠç©…⣀ݞzؘtÒ“nÎiɉdÆ…`Â]Á€[¿~Y¾}X½|W½|V¼{V¼{V¼{V¼{V¼{V¼|W¼|W½}X½}Y½~Z½~Z¼~Z»}[º}[º}[º~\º~\º~]º~]¹~]¸~]·}]¶|\´z[²yZ°wY®vX¬tWªsV¨rU¦pT¤oS¢nS mRŸlRkR›jQšiQ˜hQ–gQ“fQ‘ePdPŒcPŠaP‡`O„^O]O}[NyYNuWNpTMnTMmSMkRLhPL|H$D>IQ2P+XHK_LLfQOcNLXIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À©qSºyTÃ~VΈ`遲ޜv¾€]ªqS–LŽG|>g3 +S)?*%.—hQ—hQ‘eP‡`OuWM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ[JK`LKdNLgPLjQLlRMnSMoTMqUMsVMwXNzYN}[N€\O‚^O…_O‡`OŠaPŒbPŽdP‘eP“fP•gQ—hQ˜iQšjRœkRŸlS¡nT¤pV§sX«vZ°z^¶b¼…gËmÊ’sјzØŸ€Þ¤…ã©Šèê¯ë°ê¯Žè¬‹å¨‡à¤‚Ûž|Ö™wÑ“qÌŽlljgÃ…bÀ‚_½\»}Zº{X¹zW¸yV·yU·xU·xU·xT·xT·xU·xU·xU·yV·yV·yW¸zW¸{X¹{Y¹|Zº}[º}[º}\º~\¹~]¹~]¸}]·|\µ{\´z[²yZ°wY®vX¬tWªsV¨rU¦pT¤oS¢nS¡mRŸlRkRœjQšiQ˜hQ–gQ”fQ’ePdPcPŠbP‡`O…_O‚]O~[NzZNvWNrUMoTMmSMlRMiQLeOLJAIJ(h>!]KKfQOgQN_LKD>I\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À™iQ°tS¸yT¼{UÂYÎŒeïˆô´Õ—u¶|\ Z'™LˆD
|> + +
&3#.$-% .% .& /&!,#,#@70A71XNHXNHWNHWNHZRLYQLYQLXQLWQLWPLUOLSNLQMKOLJMJJ0//.-.,,-&(+"(!' +%' %$#" ! !$
diff --git a/tests/auto/gui/image/qimagereader/images/test.ppm b/tests/auto/gui/image/qimagereader/images/test.ppm new file mode 100644 index 0000000000..05d627c0cb --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/test.ppm @@ -0,0 +1,2 @@ +P6 10 10 1023 +¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬
\ No newline at end of file diff --git a/tests/auto/gui/image/qimagereader/images/test.xpm b/tests/auto/gui/image/qimagereader/images/test.xpm new file mode 100644 index 0000000000..5fcf075b7f --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/test.xpm @@ -0,0 +1,260 @@ +/* XPM */ +static char * test_xpm[] = { +"256 256 1 1", +" c grey", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/tests/auto/gui/image/qimagereader/images/test32bfv4.bmp b/tests/auto/gui/image/qimagereader/images/test32bfv4.bmp Binary files differnew file mode 100644 index 0000000000..37060373ed --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/test32bfv4.bmp diff --git a/tests/auto/gui/image/qimagereader/images/test32v5.bmp b/tests/auto/gui/image/qimagereader/images/test32v5.bmp Binary files differnew file mode 100644 index 0000000000..8ad3cfa60d --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/test32v5.bmp diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_1.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_1.tiff Binary files differnew file mode 100644 index 0000000000..3fcb8a9aca --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_1.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_2.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_2.tiff Binary files differnew file mode 100644 index 0000000000..6f3e9d5297 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_2.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_3.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_3.tiff Binary files differnew file mode 100644 index 0000000000..aab9cf2596 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_3.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_4.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_4.tiff Binary files differnew file mode 100644 index 0000000000..aad96ffc6c --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_4.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_5.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_5.tiff Binary files differnew file mode 100644 index 0000000000..05d23dcb86 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_5.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_6.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_6.tiff Binary files differnew file mode 100644 index 0000000000..9ffe7fcaa4 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_6.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_7.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_7.tiff Binary files differnew file mode 100644 index 0000000000..eeeb01937e --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_7.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_8.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_8.tiff Binary files differnew file mode 100644 index 0000000000..87cf2fd774 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/indexed_orientation_8.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_1.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_1.tiff Binary files differnew file mode 100644 index 0000000000..3b589b2232 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_1.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_2.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_2.tiff Binary files differnew file mode 100644 index 0000000000..9a662239db --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_2.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_3.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_3.tiff Binary files differnew file mode 100644 index 0000000000..eed242388c --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_3.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_4.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_4.tiff Binary files differnew file mode 100644 index 0000000000..055480e0ca --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_4.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_5.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_5.tiff Binary files differnew file mode 100644 index 0000000000..b4d0974ec8 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_5.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_6.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_6.tiff Binary files differnew file mode 100644 index 0000000000..3b1e02af56 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_6.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_7.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_7.tiff Binary files differnew file mode 100644 index 0000000000..b752c745c3 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_7.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_8.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_8.tiff Binary files differnew file mode 100644 index 0000000000..e228d05659 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/mono_orientation_8.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_indexed.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_indexed.tiff Binary files differnew file mode 100644 index 0000000000..7507e526a5 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_indexed.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_mono.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_mono.tiff Binary files differnew file mode 100644 index 0000000000..8ff9db80f5 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_mono.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_rgb.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_rgb.tiff Binary files differnew file mode 100644 index 0000000000..321ea3ebf5 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/original_rgb.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_1.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_1.tiff Binary files differnew file mode 100644 index 0000000000..2756a82fbb --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_1.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_2.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_2.tiff Binary files differnew file mode 100644 index 0000000000..ae9af0999d --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_2.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_3.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_3.tiff Binary files differnew file mode 100644 index 0000000000..a2f432526b --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_3.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_4.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_4.tiff Binary files differnew file mode 100644 index 0000000000..f35bfc4c9c --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_4.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_5.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_5.tiff Binary files differnew file mode 100644 index 0000000000..70e5478065 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_5.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_6.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_6.tiff Binary files differnew file mode 100644 index 0000000000..b2635fe14f --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_6.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_7.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_7.tiff Binary files differnew file mode 100644 index 0000000000..1fb0cd9df6 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_7.tiff diff --git a/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_8.tiff b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_8.tiff Binary files differnew file mode 100644 index 0000000000..666b1b4c55 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tiff_oriented/rgb_orientation_8.tiff diff --git a/tests/auto/gui/image/qimagereader/images/transparent.xpm b/tests/auto/gui/image/qimagereader/images/transparent.xpm new file mode 100644 index 0000000000..5ddcf0b00e --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/transparent.xpm @@ -0,0 +1,788 @@ +/* XPM */ +static char *dummy[]={ +"8 8 777 2", +"#R c none", +"fn c #000001", +".e c #000069", +".f c #00006d", +".g c #00006e", +"#d c #0042b4", +"aJ c #010101", +"g0 c #010102", +"dr c #010202", +"gd c #010203", +"#J c #0157bb", +"e. c #020202", +"du c #020304", +"fR c #030303", +"jJ c #040404", +"hf c #040608", +"fE c #040609", +"cO c #04070a", +"k# c #050505", +"gC c #050709", +"ka c #060606", +"br c #06080a", +"dY c #06090d", +"hI c #070707", +"in c #07090b", +"cL c #070a0e", +"cd c #070b0f", +"e0 c #080808", +"gZ c #080b0e", +"eu c #080b0f", +"dz c #080c10", +"hD c #090909", +"fq c #090d11", +"cH c #090e13", +"jB c #0a0a0a", +"#U c #0a0d0f", +"a4 c #0a0d10", +"g3 c #0a0d11", +"fu c #0a0f14", +"cj c #0a1016", +"kb c #0b0b0b", +"#n c #0b0d0f", +"a1 c #0b0e10", +"g8 c #0b0f13", +"f4 c #0b0f14", +"hE c #0c0c0c", +"bf c #0c0f12", +".X c #0c28a0", +"bT c #0d0d0d", +"ax c #0d1014", +"hr c #0d1217", +"dH c #0d141b", +"jy c #0e0e0e", +"aW c #0e1115", +"eH c #0e141b", +"bE c #0f0f0f", +"ar c #0f1317", +"g5 c #0f1419", +"hg c #0f151a", +"fh c #0f151c", +"dJ c #0f171f", +"gI c #101010", +".z c #101094", +"h. c #10161b", +"gm c #10161c", +"eL c #10171f", +"hK c #111111", +"at c #11161b", +"fC c #111820", +"dA c #111922", +"aj c #1163c4", +"bJ c #121212", +"#Z c #12161a", +"ba c #12171c", +"ho c #12181e", +"jK c #131313", +"iq c #13191d", +"cA c #131e2a", +"c7 c #141414", +"dR c #141e29", +"jr c #151515", +"aA c #151a1f", +"hq c #151c23", +"fl c #151e28", +"eV c #151e29", +"d4 c #161616", +"hw c #161e25", +"jk c #171717", +"bs c #171d23", +"g9 c #171f27", +"eC c #17212b", +"b9 c #172432", +"d5 c #181818", +"as c #181e24", +"bn c #181f25", +"bS c #191919", +"gr c #19232d", +"ed c #1a1a1a", +".d c #1a1a6e", +"gB c #1a242e", +"eK c #1a2531", +"dQ c #1a2633", +"hL c #1b1b1b", +"g1 c #1b242d", +"g# c #1b252f", +"eJ c #1b2734", +"d1 c #1b2937", +"bW c #1c1c1c", +"gW c #1c262f", +"ci c #1c2b3b", +"cs c #1c2c3c", +"e# c #1d1d1d", +"#3 c #1d232a", +"f8 c #1d2833", +"fI c #1d2936", +"eO c #1d2a38", +"cw c #1d2e3f", +"jR c #1e1e1e", +"a2 c #1e262e", +"eP c #1e2b39", +"dE c #1e2d3d", +"cF c #1e2f41", +"aO c #1e6ec9", +"c4 c #1f1f1f", +"gx c #1f2a36", +"c# c #1f3043", +"j2 c #202020", +"bk c #202931", +"ht c #202c36", +"eF c #202f3e", +"b7 c #203245", +"cB c #203246", +"hG c #212121", +"aE c #212932", +"bp c #212a32", +"hl c #212d38", +"cc c #213347", +".M c #214eb7", +"hF c #222222", +"#7 c #222a32", +"fw c #223040", +"eU c #223141", +"jC c #232323", +"bb c #232c35", +"ga c #23303d", +"cv c #23364a", +"cn c #23364b", +"jl c #242424", +"gj c #243240", +"cm c #24374c", +"c. c #24384d", +"bF c #252525", +"be c #252f39", +"gt c #253341", +"dU c #253649", +".Y c #256cc9", +"jG c #262626", +"h8 c #26333d", +"hb c #263440", +"gs c #263443", +"cr c #263b51", +"cW c #272727", +"aC c #27313b", +"a9 c #27313c", +"fk c #273748", +"eR c #27384b", +"cq c #273d55", +"jV c #282828", +"#5 c #28313b", +"b0 c #2877ce", +"gL c #292929", +"#Y c #29323c", +"hu c #293744", +"fK c #293a4d", +"jP c #2a2a2a", +"#w c #2a323b", +"bg c #2a3540", +"dF c #2a3f55", +"jn c #2b2b2b", +"a6 c #2b3641", +"jY c #2c2c2c", +"h5 c #2c3b47", +"hp c #2c3c4a", +"gp c #2c3c4d", +"cx c #2c445e", +"bU c #2d2d2d", +"h# c #2d3e4c", +"dS c #2d435b", +"e5 c #2e2e2e", +"cG c #2e4762", +"jF c #2f2f2f", +"aG c #2f3b48", +"gU c #2f3f4e", +"ck c #2f4966", +"j0 c #303030", +"a0 c #303d4a", +"he c #304251", +"cQ c #307ace", +"e4 c #313131", +"ew c #31465d", +"dW c #314862", +"ce c #314b68", +"jm c #323232", +"bm c #323f4d", +"k. c #333333", +"e3 c #343434", +"hi c #344757", +"eT c #344b64", +"b8 c #34506f", +"dj c #347fd1", +"bX c #353535", +"f9 c #35485c", +"ac c #363636", +"#V c #36434f", +"fv c #364c64", +"dV c #36506d", +"c2 c #373737", +"ev c #37506a", +"bI c #383838", +"bw c #384655", +"h4 c #384b5a", +"hk c #384c5d", +"ea c #393939", +"bh c #394857", +"gX c #394d5f", +"#e c #3981d2", +"e6 c #3a3a3a", +"eS c #3a546f", +"em c #3a81d2", +"#F c #3b3b3b", +"eQ c #3b5571", +"dT c #3b5776", +"cI c #3b5c7f", +"gJ c #3c3c3c", +"hX c #3c5060", +"fi c #3c546f", +"gG c #3d3d3d", +"jv c #3e3e3e", +"az c #3e4e5e", +"fL c #3e5772", +"bK c #3f3f3f", +"gD c #3f576f", +"fJ c #3f5874", +"d2 c #3f86d5", +"jx c #404040", +"#8 c #404e5d", +"bv c #405161", +"cf c #406389", +"jL c #414141", +"iG c #415561", +"im c #415663", +"gz c #415971", +"et c #415d7c", +"cz c #41658c", +"f# c #418ad7", +"jT c #424242", +"gy c #425b74", +"fs c #425d7a", +"#K c #4288d4", +"jQ c #434343", +"eX c #438cda", +"j8 c #444444", +".L c #44449a", +"eZ c #454545", +"#s c #455362", +"fx c #45617f", +"cK c #456b94", +"aP c #458cd5", +"ab c #464646", +".n c #46469f", +"aH c #46586a", +"gV c #465f74", +"d0 c #46678c", +"c9 c #474747", +"aF c #47596c", +"a3 c #475a6d", +"ex c #476687", +"jU c #484848", +"by c #485b6e", +"gq c #48627d", +"dI c #486b91", +"cC c #48709b", +"js c #494949", +"#2 c #495a6b", +"ih c #49606f", +"hm c #49637a", +"gk c #49647f", +"j7 c #4a4a4a", +"dt c #4a6e94", +"ak c #4a8dd7", +"b1 c #4a90db", +"c1 c #4b4b4b", +"bx c #4b5f72", +"fr c #4b698a", +"dG c #4b6e95", +"co c #4b75a2", +"fW c #4b91db", +"bD c #4c4c4c", +"hc c #4c687f", +"j6 c #4d4d4d", +"#Q c #4d5f71", +"ik c #4d6676", +"hH c #4e4e4e", +"#0 c #4e5f72", +"aD c #4e6277", +"b. c #4e6377", +"gN c #4e91dc", +"c0 c #4f4f4f", +"bj c #4f6378", +"dZ c #4f759e", +"cD c #4f7aa9", +"hN c #4f8dcd", +"kd c #505050", +"#S c #506275", +"#6 c #506376", +"ge c #506e8c", +"af c #515151", +"b# c #51667b", +"dk c #5195df", +"cT c #525252", +".c c #525280", +"bq c #52677d", +"iH c #526b79", +"fj c #527397", +"eW c #52769d", +"dy c #527aa5", +"hJ c #535353", +"#x c #536476", +"eG c #53789f", +"jM c #545454", +"#r c #546577", +"bz c #546a80", +"dM c #547ca8", +"fP c #5499e2", +"jp c #555555", +"iK c #556f7e", +"bM c #565656", +"fB c #56799f", +"dC c #567fab", +"gE c #569be2", +"cU c #575757", +"h7 c #57748b", +"gc c #577797", +"fN c #577ba1", +"dx c #5780ad", +"cg c #5787bb", +"i4 c #585858", +"iF c #587483", +"hy c #587792", +"g2 c #587893", +"fy c #587ca3", +"eA c #587ea7", +"jW c #595959", +"bu c #597087", +"ia c #5984b2", +"ae c #5a5a5a", +"#t c #5a6c7f", +"bd c #5a7189", +"ij c #5a7789", +"eI c #5a81ab", +"bR c #5b5b5b", +"ch c #5b8dc3", +"en c #5b9be1", +"ke c #5c5c5c", +"cP c #5c8fc5", +"j5 c #5d5d5d", +"iN c #5d7fa0", +"gl c #5d80a3", +"fp c #5d83ac", +"cl c #5d8fc6", +"b2 c #5d9de6", +"c8 c #5e5e5e", +"hh c #5e7f9c", +"hn c #5e809d", +"i3 c #5f5f5f", +"#1 c #5f758c", +"a8 c #5f7890", +"g7 c #5f819e", +"cJ c #5f93cc", +"jz c #606060", +"ct c #6094cd", +"bO c #616161", +"eN c #618cb9", +"jH c #626262", +"iW c #627c8d", +"hd c #6285a3", +"ey c #628dbb", +"dO c #6290c4", +"ca c #6297d1", +"jI c #636363", +"eM c #638fbd", +"jN c #646464", +"fH c #648db9", +"eE c #648fbe", +"cb c #649ad5", +"hA c #64a8e2", +"jw c #656565", +"#k c #65798f", +"fF c #658eba", +"fA c #658fbb", +"fa c #65a4e7", +"b3 c #65a6e8", +"jX c #666666", +"hW c #6688a3", +"gh c #668cb2", +"aI c #6696cb", +"dN c #6697cc", +"bA c #6699ce", +"cu c #669edb", +"#C c #676767", +"f3 c #678db4", +"dl c #67a6eb", +"kc c #686868", +"cS c #696969", +"dK c #699bd2", +"cN c #69a2e0", +"cy c #69a3e1", +"fX c #69a6e8", +"jD c #6a6a6a", +"av c #6a84a1", +"ds c #6a9cd3", +"dL c #6a9cd4", +"jt c #6b6b6b", +"fo c #6b97c6", +"cE c #6ba5e4", +"jS c #6c6c6c", +"aV c #6c88a4", +"ir c #6c8ea4", +"il c #6c8fa5", +"eD c #6c9bce", +"dB c #6c9ed7", +"dq c #6c9fd8", +"cM c #6ca7e7", +"cp c #6ca8e8", +"eo c #6cabed", +"i2 c #6d6d6d", +"#T c #6d869f", +"#W c #6d87a0", +"gY c #6d94b5", +"aa c #6d9bcb", +"eB c #6d9dd0", +"dw c #6da0d9", +"dD c #6da1da", +"b4 c #6dacee", +"h9 c #6dafe2", +"i6 c #6e6e6e", +"bt c #6e8aa7", +"fM c #6e9bcb", +"dP c #6ea3dc", +"b5 c #6eabee", +"jd c #707070", +"ix c #7088a2", +"hx c #7098ba", +"f7 c #7099c3", +"dv c #70a5df", +"b6 c #70adef", +"iy c #70aff1", +"dm c #70aff2", +"jE c #717171", +"#m c #7188a0", +"#u c #7189a1", +"aY c #718eac", +"gO c #71aced", +"jq c #727272", +"gb c #729cc6", +"hO c #72afee", +"ib c #72afef", +"e7 c #737373", +"#y c #738ba4", +"#A c #739eca", +".j c #747474", +"#9 c #748fab", +"hs c #749ec1", +"f6 c #749fca", +".i c #757575", +"#q c #758da6", +"a5 c #7593b1", +"bo c #7594b2", +"ii c #759bb3", +"fb c #75b3f4", +"ep c #75b4f3", +"is c #75b8e2", +"ag c #767676", +"fz c #76a6da", +"ez c #76a9e0", +"dX c #76adeb", +".h c #777777", +".m c #777794", +"iX c #77a6b3", +"dn c #77b1f4", +"gK c #787878", +"#4 c #7894b0", +"fG c #78a9dd", +"j# c #797979", +"bV c #7a7a7a", +"do c #7ab4f4", +"jA c #7b7b7b", +"io c #7ba3bc", +"dp c #7bb5f5", +".k c #7c7c7c", +"bc c #7c9cbd", +"gi c #7caad8", +"aQ c #7cb0e7", +"fY c #7cb8f9", +"iM c #7cbee2", +"j1 c #7d7d7d", +"aX c #7d9ebf", +"fm c #7db0e7", +"j4 c #7e7e7e", +".8 c #7ea5ce", +"#D c #7f7f7f", +"hv c #7facd3", +"gn c #7faedd", +"eb c #808080", +"er c #80bdf9", +"j3 c #818181", +"hz c #81afd6", +"gu c #81b0e0", +"eq c #81bbf9", +"fc c #81bbfc", +"#b c #828282", +"iE c #82aac0", +"i5 c #838383", +"ha c #83b1d9", +"es c #83bcf9", +"ad c #848484", +"go c #84b5e6", +".v c #858585", +"#p c #85a0bc", +"bN c #868686", +"hZ c #86b3d6", +"fD c #86bcf6", +"fO c #86bcf7", +"gP c #86c1ff", +"di c #878787", +"ft c #87bdf8", +"bH c #888888", +"iT c #88cfe2", +"jZ c #898989", +"#z c #89a5c3", +"g. c #89bbee", +"fg c #89c0fc", +"fd c #89c2fd", +"hP c #89c3ff", +"jb c #8a8a8a", +"#o c #8aa6c4", +"jc c #8b8b8b", +".S c #8baccf", +"iI c #8bb6ce", +"al c #8bb9e8", +"hj c #8bbde7", +"gw c #8bbef2", +"ff c #8bc3ff", +"fe c #8bc4ff", +"fZ c #8bc6ff", +"ec c #8c8c8c", +"gv c #8cbff3", +"jO c #8d8d8d", +"a# c #8dadce", +"ic c #8dc7ff", +"#H c #8e8e8e", +"a. c #8eaed0", +"#L c #8ebae8", +"hY c #8ebee3", +"g4 c #8ec1ec", +"iO c #8ecbff", +"ju c #8f8f8f", +"bi c #8fb5da", +"h6 c #8fc0e5", +"f5 c #8fc4f9", +"jf c #909090", +"bl c #90b6dc", +"i1 c #90dfe2", +"bC c #919191", +"aB c #91b5dc", +"aZ c #91b7dd", +"hV c #91c2e8", +"gf c #91c6fc", +"gg c #91c7fd", +"f0 c #91c8ff", +"i7 c #929292", +"gA c #92c8fe", +"iz c #92ccff", +"iU c #939393", +"a7 c #93b9e0", +"f2 c #93c9ff", +"gQ c #93ccff", +"e8 c #949494", +".y c #9494b0", +"h1 c #94c6ec", +"f1 c #94caff", +"j9 c #959595", +"#X c #95b7da", +"cX c #969696", +"ay c #96bbe3", +"#f c #96bde8", +"aR c #96c3ee", +"gR c #96cfff", +".J c #979797", +"hQ c #97cfff", +"fT c #989898", +"#j c #98b6d7", +"#l c #98b7d8", +"iJ c #98c7e1", +"g6 c #98cffd", +"jj c #999999", +"aS c #99c4ee", +"h3 c #99ccf4", +"gS c #99d0ff", +".l c #9a9a9a", +".b c #9a9aa4", +"aw c #9ac1ea", +"gT c #9ad1ff", +"dg c #9b9b9b", +".N c #9bbee8", +"aq c #9bc1eb", +"am c #9bc4ee", +"eg c #9c9c9c", +"au c #9cc3ed", +"ao c #9cc5ee", +"c5 c #9d9d9d", +"aT c #9dc7ef", +"hU c #9dd2fb", +"hR c #9dd3ff", +"dh c #9e9e9e", +"#v c #9ebee0", +".Z c #9ec3e8", +"#M c #9ec3ed", +"#N c #9ec5ed", +"ap c #9ec5ef", +"aU c #9ec7f0", +"h2 c #9ed4fd", +"id c #9ed6ff", +"df c #9f9f9f", +"an c #9fc5ee", +"h0 c #9fd5fe", +"aM c #a0a0a0", +"hT c #a0d6ff", +"jh c #a1a1a1", +"hS c #a1d7ff", +"ji c #a2a2a2", +"#P c #a2c7ed", +"i8 c #a3a3a3", +"#O c #a3c8ed", +"iA c #a3daff", +"j. c #a4a4a4", +"je c #a5a5a5", +"#g c #a5c8ed", +"ip c #a5dafb", +"iv c #a6a6a6", +".F c #a6bed4", +"de c #a7a7a7", +"#h c #a7c9ed", +"if c #a7ddff", +"ie c #a7deff", +"eh c #a8a8a8", +"#i c #a8caee", +"iL c #a8dbf8", +"ig c #a8deff", +"iP c #a8e0ff", +"iY c #a8e2e6", +"hC c #a9a9a9", +".0 c #a9caed", +"#B c #aaaaaa", +"fU c #ababab", +".5 c #abc9e9", +"iB c #abe3ff", +"e2 c #acacac", +".6 c #accaea", +"jo c #adadad", +".1 c #adcbed", +".7 c #adccec", +"iD c #ade2ff", +"iC c #ade3ff", +"fS c #aeaeae", +".4 c #aecded", +"db c #afafaf", +".A c #afbbe7", +".2 c #afccee", +".3 c #afceee", +"d6 c #b0b0b0", +"iQ c #b0e9ff", +"bG c #b1b1b1", +"jg c #b2b2b2", +"#E c #b3b3b3", +".O c #b3d1ed", +"gF c #b4b4b4", +"cY c #b5b5b5", +"iR c #b5ebff", +"hM c #b6b6b6", +"iS c #b6ecff", +"d9 c #b7b7b7", +".U c #b8b8b8", +".u c #b9b9b9", +"dd c #bababa", +".P c #bad4ee", +"bL c #bbbbbb", +".Q c #bbd4ef", +".R c #bbd5f0", +"e9 c #bcbcbc", +"c3 c #bdbdbd", +"f. c #bebebe", +"d8 c #bfbfbf", +".o c #bfc2e8", +"iZ c #bffdff", +"iw c #c0c0c0", +"iV c #c1c1c1", +"i0 c #c1feff", +"ei c #c2c2c2", +"ej c #c3c3c3", +"#a c #c4c4c4", +"el c #c5c5c5", +"d7 c #c6c6c6", +".r c #c6cbda", +"ek c #c7c7c7", +"aN c #c8c8c8", +"#G c #c9c9c9", +"aL c #cacaca", +"ai c #cbcbcb", +".B c #cbddf2", +"bZ c #cccccc", +".C c #cce0f3", +"dc c #cdcdcd", +"ah c #cecece", +"da c #cfcfcf", +".E c #cfe1f3", +".D c #cfe1f4", +"#I c #d0d0d0", +"cV c #d1d1d1", +"fQ c #d2d2d2", +"bB c #d3d3d3", +"#c c #d4d4d4", +"d# c #d5d5d5", +"aK c #d6d6d6", +"cZ c #d7d7d7", +"c6 c #d8d8d8", +"gH c #d9d9d9", +".W c #dadada", +"gM c #dbdbdb", +"bQ c #dcdcdc", +"e1 c #dddddd", +"cR c #dedede", +"d. c #dfdfdf", +"bP c #e0e0e0", +"i# c #e1e1e1", +"bY c #e2e2e2", +".K c #e3e3e3", +"ee c #e4e4e4", +"d3 c #e5e5e5", +"ef c #e6e6e6", +".p c #e6e9f6", +"fV c #e7e7e7", +"eY c #e8e8e8", +".a c #e9e9e9", +".q c #e9edf8", +".V c #eaeaea", +"## c #ebebeb", +"Qt c #ececec", +".w c #ededed", +".x c #eeeeee", +"#. c #efefef", +".# c #f0f0f0", +".9 c #f1f1f1", +".I c #f2f2f2", +".T c #f3f3f3", +"ja c #f4f4f4", +"i9 c #f5f5f5", +"hB c #f6f6f6", +".H c #f7f7f7", +".G c #f8f8f8", +"i. c #f9f9f9", +"kg c #fafafa", +"kf c #fbfbfb", +".t c #fcfcfc", +".s c #fdfdfd", +"it c #fefefe", +"iu c #ffffff", +"#RQtQtQtQtQtQt#R", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"QtQtQtQtQtQtQtQt", +"#RQtQtQtQtQtQt#R"}; diff --git a/tests/auto/gui/image/qimagereader/images/trolltech.gif b/tests/auto/gui/image/qimagereader/images/trolltech.gif Binary files differnew file mode 100644 index 0000000000..f674369efc --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/trolltech.gif diff --git a/tests/auto/gui/image/qimagereader/images/tst7.bmp b/tests/auto/gui/image/qimagereader/images/tst7.bmp Binary files differnew file mode 100644 index 0000000000..6d3ac9241c --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tst7.bmp diff --git a/tests/auto/gui/image/qimagereader/images/tst7.png b/tests/auto/gui/image/qimagereader/images/tst7.png Binary files differnew file mode 100644 index 0000000000..96efae4e79 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/tst7.png diff --git a/tests/auto/gui/image/qimagereader/images/txts.png b/tests/auto/gui/image/qimagereader/images/txts.png Binary files differnew file mode 100755 index 0000000000..99be1eb4f9 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/txts.png diff --git a/tests/auto/gui/image/qimagereader/qimagereader.pro b/tests/auto/gui/image/qimagereader/qimagereader.pro new file mode 100644 index 0000000000..43d587ea48 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/qimagereader.pro @@ -0,0 +1,36 @@ +load(qttest_p4) +SOURCES += tst_qimagereader.cpp +MOC_DIR=tmp +QT += widgets widgets-private core-private gui-private network +RESOURCES += qimagereader.qrc +!symbian:DEFINES += SRCDIR=\\\"$$PWD\\\" + +win32-msvc:QMAKE_CXXFLAGS -= -Zm200 +win32-msvc:QMAKE_CXXFLAGS += -Zm800 +win32-msvc.net:QMAKE_CXXFLAGS -= -Zm300 +win32-msvc.net:QMAKE_CXXFLAGS += -Zm1100 + +wince*: { + images.files = images + images.path = . + + imagePlugins.files = $$QT_BUILD_TREE/plugins/imageformats/*.dll + imagePlugins.path = imageformats + + DEPLOYMENT += images imagePlugins + DEFINES += SRCDIR=\\\".\\\" +} + +symbian: { + images.files = images + images.path = . + + DEPLOYMENT += images + + qt_not_deployed { + imagePlugins.files = qjpeg.dll qgif.dll qmng.dll + imagePlugins.path = imageformats + + DEPLOYMENT += imagePlugins + } +} diff --git a/tests/auto/gui/image/qimagereader/qimagereader.qrc b/tests/auto/gui/image/qimagereader/qimagereader.qrc new file mode 100644 index 0000000000..2c70652389 --- /dev/null +++ b/tests/auto/gui/image/qimagereader/qimagereader.qrc @@ -0,0 +1,71 @@ +<RCC> + <qresource prefix="/"> + <file>images/16bpp.bmp</file> + <file>images/4bpp-rle.bmp</file> + <file>images/YCbCr_cmyk.jpg</file> + <file>images/YCbCr_cmyk.png</file> + <file>images/YCbCr_rgb.jpg</file> + <file>images/away.png</file> + <file>images/ball.mng</file> + <file>images/bat1.gif</file> + <file>images/bat2.gif</file> + <file>images/beavis.jpg</file> + <file>images/black.png</file> + <file>images/black.xpm</file> + <file>images/colorful.bmp</file> + <file>images/corrupt-colors.xpm</file> + <file>images/corrupt-pixels.xpm</file> + <file>images/corrupt.bmp</file> + <file>images/corrupt.gif</file> + <file>images/corrupt.jpg</file> + <file>images/corrupt.mng</file> + <file>images/corrupt.png</file> + <file>images/corrupt.xbm</file> + <file>images/crash-signed-char.bmp</file> + <file>images/earth.gif</file> + <file>images/fire.mng</file> + <file>images/font.bmp</file> + <file>images/gnus.xbm</file> + <file>images/image.pbm</file> + <file>images/image.pgm</file> + <file>images/image.png</file> + <file>images/image.ppm</file> + <file>images/image_100dpi.tif</file> + <file>images/kollada.png</file> + <file>images/marble.xpm</file> + <file>images/namedcolors.xpm</file> + <file>images/negativeheight.bmp</file> + <file>images/noclearcode.bmp</file> + <file>images/noclearcode.gif</file> + <file>images/nontransparent.xpm</file> + <file>images/runners.ppm</file> + <file>images/teapot.ppm</file> + <file>images/test.ppm</file> + <file>images/test.xpm</file> + <file>images/test32bfv4.bmp</file> + <file>images/test32v5.bmp</file> + <file>images/tst7.bmp</file> + <file>images/tst7.png</file> + <file>images/transparent.xpm</file> + <file>images/trolltech.gif</file> + <file>images/qt.gif</file> + <file>images/qt1.gif</file> + <file>images/qt2.gif</file> + <file>images/qt3.gif</file> + <file>images/qt4.gif</file> + <file>images/qt5.gif</file> + <file>images/qt6.gif</file> + <file>images/qt7.gif</file> + <file>images/qt8.gif</file> + <file>images/endless-anim.gif</file> + <file>images/four-frames.gif</file> + <file>images/qt-gif-anim.gif</file> + <file>images/qt-gif-noanim.gif</file> + <file>images/rect.svg</file> + <file>images/rect.svgz</file> + <file>images/corrupt.svg</file> + <file>images/corrupt.svgz</file> + <file>images/qtbug13653-no_eoi.jpg</file> + <file>images/txts.png</file> + </qresource> +</RCC> diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp new file mode 100644 index 0000000000..ffedc69a7f --- /dev/null +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -0,0 +1,2026 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <QBuffer> +#include <QDebug> +#include <QFile> +#include <QImage> +#include <QImageReader> +#include <QImageWriter> +#include <QLabel> +#include <QPixmap> +#include <QSet> +#include <QTcpSocket> +#include <QTcpServer> +#include <QTimer> + +#include "../../../platformquirks.h" + +#if defined(Q_OS_SYMBIAN) +# define SRCDIR "." +#endif + +typedef QMap<QString, QString> QStringMap; +typedef QList<int> QIntList; +Q_DECLARE_METATYPE(QImage) +Q_DECLARE_METATYPE(QRect) +Q_DECLARE_METATYPE(QSize) +Q_DECLARE_METATYPE(QColor) +Q_DECLARE_METATYPE(QStringMap) +Q_DECLARE_METATYPE(QIntList) +Q_DECLARE_METATYPE(QIODevice *) +Q_DECLARE_METATYPE(QImage::Format) + +//TESTED_FILES= + +class tst_QImageReader : public QObject +{ + Q_OBJECT + +public: + tst_QImageReader(); + virtual ~tst_QImageReader(); + +public slots: + void init(); + void cleanup(); + +private slots: + void getSetCheck(); + void readImage_data(); + void readImage(); + void jpegRgbCmyk(); + + void setScaledSize_data(); + void setScaledSize(); + + void setClipRect_data(); + void setClipRect(); + + void setScaledClipRect_data(); + void setScaledClipRect(); + + void imageFormat_data(); + void imageFormat(); + + void blackXPM(); + void transparentXPM(); + void multiWordNamedColorXPM(); + + void supportedFormats(); + + void readFromDevice_data(); + void readFromDevice(); + + void readFromFileAfterJunk_data(); + void readFromFileAfterJunk(); + + void devicePosition_data(); + void devicePosition(); + + void setBackgroundColor_data(); + void setBackgroundColor(); + + void supportsAnimation_data(); + void supportsAnimation(); + + void readFromResources_data(); + void readFromResources(); + + void dotsPerMeter_data(); + void dotsPerMeter(); + + void physicalDpi_data(); + void physicalDpi(); + + void sizeBeforeRead_data(); + void sizeBeforeRead(); + + void sizeBeforeFormat_data(); + void sizeBeforeFormat(); + + void imageFormatBeforeRead_data(); + void imageFormatBeforeRead(); + + void gifHandlerBugs(); + void animatedGif(); + void gifImageCount(); + void gifLoopCount(); + + void readCorruptImage_data(); + void readCorruptImage(); + void readCorruptBmp(); + + void supportsOption_data(); + void supportsOption(); + + void tiffCompression_data(); + void tiffCompression(); + void tiffEndianness(); + + void tiffOrientation_data(); + void tiffOrientation(); + + void tiffGrayscale(); + + void autoDetectImageFormat(); + void fileNameProbing(); + + void pixelCompareWithBaseline_data(); + void pixelCompareWithBaseline(); + + void task255627_setNullScaledSize_data(); + void task255627_setNullScaledSize(); + + void testIgnoresFormatAndExtension_data(); + void testIgnoresFormatAndExtension(); + + void saveFormat_data(); + void saveFormat(); + + void readText_data(); + void readText(); + + void preserveTexts_data(); + void preserveTexts(); +}; + +static const QLatin1String prefix(SRCDIR "/images/"); + +// helper to skip an autotest when the given image format is not supported +#define SKIP_IF_UNSUPPORTED(format) do { \ + if (!QByteArray(format).isEmpty() && !QImageReader::supportedImageFormats().contains(format)) \ + QSKIP("\"" + QByteArray(format) + "\" images are not supported", SkipSingle); \ +} while (0) + +// Testing get/set functions +void tst_QImageReader::getSetCheck() +{ + QImageReader obj1; + // QIODevice * QImageReader::device() + // void QImageReader::setDevice(QIODevice *) + QFile *var1 = new QFile; + obj1.setDevice(var1); + + //A bit strange but that's the only way to compile under windows. + QCOMPARE((QIODevice *) var1, obj1.device()); + obj1.setDevice((QIODevice *)0); + QCOMPARE((QIODevice *) 0, + obj1.device()); + delete var1; +} + +tst_QImageReader::tst_QImageReader() +{ +} + +tst_QImageReader::~tst_QImageReader() +{ + +} + +void tst_QImageReader::init() +{ +} + +void tst_QImageReader::cleanup() +{ +} + +void tst_QImageReader::readImage_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<bool>("success"); + QTest::addColumn<QByteArray>("format"); + + QTest::newRow("empty") << QString() << false << QByteArray(); + QTest::newRow("BMP: colorful") << QString("colorful.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << QString("test32bfv4.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << QString("test32v5.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: font") << QString("font.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: signed char") << QString("crash-signed-char.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: 4bpp RLE") << QString("4bpp-rle.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: 4bpp uncompressed") << QString("tst7.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: 16bpp") << QString("16bpp.bmp") << true << QByteArray("bmp"); + QTest::newRow("BMP: negative height") << QString("negativeheight.bmp") << true << QByteArray("bmp"); + QTest::newRow("XPM: marble") << QString("marble.xpm") << true << QByteArray("xpm"); + QTest::newRow("PNG: kollada") << QString("kollada.png") << true << QByteArray("png"); + QTest::newRow("PPM: teapot") << QString("teapot.ppm") << true << QByteArray("ppm"); + QTest::newRow("PPM: runners") << QString("runners.ppm") << true << QByteArray("ppm"); + QTest::newRow("PPM: test") << QString("test.ppm") << true << QByteArray("ppm"); + QTest::newRow("XBM: gnus") << QString("gnus.xbm") << true << QByteArray("xbm"); + + QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << true << QByteArray("jpeg"); + QTest::newRow("JPEG: qtbug13653") << QString("qtbug13653-no_eoi.jpg") << true << QByteArray("jpeg"); + + QTest::newRow("GIF: earth") << QString("earth.gif") << true << QByteArray("gif"); + QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << true << QByteArray("gif"); + + QTest::newRow("MNG: ball") << QString("ball.mng") << true << QByteArray("mng"); + QTest::newRow("MNG: fire") << QString("fire.mng") << true << QByteArray("mng"); + + QTest::newRow("SVG: rect") << QString("rect.svg") << true << QByteArray("svg"); + QTest::newRow("SVGZ: rect") << QString("rect.svgz") << true << QByteArray("svgz"); +} + +void tst_QImageReader::readImage() +{ + QFETCH(QString, fileName); + QFETCH(bool, success); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + for (int i = 0; i < 2; ++i) { + QImageReader io(prefix + fileName, i ? QByteArray() : format); + if (success) { + if (!io.supportsAnimation()) + QVERIFY(io.imageCount() > 0); + } else { + QCOMPARE(io.imageCount(), -1); + } + QImage image = io.read(); + if (!success) { + QVERIFY(image.isNull()); + return; + } + + QVERIFY2(!image.isNull(), io.errorString().toLatin1().constData()); + + // No format + QImageReader io2(prefix + fileName); + QVERIFY2(!io2.read().isNull(), io.errorString().toLatin1().constData()); + + // No extension, no format + QImageReader io3(prefix + fileName.left(fileName.lastIndexOf(QLatin1Char('.')))); + QVERIFY2(!io3.read().isNull(), io.errorString().toLatin1().constData()); + + // Read into \a image2 + QImage image2; + QImageReader image2Reader(prefix + fileName, i ? QByteArray() : format); + QCOMPARE(image2Reader.format(), format); + QVERIFY(image2Reader.read(&image2)); + if (image2Reader.canRead()) { + if (i) + QVERIFY(!image2Reader.format().isEmpty()); + else + QCOMPARE(image2Reader.format(), format); + } else { + if (i) + QVERIFY(image2Reader.format().isEmpty()); + else + QVERIFY(!image2Reader.format().isEmpty()); + } + QCOMPARE(image, image2); + do { + QVERIFY2(!image.isNull(), io.errorString().toLatin1().constData()); + } while (!(image = io.read()).isNull()); + } +} + +void tst_QImageReader::jpegRgbCmyk() +{ + QImage image1(prefix + QLatin1String("YCbCr_cmyk.jpg")); + QImage image2(prefix + QLatin1String("YCbCr_cmyk.png")); + + if (PlatformQuirks::isImageLoaderImprecise()) { + // first, do some obvious tests + QCOMPARE(image1.height(), image2.height()); + QCOMPARE(image1.width(), image2.width()); + QCOMPARE(image1.format(), image2.format()); + QCOMPARE(image1.format(), QImage::Format_RGB32); + + // compare all the pixels with a slack of 3. This ignores rounding errors in libjpeg/libpng + for (int h = 0; h < image1.height(); ++h) { + const uchar *s1 = image1.constScanLine(h); + const uchar *s2 = image2.constScanLine(h); + for (int w = 0; w < image1.width() * 4; ++w) { + if (*s1 != *s2) { + QVERIFY2(qAbs(*s1 - *s2) <= 3, qPrintable(QString("images differ in line %1, col %2 (image1: %3, image2: %4)").arg(h).arg(w).arg(*s1, 0, 16).arg(*s2, 0, 16))); + } + s1++; + s2++; + } + } + } else { + QCOMPARE(image1, image2); + } +} + +void tst_QImageReader::setScaledSize_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QSize>("newSize"); + QTest::addColumn<QByteArray>("format"); + + QTest::newRow("BMP: colorful") << "colorful" << QSize(200, 200) << QByteArray("bmp"); + QTest::newRow("BMP: font") << "font" << QSize(200, 200) << QByteArray("bmp"); + QTest::newRow("XPM: marble") << "marble" << QSize(200, 200) << QByteArray("xpm"); + QTest::newRow("PNG: kollada") << "kollada" << QSize(200, 200) << QByteArray("png"); + QTest::newRow("PPM: teapot") << "teapot" << QSize(200, 200) << QByteArray("ppm"); + QTest::newRow("PPM: runners") << "runners.ppm" << QSize(400, 400) << QByteArray("ppm"); + QTest::newRow("PPM: test") << "test.ppm" << QSize(10, 10) << QByteArray("ppm"); + QTest::newRow("XBM: gnus") << "gnus" << QSize(200, 200) << QByteArray("xbm"); + + QTest::newRow("JPEG: beavis A") << "beavis" << QSize(200, 200) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis B") << "beavis" << QSize(175, 175) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis C") << "beavis" << QSize(100, 100) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis D") << "beavis" << QSize(100, 200) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis E") << "beavis" << QSize(200, 100) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis F") << "beavis" << QSize(87, 87) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis G") << "beavis" << QSize(50, 45) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis H") << "beavis" << QSize(43, 43) << QByteArray("jpeg"); + QTest::newRow("JPEG: beavis I") << "beavis" << QSize(25, 25) << QByteArray("jpeg"); + + QTest::newRow("GIF: earth") << "earth" << QSize(200, 200) << QByteArray("gif"); + QTest::newRow("GIF: trolltech") << "trolltech" << QSize(200, 200) << QByteArray("gif"); + + QTest::newRow("MNG: ball") << "ball" << QSize(200, 200) << QByteArray("mng"); + QTest::newRow("MNG: fire") << "fire" << QSize(200, 200) << QByteArray("mng"); + + QTest::newRow("SVG: rect") << "rect" << QSize(200, 200) << QByteArray("svg"); + QTest::newRow("SVGZ: rect") << "rect" << QSize(200, 200) << QByteArray("svgz"); +} + +void tst_QImageReader::setScaledSize() +{ + QFETCH(QString, fileName); + QFETCH(QSize, newSize); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImageReader reader(prefix + fileName); + reader.setScaledSize(newSize); + QImage image = reader.read(); + QVERIFY(!image.isNull()); + + QCOMPARE(image.size(), newSize); +} + +void tst_QImageReader::task255627_setNullScaledSize_data() +{ + setScaledSize_data(); +} + +void tst_QImageReader::task255627_setNullScaledSize() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImageReader reader(prefix + fileName); + + // set a null size + reader.setScaledSize(QSize(0, 0)); + reader.setQuality(0); + QImage image = reader.read(); + QVERIFY(image.isNull()); + QCOMPARE(image.size(), QSize(0, 0)); +} + +void tst_QImageReader::setClipRect_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QRect>("newRect"); + QTest::addColumn<QByteArray>("format"); + QTest::newRow("BMP: colorful") << "colorful" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << "test32v5" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: font") << "font" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: 4bpp uncompressed") << "tst7.bmp" << QRect(0, 0, 31, 31) << QByteArray("bmp"); + QTest::newRow("XPM: marble") << "marble" << QRect(0, 0, 50, 50) << QByteArray("xpm"); + QTest::newRow("PNG: kollada") << "kollada" << QRect(0, 0, 50, 50) << QByteArray("png"); + QTest::newRow("PPM: teapot") << "teapot" << QRect(0, 0, 50, 50) << QByteArray("ppm"); + QTest::newRow("PPM: runners") << "runners.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); + QTest::newRow("PPM: test") << "test.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); + QTest::newRow("XBM: gnus") << "gnus" << QRect(0, 0, 50, 50) << QByteArray("xbm"); + + QTest::newRow("JPEG: beavis") << "beavis" << QRect(0, 0, 50, 50) << QByteArray("jpeg"); + + QTest::newRow("GIF: earth") << "earth" << QRect(0, 0, 50, 50) << QByteArray("gif"); + QTest::newRow("GIF: trolltech") << "trolltech" << QRect(0, 0, 50, 50) << QByteArray("gif"); + + QTest::newRow("MNG: ball") << "ball" << QRect(0, 0, 50, 50) << QByteArray("mng"); + QTest::newRow("MNG: fire") << "fire" << QRect(0, 0, 50, 50) << QByteArray("mng"); + + QTest::newRow("SVG: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svg"); + QTest::newRow("SVGZ: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svgz"); +} + +void tst_QImageReader::setClipRect() +{ + QFETCH(QString, fileName); + QFETCH(QRect, newRect); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImageReader reader(prefix + fileName); + reader.setClipRect(newRect); + QImage image = reader.read(); + QVERIFY(!image.isNull()); + QCOMPARE(image.rect(), newRect); + + QImageReader originalReader(prefix + fileName); + QImage originalImage = originalReader.read(); + QCOMPARE(originalImage.copy(newRect), image); +} + +void tst_QImageReader::setScaledClipRect_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QRect>("newRect"); + QTest::addColumn<QByteArray>("format"); + + QTest::newRow("BMP: colorful") << "colorful" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32bfv4") << "test32bfv4" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: test32v5") << "test32v5" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("BMP: font") << "font" << QRect(0, 0, 50, 50) << QByteArray("bmp"); + QTest::newRow("XPM: marble") << "marble" << QRect(0, 0, 50, 50) << QByteArray("xpm"); + QTest::newRow("PNG: kollada") << "kollada" << QRect(0, 0, 50, 50) << QByteArray("png"); + QTest::newRow("PPM: teapot") << "teapot" << QRect(0, 0, 50, 50) << QByteArray("ppm"); + QTest::newRow("PPM: runners") << "runners.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); + QTest::newRow("PPM: test") << "test.ppm" << QRect(0, 0, 50, 50) << QByteArray("ppm"); + QTest::newRow("XBM: gnus") << "gnus" << QRect(0, 0, 50, 50) << QByteArray("xbm"); + + QTest::newRow("JPEG: beavis") << "beavis" << QRect(0, 0, 50, 50) << QByteArray("jpeg"); + + QTest::newRow("GIF: earth") << "earth" << QRect(0, 0, 50, 50) << QByteArray("gif"); + QTest::newRow("GIF: trolltech") << "trolltech" << QRect(0, 0, 50, 50) << QByteArray("gif"); + + QTest::newRow("MNG: ball") << "ball" << QRect(0, 0, 50, 50) << QByteArray("mng"); + QTest::newRow("MNG: fire") << "fire" << QRect(0, 0, 50, 50) << QByteArray("mng"); + + QTest::newRow("SVG: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svg"); + QTest::newRow("SVGZ: rect") << "rect" << QRect(0, 0, 50, 50) << QByteArray("svgz"); +} + +void tst_QImageReader::setScaledClipRect() +{ + QFETCH(QString, fileName); + QFETCH(QRect, newRect); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImageReader reader(prefix + fileName); + reader.setScaledSize(QSize(300, 300)); + reader.setScaledClipRect(newRect); + QImage image = reader.read(); + QVERIFY(!image.isNull()); + QCOMPARE(image.rect(), newRect); + + QImageReader originalReader(prefix + fileName); + originalReader.setScaledSize(QSize(300, 300)); + QImage originalImage = originalReader.read(); + QCOMPARE(originalImage.copy(newRect), image); +} + +void tst_QImageReader::imageFormat_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("format"); + QTest::addColumn<QImage::Format>("imageFormat"); + + QTest::newRow("pbm") << QString("image.pbm") << QByteArray("pbm") << QImage::Format_Mono; + QTest::newRow("pgm") << QString("image.pgm") << QByteArray("pgm") << QImage::Format_Indexed8; + QTest::newRow("ppm-1") << QString("image.ppm") << QByteArray("ppm") << QImage::Format_RGB32; + QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm") << QImage::Format_RGB32; + QTest::newRow("ppm-3") << QString("runners.ppm") << QByteArray("ppm") << QImage::Format_RGB32; + QTest::newRow("ppm-4") << QString("test.ppm") << QByteArray("ppm") << QImage::Format_RGB32; + + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg") << QImage::Format_Indexed8; + QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg") << QImage::Format_RGB32; + QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg") << QImage::Format_RGB32; + + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif") << QImage::Format_Invalid; + QTest::newRow("gif-2") << QString("trolltech.gif") << QByteArray("gif") << QImage::Format_Invalid; + + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm") << QImage::Format_MonoLSB; + QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm") << QImage::Format_Indexed8; + QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp") << QImage::Format_Indexed8; + QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp") << QImage::Format_Indexed8; + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp") << QImage::Format_RGB32; + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp") << QImage::Format_RGB32; + QTest::newRow("png") << QString("kollada.png") << QByteArray("png") << QImage::Format_ARGB32; + QTest::newRow("png-2") << QString("YCbCr_cmyk.png") << QByteArray("png") << QImage::Format_RGB32; + QTest::newRow("mng-1") << QString("ball.mng") << QByteArray("mng") << QImage::Format_Invalid; + QTest::newRow("mng-2") << QString("fire.mng") << QByteArray("mng") << QImage::Format_Invalid; + QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg") << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz") << QImage::Format_ARGB32_Premultiplied; +} + +void tst_QImageReader::imageFormat() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + QFETCH(QImage::Format, imageFormat); + + SKIP_IF_UNSUPPORTED(format); + + QCOMPARE(QImageReader::imageFormat(prefix + fileName), format); + QImageReader reader(prefix + fileName); + QCOMPARE(reader.imageFormat(), imageFormat); +} + +void tst_QImageReader::blackXPM() +{ + QImage image(prefix + QLatin1String("black.xpm")); + QImage image2(prefix + QLatin1String("black.png")); + QCOMPARE(image.pixel(25, 25), qRgb(190, 190, 190)); + QCOMPARE(image.pixel(25, 25), image2.pixel(25, 25)); +} + +void tst_QImageReader::transparentXPM() +{ + QImage image(prefix + QLatin1String("nontransparent.xpm")); + QImage image2(prefix + QLatin1String("transparent.xpm")); + QCOMPARE(image.format(), QImage::Format_RGB32); + QCOMPARE(image2.format(), QImage::Format_ARGB32); +} + +void tst_QImageReader::multiWordNamedColorXPM() +{ + QImage image(prefix + QLatin1String("namedcolors.xpm")); + QCOMPARE(image.pixel(0, 0), qRgb(102, 139, 139)); // pale turquoise 4 + QCOMPARE(image.pixel(0, 1), qRgb(250, 250, 210)); // light golden rod yellow + QCOMPARE(image.pixel(0, 2), qRgb(255, 250, 205)); // lemon chiffon +} + +void tst_QImageReader::supportedFormats() +{ + QList<QByteArray> formats = QImageReader::supportedImageFormats(); + QList<QByteArray> sortedFormats = formats; + qSort(sortedFormats); + + // check that the list is sorted + QCOMPARE(formats, sortedFormats); + + QSet<QByteArray> formatSet; + foreach (QByteArray format, formats) + formatSet << format; + + // check that the list does not contain duplicates + QCOMPARE(formatSet.size(), formats.size()); +} + +void tst_QImageReader::setBackgroundColor_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QColor>("color"); + + QTest::newRow("BMP: colorful") << QString("colorful.bmp") << QColor(Qt::white); + QTest::newRow("BMP: font") << QString("font.bmp") << QColor(Qt::black); + QTest::newRow("BMP: signed char") << QString("crash-signed-char.bmp") << QColor(Qt::red); + QTest::newRow("XPM: marble") << QString("marble.xpm") << QColor(Qt::darkRed); + QTest::newRow("PNG: kollada") << QString("kollada.png") << QColor(Qt::green); + QTest::newRow("PPM: teapot") << QString("teapot.ppm") << QColor(Qt::darkGreen); + QTest::newRow("PPM: runners") << QString("runners.ppm") << QColor(Qt::red); + QTest::newRow("PPM: test") << QString("test.ppm") << QColor(Qt::white); + QTest::newRow("XBM: gnus") << QString("gnus.xbm") << QColor(Qt::blue); + + QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << QColor(Qt::darkBlue); + + QTest::newRow("GIF: earth") << QString("earth.gif") << QColor(Qt::cyan); + QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << QColor(Qt::magenta); + + QTest::newRow("MNG: ball") << QString("ball.mng") << QColor(Qt::yellow); + QTest::newRow("MNG: fire") << QString("fire.mng") << QColor(Qt::gray); + + QTest::newRow("SVG: rect") << QString("rect.svg") << QColor(Qt::darkGreen); + QTest::newRow("SVGZ: rect") << QString("rect.svgz") << QColor(Qt::darkGreen); +} + +void tst_QImageReader::setBackgroundColor() +{ + QFETCH(QString, fileName); + QFETCH(QColor, color); + QImageReader io("images/" + fileName); + io.setBackgroundColor(color); + if (io.backgroundColor().isValid()) + QCOMPARE(io.backgroundColor(), color); +} + +void tst_QImageReader::supportsAnimation_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<bool>("success"); + + QTest::newRow("BMP: colorful") << QString("colorful.bmp") << false; + QTest::newRow("BMP: font") << QString("font.bmp") << false; + QTest::newRow("BMP: signed char") << QString("crash-signed-char.bmp") << false; + QTest::newRow("BMP: test32bfv4") << QString("test32bfv4.bmp") << false;; + QTest::newRow("BMP: test32v5") << QString("test32v5.bmp") << false; + QTest::newRow("XPM: marble") << QString("marble.xpm") << false; + QTest::newRow("PNG: kollada") << QString("kollada.png") << false; + QTest::newRow("PPM: teapot") << QString("teapot.ppm") << false; + QTest::newRow("PPM: teapot") << QString("teapot.ppm") << false; + QTest::newRow("PPM: runners") << QString("runners.ppm") << false; + QTest::newRow("XBM: gnus") << QString("gnus.xbm") << false; + + QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << false; + + QTest::newRow("GIF: earth") << QString("earth.gif") << true; + QTest::newRow("GIF: trolltech") << QString("trolltech.gif") << true; + + QTest::newRow("MNG: ball") << QString("ball.mng") << true; + QTest::newRow("MNG: fire") << QString("fire.mng") << true; + + QTest::newRow("SVG: rect") << QString("rect.svg") << false; + QTest::newRow("SVGZ: rect") << QString("rect.svgz") << false; +} + +void tst_QImageReader::supportsAnimation() +{ + QFETCH(QString, fileName); + QFETCH(bool, success); + QImageReader io(prefix + fileName); + QCOMPARE(io.supportsAnimation(), success); +} + +void tst_QImageReader::sizeBeforeRead_data() +{ + imageFormat_data(); +} + +void tst_QImageReader::sizeBeforeRead() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImageReader reader(prefix + fileName); + QVERIFY(reader.canRead()); + if (format == "mng") { + QCOMPARE(reader.size(), QSize()); + return; + } + + QSize size = reader.size(); + QVERIFY(reader.canRead()); + QImage image = reader.read(); + QVERIFY(!image.isNull()); + QCOMPARE(size, image.size()); +} + +void tst_QImageReader::sizeBeforeFormat_data() +{ + imageFormat_data(); +} + +void tst_QImageReader::sizeBeforeFormat() +{ + QFETCH(QString, fileName); + + QByteArray formatA, formatB; + + { + QImageReader reader(prefix + fileName); + formatA = reader.format(); + } + + { + QImageReader reader(prefix + fileName); + QSize size = reader.size(); + formatB = reader.format(); + } + + QCOMPARE(formatA, formatB); +} + +void tst_QImageReader::imageFormatBeforeRead_data() +{ + imageFormat_data(); +} + +void tst_QImageReader::imageFormatBeforeRead() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + QFETCH(QImage::Format, imageFormat); + + SKIP_IF_UNSUPPORTED(format); + + QImageReader reader(fileName); + if (reader.supportsOption(QImageIOHandler::ImageFormat)) { + QImage::Format fileFormat = reader.imageFormat(); + QCOMPARE(fileFormat, imageFormat); + QSize size = reader.size(); + QImage image(size, fileFormat); + QVERIFY(reader.read(&image)); + QCOMPARE(image.format(), fileFormat); + } +} + +void tst_QImageReader::gifHandlerBugs() +{ + SKIP_IF_UNSUPPORTED("gif"); + + { + QImageReader io(prefix + "trolltech.gif"); + QVERIFY(io.loopCount() != 1); + int count=0; + for (; io.canRead(); io.read(), ++count) ; + QVERIFY(count == 34); + } + + // Task 95166 + { + QImageReader io1(prefix + "bat1.gif"); + QImageReader io2(prefix + "bat2.gif"); + QVERIFY(io1.canRead()); + QVERIFY(io2.canRead()); + QImage im1 = io1.read(); + QImage im2 = io2.read(); + QVERIFY(!im1.isNull()); + QVERIFY(!im2.isNull()); + QCOMPARE(im1, im2); + } + + // Task 9994 + { + QImageReader io1(prefix + "noclearcode.gif"); + QImageReader io2(prefix + "noclearcode.bmp"); + QVERIFY(io1.canRead()); QVERIFY(io2.canRead()); + QImage im1 = io1.read(); QImage im2 = io2.read(); + QVERIFY(!im1.isNull()); QVERIFY(!im2.isNull()); + QCOMPARE(im1.convertToFormat(QImage::Format_ARGB32), im2.convertToFormat(QImage::Format_ARGB32)); + } + + // Check the undocumented feature. + { + QImageReader io(prefix + "endless-anim.gif"); + QVERIFY(io.canRead()); + QCOMPARE(io.loopCount(), -1); + } +} + +void tst_QImageReader::animatedGif() +{ + SKIP_IF_UNSUPPORTED("gif"); + + QImageReader io(":images/qt.gif"); + QImage image = io.read(); + QVERIFY(!image.isNull()); + int i = 0; + while(!image.isNull()){ + QString frameName = QString(":images/qt%1.gif").arg(++i); + QCOMPARE(image, QImage(frameName)); + image = io.read(); + } +} + +// http://bugreports.qt.nokia.com/browse/QTBUG-6696 +// Check the count of images in various call orders... +void tst_QImageReader::gifImageCount() +{ + SKIP_IF_UNSUPPORTED("gif"); + + // just read every frame... and see how much we got.. + { + QImageReader io(":images/four-frames.gif"); + + QVERIFY(io.canRead()); + QImage blackFrame = io.read(); + + QVERIFY(io.canRead()); + QImage whiteFrame = io.read(); + + QVERIFY(io.canRead()); + QImage greenFrame = io.read(); + + QVERIFY(io.imageCount() == 4); + + QVERIFY(io.canRead()); + QImage blueFrame = io.read(); + + QVERIFY(!io.canRead()); + QImage emptyFrame = io.read(); + + QVERIFY(!io.canRead()); + QCOMPARE(blackFrame.pixel(0,0), qRgb(0, 0, 0)); + QCOMPARE(blackFrame.size(), QSize(64,64)); + + QCOMPARE(whiteFrame.pixel(0,0), qRgb(0xff, 0xff, 0xff)); + QCOMPARE(whiteFrame.size(), QSize(64,64)); + + QCOMPARE(greenFrame.pixel(0,0), qRgb(0x0, 0xff, 0x0)); + QCOMPARE(greenFrame.size(), QSize(64,64)); + + QCOMPARE(blueFrame.pixel(0,0), qRgb(0x0, 0x0, 0xff)); + QCOMPARE(blueFrame.size(), QSize(64,64)); + QVERIFY(emptyFrame.isNull()); + } + + // Read and get the size + { + QImageReader io(":images/four-frames.gif"); + + QVERIFY(io.canRead()); + QCOMPARE(io.size(), QSize(64,64)); + + QVERIFY(io.canRead()); + QCOMPARE(io.size(), QSize(64,64)); + QCOMPARE(io.size(), QSize(64,64)); + QVERIFY(io.canRead()); + QImage blackFrame = io.read(); + + QVERIFY(io.canRead()); + QCOMPARE(io.size(), QSize(64,64)); + QCOMPARE(io.size(), QSize(64,64)); + QVERIFY(io.canRead()); + QImage whiteFrame = io.read(); + + QVERIFY(io.canRead()); + QCOMPARE(io.size(), QSize(64,64)); + QCOMPARE(io.size(), QSize(64,64)); + QVERIFY(io.canRead()); + QImage greenFrame = io.read(); + + QVERIFY(io.canRead()); + QCOMPARE(io.size(), QSize(64,64)); + QCOMPARE(io.size(), QSize(64,64)); + QVERIFY(io.canRead()); + QImage blueFrame = io.read(); + + QVERIFY(!io.canRead()); + QCOMPARE(io.size(), QSize()); + QCOMPARE(io.size(), QSize()); + QVERIFY(!io.canRead()); + QImage emptyFrame = io.read(); + + QVERIFY(!io.canRead()); + QCOMPARE(blackFrame.pixel(0,0), qRgb(0, 0, 0)); + QCOMPARE(blackFrame.size(), QSize(64,64)); + + QCOMPARE(whiteFrame.pixel(0,0), qRgb(0xff, 0xff, 0xff)); + QCOMPARE(whiteFrame.size(), QSize(64,64)); + + QCOMPARE(greenFrame.pixel(0,0), qRgb(0x0, 0xff, 0x0)); + QCOMPARE(greenFrame.size(), QSize(64,64)); + + QCOMPARE(blueFrame.pixel(0,0), qRgb(0x0, 0x0, 0xff)); + QCOMPARE(blueFrame.size(), QSize(64,64)); + QVERIFY(emptyFrame.isNull()); + } + + // Do a Size query as substitute for canRead + { + QImageReader io(":images/four-frames.gif"); + + QCOMPARE(io.size(), QSize(64,64)); + QCOMPARE(io.size(), QSize(64,64)); + QImage blackFrame = io.read(); + + QCOMPARE(io.size(), QSize(64,64)); + QCOMPARE(io.size(), QSize(64,64)); + QImage whiteFrame = io.read(); + + QCOMPARE(io.size(), QSize(64,64)); + QCOMPARE(io.size(), QSize(64,64)); + QImage greenFrame = io.read(); + + QCOMPARE(io.size(), QSize(64,64)); + QCOMPARE(io.size(), QSize(64,64)); + QImage blueFrame = io.read(); + + QCOMPARE(io.size(), QSize()); + QVERIFY(!io.canRead()); + QImage emptyFrame = io.read(); + + QVERIFY(!io.canRead()); + QCOMPARE(blackFrame.pixel(0,0), qRgb(0, 0, 0)); + QCOMPARE(blackFrame.size(), QSize(64,64)); + + QCOMPARE(whiteFrame.pixel(0,0), qRgb(0xff, 0xff, 0xff)); + QCOMPARE(whiteFrame.size(), QSize(64,64)); + + QCOMPARE(greenFrame.pixel(0,0), qRgb(0x0, 0xff, 0x0)); + QCOMPARE(greenFrame.size(), QSize(64,64)); + + QCOMPARE(blueFrame.pixel(0,0), qRgb(0x0, 0x0, 0xff)); + QCOMPARE(blueFrame.size(), QSize(64,64)); + QVERIFY(emptyFrame.isNull()); + } + { + QImageReader io(":images/trolltech.gif"); + QVERIFY(io.imageCount() == 34); + QVERIFY(io.size() == QSize(128,64)); + } +} + +void tst_QImageReader::gifLoopCount() +{ + SKIP_IF_UNSUPPORTED("gif"); + + { + QImageReader io(":images/qt-gif-anim.gif"); + QCOMPARE(io.loopCount(), -1); // infinite loop + } + { + QImageReader io(":images/qt-gif-noanim.gif"); + QCOMPARE(io.loopCount(), 0); // no loop + } +} + +class Server : public QObject +{ + Q_OBJECT +public: + Server(const QByteArray &data) :serverSocket(0) + { + connect(&server, SIGNAL(newConnection()), this, SLOT(acceptNewConnection())); + server.listen(); + this->data = data; + } + +public slots: + void runTest() + { + connect(&clientSocket, SIGNAL(connected()), this, SLOT(connected())); + clientSocket.connectToHost(QHostAddress::LocalHost, server.serverPort()); + } + +public: + inline QTcpSocket *socket() const { return serverSocket; } + +signals: + void ready(); + +private slots: + void acceptNewConnection() + { + serverSocket = server.nextPendingConnection(); + connect(serverSocket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(remoteHostClosed())); + } + + void connected() + { + clientSocket.write(data); + clientSocket.disconnectFromHost(); + } + + void remoteHostClosed() + { + emit ready(); + } + +private: + QTcpServer server; + QTcpSocket clientSocket; + QTcpSocket *serverSocket; + QByteArray data; +}; + +void tst_QImageReader::readFromDevice_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("format"); + + QTest::newRow("pbm") << QString("image.pbm") << QByteArray("pbm"); + QTest::newRow("pgm") << QString("image.pgm") << QByteArray("pgm"); + QTest::newRow("ppm-1") << QString("image.ppm") << QByteArray("ppm"); + QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm"); + QTest::newRow("ppm-3") << QString("teapot.ppm") << QByteArray("ppm"); + QTest::newRow("ppm-4") << QString("runners.ppm") << QByteArray("ppm"); + + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-4") << QString("qtbug13653-no_eoi.jpg") << QByteArray("jpeg"); + + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif"); + QTest::newRow("gif-2") << QString("trolltech.gif") << QByteArray("gif"); + + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); + QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); + QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); + QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); + + QTest::newRow("mng-1") << QString("ball.mng") << QByteArray("mng"); + QTest::newRow("mng-2") << QString("fire.mng") << QByteArray("mng"); + + QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); + QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); +} + +void tst_QImageReader::readFromDevice() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImage expectedImage(prefix + fileName, format); + + QFile file(prefix + fileName); + QVERIFY(file.open(QFile::ReadOnly)); + QByteArray imageData = file.readAll(); + QVERIFY(!imageData.isEmpty()); + { + QBuffer buffer; + buffer.setData(imageData); + QVERIFY(buffer.open(QBuffer::ReadOnly)); + + QImageReader reader(&buffer); + QVERIFY(reader.canRead()); + QImage imageReaderImage = reader.read(); + + QCOMPARE(imageReaderImage, expectedImage); + + buffer.seek(0); + + QImage image1; + QVERIFY(image1.loadFromData((const uchar *)buffer.data().data(), + buffer.data().size(), format.data())); + QCOMPARE(image1, expectedImage); + + QByteArray throughBase64 = QByteArray::fromBase64(imageData.toBase64()); + QVERIFY(image1.loadFromData((const uchar *)throughBase64.data(), + throughBase64.size(), format.data())); + QCOMPARE(image1, expectedImage); + } + +#if defined (Q_OS_SYMBIAN) && defined (__WINS__) + //the emulator hangs in socket write (this is a test bug, it assumes the TCP stack can accept a whole image to its buffers) + if(imageData.size() > 16384) + QSKIP("image larger than socket buffer (test needs to be rewritten)", SkipSingle); +#endif + Server server(imageData); + QEventLoop loop; + connect(&server, SIGNAL(ready()), &loop, SLOT(quit())); + QTimer::singleShot(0, &server, SLOT(runTest())); + QTimer::singleShot(5000, &loop, SLOT(quit())); + loop.exec(); + + QImageReader reader(server.socket(), format == "xbm" ? "xbm" : ""); + if (format == "xbm") + QVERIFY(!reader.canRead()); + else + QVERIFY(reader.canRead()); + QImage imageReaderImage = reader.read(); + QCOMPARE(imageReaderImage, expectedImage); +} + +void tst_QImageReader::readFromFileAfterJunk_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("format"); + + QTest::newRow("pbm") << QString("image.pbm") << QByteArray("pbm"); + QTest::newRow("pgm") << QString("image.pgm") << QByteArray("pgm"); + QTest::newRow("ppm-1") << QString("image.ppm") << QByteArray("ppm"); + QTest::newRow("ppm-2") << QString("teapot.ppm") << QByteArray("ppm"); + QTest::newRow("ppm-3") << QString("teapot.ppm") << QByteArray("ppm"); + QTest::newRow("ppm-4") << QString("runners.ppm") << QByteArray("ppm"); + + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); + + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); + QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); + QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); + QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); + QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); + QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); +} + +void tst_QImageReader::readFromFileAfterJunk() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QFile::remove("junk"); + QFile junkFile("junk"); + QVERIFY(junkFile.open(QFile::WriteOnly)); + + QFile imageFile(prefix + fileName); + QVERIFY(imageFile.open(QFile::ReadOnly)); + QByteArray imageData = imageFile.readAll(); + QVERIFY(!imageData.isNull()); + + int iterations = 3; + if (format == "ppm" || format == "pbm" || format == "pgm" || format == "svg" || format == "svgz") + iterations = 1; + + if (format == "mng" || !QImageWriter::supportedImageFormats().contains(format)) { + for (int i = 0; i < iterations; ++i) { + junkFile.write("deadbeef", 9); + QCOMPARE(junkFile.write(imageData), qint64(imageData.size())); + } + } else { + for (int i = 0; i < iterations; ++i) { + QImageWriter writer(&junkFile, format); + junkFile.write("deadbeef", 9); + QVERIFY(writer.write(QImage(prefix + fileName))); + } + } + junkFile.close(); + junkFile.open(QFile::ReadOnly); + + for (int i = 0; i < iterations; ++i) { + QByteArray ole = junkFile.read(9); + junkFile.ungetChar(ole[ole.size() - 1]); + char c; + junkFile.getChar(&c); + QImageReader reader(&junkFile); + QVERIFY(reader.canRead()); + QVERIFY(!reader.read().isNull()); + } +} + +void tst_QImageReader::devicePosition_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("format"); + + QTest::newRow("pbm") << QString("image.pbm") << QByteArray("pbm"); + QTest::newRow("pgm") << QString("image.pgm") << QByteArray("pgm"); + QTest::newRow("ppm-1") << QString("image.ppm") << QByteArray("ppm"); + + QTest::newRow("jpeg-1") << QString("beavis.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-2") << QString("YCbCr_cmyk.jpg") << QByteArray("jpeg"); + QTest::newRow("jpeg-3") << QString("YCbCr_rgb.jpg") << QByteArray("jpeg"); + + QTest::newRow("gif-1") << QString("earth.gif") << QByteArray("gif"); + + QTest::newRow("xbm") << QString("gnus.xbm") << QByteArray("xbm"); + QTest::newRow("xpm") << QString("marble.xpm") << QByteArray("xpm"); + QTest::newRow("bmp-1") << QString("colorful.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-2") << QString("font.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-3") << QString("test32bfv4.bmp") << QByteArray("bmp"); + QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp"); + QTest::newRow("png") << QString("kollada.png") << QByteArray("png"); + QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg"); + QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz"); +} + +void tst_QImageReader::devicePosition() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImage expected(prefix + fileName); + QVERIFY(!expected.isNull()); + + QFile imageFile(prefix + fileName); + QVERIFY(imageFile.open(QFile::ReadOnly)); + QByteArray imageData = imageFile.readAll(); + QVERIFY(!imageData.isNull()); + int imageDataSize = imageData.size(); + + const char *preStr = "prebeef\n"; + int preLen = qstrlen(preStr); + imageData.prepend(preStr); + if (format != "svg" && format != "svgz") // Doesn't handle trailing data + imageData.append("\npostbeef"); + QBuffer buf(&imageData); + buf.open(QIODevice::ReadOnly); + buf.seek(preLen); + QImageReader reader(&buf, format); + QCOMPARE(expected, reader.read()); + if (format != "ppm" && + format != "pgm" && + format != "pbm" && + format != "gif") // Known not to work + QCOMPARE(buf.pos(), qint64(preLen+imageDataSize)); +} + + +void tst_QImageReader::readFromResources_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("format"); + QTest::addColumn<QSize>("size"); + QTest::addColumn<QString>("message"); + + QTest::newRow("corrupt.bmp") << QString("corrupt.bmp") + << QByteArray("bmp") << QSize(0, 0) + << QString(""); + QTest::newRow("negativeheight.bmp") << QString("negativeheight.bmp") + << QByteArray("bmp") << QSize(127, 64) + << QString(""); + QTest::newRow("font.bmp") << QString("font.bmp") + << QByteArray("bmp") << QSize(240, 8) + << QString(""); + QTest::newRow("noclearcode.bmp") << QString("noclearcode.bmp") + << QByteArray("bmp") << QSize(29, 18) + << QString(""); + QTest::newRow("colorful.bmp") << QString("colorful.bmp") + << QByteArray("bmp") << QSize(320, 200) + << QString(""); + QTest::newRow("16bpp.bmp") << QString("16bpp.bmp") + << QByteArray("bmp") << QSize(320, 240) + << QString(""); + QTest::newRow("crash-signed-char.bmp") << QString("crash-signed-char.bmp") + << QByteArray("bmp") << QSize(360, 280) + << QString(""); + QTest::newRow("4bpp-rle.bmp") << QString("4bpp-rle.bmp") + << QByteArray("bmp") << QSize(640, 480) + << QString(""); + QTest::newRow("test32bfv4.bmp") << QString("test32bfv4.bmp") + << QByteArray("bmp") << QSize(373, 156) + << QString(""); + QTest::newRow("test32v5.bmp") << QString("test32v5.bmp") + << QByteArray("bmp") << QSize(373, 156) + << QString(""); + QTest::newRow("corrupt.gif") << QString("corrupt.gif") + << QByteArray("gif") << QSize(0, 0) + << QString(""); + QTest::newRow("trolltech.gif") << QString("trolltech.gif") + << QByteArray("gif") << QSize(128, 64) + << QString(""); + QTest::newRow("noclearcode.gif") << QString("noclearcode.gif") + << QByteArray("gif") << QSize(29, 18) + << QString(""); + QTest::newRow("earth.gif") << QString("earth.gif") + << QByteArray("gif") << QSize(320, 200) + << QString(""); + QTest::newRow("bat1.gif") << QString("bat1.gif") + << QByteArray("gif") << QSize(32, 32) + << QString(""); + QTest::newRow("bat2.gif") << QString("bat2.gif") + << QByteArray("gif") << QSize(32, 32) + << QString(""); + QTest::newRow("corrupt.jpg") << QString("corrupt.jpg") + << QByteArray("jpg") << QSize(0, 0) + << QString("JPEG datastream contains no image"); + QTest::newRow("beavis.jpg") << QString("beavis.jpg") + << QByteArray("jpg") << QSize(350, 350) + << QString(""); + QTest::newRow("YCbCr_cmyk.jpg") << QString("YCbCr_cmyk.jpg") + << QByteArray("jpg") << QSize(75, 50) + << QString(""); + QTest::newRow("YCbCr_rgb.jpg") << QString("YCbCr_rgb.jpg") + << QByteArray("jpg") << QSize(75, 50) + << QString(""); + QTest::newRow("qtbug13653-no_eoi.jpg") << QString("qtbug13653-no_eoi.jpg") + << QByteArray("jpg") << QSize(240, 180) + << QString(""); + QTest::newRow("corrupt.mng") << QString("corrupt.mng") + << QByteArray("mng") << QSize(0, 0) + << QString("MNG error 901: Application signalled I/O error; chunk IHDR; subcode 0:0"); + QTest::newRow("fire.mng") << QString("fire.mng") + << QByteArray("mng") << QSize(30, 60) + << QString(""); + QTest::newRow("ball.mng") << QString("ball.mng") + << QByteArray("mng") << QSize(32, 32) + << QString(""); + QTest::newRow("rect.svg") << QString("rect.svg") + << QByteArray("svg") << QSize(105, 137) + << QString(""); + QTest::newRow("rect.svgz") << QString("rect.svgz") + << QByteArray("svgz") << QSize(105, 137) + << QString(""); + QTest::newRow("corrupt.svg") << QString("corrupt.svg") + << QByteArray("svg") << QSize(0, 0) + << QString(""); + QTest::newRow("corrupt.svgz") << QString("corrupt.svgz") + << QByteArray("svgz") << QSize(0, 0) + << QString(""); + QTest::newRow("image.pbm") << QString("image.pbm") + << QByteArray("pbm") << QSize(16, 6) + << QString(""); + QTest::newRow("image.pgm") << QString("image.pgm") + << QByteArray("pgm") << QSize(24, 7) + << QString(""); + QTest::newRow("corrupt.png") << QString("corrupt.png") + << QByteArray("png") << QSize(0, 0) + << QString(""); + QTest::newRow("away.png") << QString("away.png") + << QByteArray("png") << QSize(16, 16) + << QString(""); + QTest::newRow("image.png") << QString("image.png") + << QByteArray("png") << QSize(22, 22) + << QString(""); + QTest::newRow("kollada.png") << QString("kollada.png") + << QByteArray("png") << QSize(436, 160) + << QString(""); + QTest::newRow("black.png") << QString("black.png") + << QByteArray("png") << QSize(48, 48) + << QString(""); + QTest::newRow("YCbCr_cmyk.png") << QString("YCbCr_cmyk.png") + << QByteArray("png") << QSize(75, 50) + << QString(""); + QTest::newRow("teapot.ppm") << QString("teapot.ppm") + << QByteArray("ppm") << QSize(256, 256) + << QString(""); + QTest::newRow("image.ppm") << QString("image.ppm") + << QByteArray("ppm") << QSize(4, 4) + << QString(""); + QTest::newRow("runners.ppm") << QString("runners.ppm") + << QByteArray("ppm") << QSize(400, 400) + << QString(""); + QTest::newRow("test.ppm") << QString("test.ppm") + << QByteArray("ppm") << QSize(10, 10) + << QString(""); + QTest::newRow("gnus.xbm") << QString("gnus.xbm") + << QByteArray("xbm") << QSize(271, 273) + << QString(""); + QTest::newRow("corrupt-colors.xpm") << QString("corrupt-colors.xpm") + << QByteArray("xpm") << QSize(0, 0) + << QString("QImage: XPM color specification is missing: bla9an.n#x"); + QTest::newRow("corrupt-pixels.xpm") << QString("corrupt-pixels.xpm") + << QByteArray("xpm") << QSize(0, 0) + << QString("QImage: XPM pixels missing on image line 3"); + QTest::newRow("corrupt-pixel-count.xpm") << QString("corrupt-pixel-count.xpm") + << QByteArray("xpm") << QSize(0, 0) + << QString(""); + QTest::newRow("marble.xpm") << QString("marble.xpm") + << QByteArray("xpm") << QSize(240, 240) + << QString(""); + QTest::newRow("test.xpm") << QString("test.xpm") + << QByteArray("xpm") << QSize(256, 256) + << QString(""); + QTest::newRow("black.xpm") << QString("black.xpm") + << QByteArray("xpm") << QSize(48, 48) + << QString(""); + QTest::newRow("namedcolors.xpm") << QString("namedcolors.xpm") + << QByteArray("xpm") << QSize(8, 8) + << QString(""); + QTest::newRow("nontransparent.xpm") << QString("nontransparent.xpm") + << QByteArray("xpm") << QSize(8, 8) + << QString(""); + QTest::newRow("transparent.xpm") << QString("transparent.xpm") + << QByteArray("xpm") << QSize(8, 8) + << QString(""); +} + +void tst_QImageReader::readFromResources() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + QFETCH(QSize, size); + QFETCH(QString, message); + + SKIP_IF_UNSUPPORTED(format); + + for (int i = 0; i < 2; ++i) { + QString file = i ? (":/images/" + fileName) : (prefix + fileName); + { + // suppress warnings if we expect them + if (!message.isEmpty()) { + for (int j = 0; j < 5; ++j) + QTest::ignoreMessage(QtWarningMsg, message.toLatin1()); + } + + // 1) full filename, no format + QImageReader reader(file); + QImage image = reader.read(); + if (size.isNull()) + QVERIFY(image.isNull()); + else + QVERIFY(!image.isNull()); + QCOMPARE(image.size(), size); + } + { + // 2) full filename, with format + QImageReader reader(file, format); + QImage image = reader.read(); + if (size.isNull()) + QVERIFY(image.isNull()); + else + QVERIFY(!image.isNull()); + QCOMPARE(image.size(), size); + } + { + // 3) full filename, with uppercase format + QImageReader reader(file, format.toUpper()); + QImage image = reader.read(); + if (size.isNull()) + QVERIFY(image.isNull()); + else + QVERIFY(!image.isNull()); + QCOMPARE(image.size(), size); + } + { + // 4) chopped filename, with format + QImageReader reader(file.left(file.lastIndexOf(QLatin1Char('.'))), format); + QImage image = reader.read(); + if (size.isNull()) + QVERIFY(image.isNull()); + else + QVERIFY(!image.isNull()); + QCOMPARE(image.size(), size); + } + { + // 5) chopped filename, with uppercase format + QImageReader reader(file.left(file.lastIndexOf(QLatin1Char('.'))), format.toUpper()); + QImage image = reader.read(); + if (size.isNull()) + QVERIFY(image.isNull()); + else + QVERIFY(!image.isNull()); + QCOMPARE(image.size(), size); + } + } + + // Check that the results are identical + if (!message.isEmpty()) { + QTest::ignoreMessage(QtWarningMsg, message.toLatin1()); + QTest::ignoreMessage(QtWarningMsg, message.toLatin1()); + } + QCOMPARE(QImageReader(prefix + fileName).read(), QImageReader(":/images/" + fileName).read()); +} + +void tst_QImageReader::readCorruptImage_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<bool>("shouldFail"); + QTest::addColumn<QString>("message"); + QTest::addColumn<QByteArray>("format"); + QTest::newRow("corrupt jpeg") << QString("corrupt.jpg") << true + << QString("JPEG datastream contains no image") + << QByteArray("jpeg"); + QTest::newRow("corrupt gif") << QString("corrupt.gif") << true << QString("") << QByteArray("gif"); + QTest::newRow("corrupt mng") << QString("corrupt.mng") << true + << QString("MNG error 901: Application signalled I/O error; chunk IHDR; subcode 0:0") + << QByteArray("mng"); + QTest::newRow("corrupt png") << QString("corrupt.png") << true << QString("") << QByteArray("png"); + QTest::newRow("corrupt bmp") << QString("corrupt.bmp") << true << QString("") << QByteArray("bmp"); + QTest::newRow("corrupt xpm (colors)") << QString("corrupt-colors.xpm") << true + << QString("QImage: XPM color specification is missing: bla9an.n#x") + << QByteArray("xpm"); + QTest::newRow("corrupt xpm (pixels)") << QString("corrupt-pixels.xpm") << true + << QString("QImage: XPM pixels missing on image line 3") + << QByteArray("xpm"); + QTest::newRow("corrupt xbm") << QString("corrupt.xbm") << false << QString("") << QByteArray("xbm"); + QTest::newRow("corrupt tiff") << QString("corrupt-data.tif") << true << QString("") << QByteArray("tiff"); + QTest::newRow("corrupt svg") << QString("corrupt.svg") << true << QString("") << QByteArray("svg"); + QTest::newRow("corrupt svgz") << QString("corrupt.svgz") << true << QString("") << QByteArray("svgz"); +} + +void tst_QImageReader::readCorruptImage() +{ + QFETCH(QString, fileName); + QFETCH(bool, shouldFail); + QFETCH(QString, message); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + if (!message.isEmpty()) + QTest::ignoreMessage(QtWarningMsg, message.toLatin1()); + QImageReader reader(prefix + fileName); + QVERIFY(reader.canRead()); + QCOMPARE(reader.read().isNull(), shouldFail); +} + +void tst_QImageReader::readCorruptBmp() +{ + QCOMPARE(QImage(prefix + "tst7.bmp").convertToFormat(QImage::Format_ARGB32_Premultiplied), QImage(prefix + "tst7.png").convertToFormat(QImage::Format_ARGB32_Premultiplied)); +} + +void tst_QImageReader::supportsOption_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QIntList>("options"); + + QTest::newRow("png") << QString("black.png") + << (QIntList() << QImageIOHandler::Gamma + << QImageIOHandler::Description + << QImageIOHandler::Quality + << QImageIOHandler::Size); +} + +void tst_QImageReader::supportsOption() +{ + QFETCH(QString, fileName); + QFETCH(QIntList, options); + + QSet<QImageIOHandler::ImageOption> allOptions; + allOptions << QImageIOHandler::Size + << QImageIOHandler::ClipRect + << QImageIOHandler::Description + << QImageIOHandler::ScaledClipRect + << QImageIOHandler::ScaledSize + << QImageIOHandler::CompressionRatio + << QImageIOHandler::Gamma + << QImageIOHandler::Quality + << QImageIOHandler::Name + << QImageIOHandler::SubType + << QImageIOHandler::IncrementalReading + << QImageIOHandler::Endianness + << QImageIOHandler::Animation + << QImageIOHandler::BackgroundColor; + + QImageReader reader(prefix + fileName); + for (int i = 0; i < options.size(); ++i) { + QVERIFY(reader.supportsOption(QImageIOHandler::ImageOption(options.at(i)))); + allOptions.remove(QImageIOHandler::ImageOption(options.at(i))); + } + + foreach (QImageIOHandler::ImageOption option, allOptions) + QVERIFY(!reader.supportsOption(option)); +} + +void tst_QImageReader::tiffCompression_data() +{ + QTest::addColumn<QString>("uncompressedFile"); + QTest::addColumn<QString>("compressedFile"); + + QTest::newRow("TIFF: adobedeflate") << "rgba_nocompression_littleendian.tif" + << "rgba_adobedeflate_littleendian.tif"; + QTest::newRow("TIFF: lzw") << "rgba_nocompression_littleendian.tif" + << "rgba_lzw_littleendian.tif"; + QTest::newRow("TIFF: packbits") << "rgba_nocompression_littleendian.tif" + << "rgba_packbits_littleendian.tif"; + QTest::newRow("TIFF: zipdeflate") << "rgba_nocompression_littleendian.tif" + << "rgba_zipdeflate_littleendian.tif"; +} + +void tst_QImageReader::tiffCompression() +{ + QFETCH(QString, uncompressedFile); + QFETCH(QString, compressedFile); + + SKIP_IF_UNSUPPORTED("tiff"); + + QImage uncompressedImage(prefix + uncompressedFile); + QImage compressedImage(prefix + compressedFile); + + QCOMPARE(uncompressedImage, compressedImage); +} + +void tst_QImageReader::tiffEndianness() +{ + SKIP_IF_UNSUPPORTED("tiff"); + + QImage littleEndian(prefix + "rgba_nocompression_littleendian.tif"); + QImage bigEndian(prefix + "rgba_nocompression_bigendian.tif"); + + QCOMPARE(littleEndian, bigEndian); +} + +void tst_QImageReader::tiffOrientation_data() +{ + QTest::addColumn<QString>("expected"); + QTest::addColumn<QString>("oriented"); + QTest::newRow("Indexed TIFF, orientation1") << "tiff_oriented/original_indexed.tiff" << "tiff_oriented/indexed_orientation_1.tiff"; + QTest::newRow("Indexed TIFF, orientation2") << "tiff_oriented/original_indexed.tiff" << "tiff_oriented/indexed_orientation_2.tiff"; + QTest::newRow("Indexed TIFF, orientation3") << "tiff_oriented/original_indexed.tiff" << "tiff_oriented/indexed_orientation_3.tiff"; + QTest::newRow("Indexed TIFF, orientation4") << "tiff_oriented/original_indexed.tiff" << "tiff_oriented/indexed_orientation_4.tiff"; + QTest::newRow("Indexed TIFF, orientation5") << "tiff_oriented/original_indexed.tiff" << "tiff_oriented/indexed_orientation_5.tiff"; + QTest::newRow("Indexed TIFF, orientation6") << "tiff_oriented/original_indexed.tiff" << "tiff_oriented/indexed_orientation_6.tiff"; + QTest::newRow("Indexed TIFF, orientation7") << "tiff_oriented/original_indexed.tiff" << "tiff_oriented/indexed_orientation_7.tiff"; + QTest::newRow("Indexed TIFF, orientation8") << "tiff_oriented/original_indexed.tiff" << "tiff_oriented/indexed_orientation_8.tiff"; + + QTest::newRow("Mono TIFF, orientation1") << "tiff_oriented/original_mono.tiff" << "tiff_oriented/mono_orientation_1.tiff"; + QTest::newRow("Mono TIFF, orientation2") << "tiff_oriented/original_mono.tiff" << "tiff_oriented/mono_orientation_2.tiff"; + QTest::newRow("Mono TIFF, orientation3") << "tiff_oriented/original_mono.tiff" << "tiff_oriented/mono_orientation_3.tiff"; + QTest::newRow("Mono TIFF, orientation4") << "tiff_oriented/original_mono.tiff" << "tiff_oriented/mono_orientation_4.tiff"; + QTest::newRow("Mono TIFF, orientation5") << "tiff_oriented/original_mono.tiff" << "tiff_oriented/mono_orientation_5.tiff"; + QTest::newRow("Mono TIFF, orientation6") << "tiff_oriented/original_mono.tiff" << "tiff_oriented/mono_orientation_6.tiff"; + QTest::newRow("Mono TIFF, orientation7") << "tiff_oriented/original_mono.tiff" << "tiff_oriented/mono_orientation_7.tiff"; + QTest::newRow("Mono TIFF, orientation8") << "tiff_oriented/original_mono.tiff" << "tiff_oriented/mono_orientation_8.tiff"; + + QTest::newRow("RGB TIFF, orientation1") << "tiff_oriented/original_rgb.tiff" << "tiff_oriented/rgb_orientation_1.tiff"; + QTest::newRow("RGB TIFF, orientation2") << "tiff_oriented/original_rgb.tiff" << "tiff_oriented/rgb_orientation_2.tiff"; + QTest::newRow("RGB TIFF, orientation3") << "tiff_oriented/original_rgb.tiff" << "tiff_oriented/rgb_orientation_3.tiff"; + QTest::newRow("RGB TIFF, orientation4") << "tiff_oriented/original_rgb.tiff" << "tiff_oriented/rgb_orientation_4.tiff"; + QTest::newRow("RGB TIFF, orientation5") << "tiff_oriented/original_rgb.tiff" << "tiff_oriented/rgb_orientation_5.tiff"; + QTest::newRow("RGB TIFF, orientation6") << "tiff_oriented/original_rgb.tiff" << "tiff_oriented/rgb_orientation_6.tiff"; + QTest::newRow("RGB TIFF, orientation7") << "tiff_oriented/original_rgb.tiff" << "tiff_oriented/rgb_orientation_7.tiff"; + QTest::newRow("RGB TIFF, orientation8") << "tiff_oriented/original_rgb.tiff" << "tiff_oriented/rgb_orientation_8.tiff"; +} + +void tst_QImageReader::tiffOrientation() +{ + QFETCH(QString, expected); + QFETCH(QString, oriented); + + SKIP_IF_UNSUPPORTED("tiff"); + + QImage expectedImage(prefix + expected); + QImage orientedImage(prefix + oriented); + QCOMPARE(expectedImage, orientedImage); +} + +void tst_QImageReader::tiffGrayscale() +{ + SKIP_IF_UNSUPPORTED("tiff"); + + QImage actualImage(prefix + "grayscale.tif"); + QImage expectedImage(prefix + "grayscale-ref.tif"); + + QCOMPARE(expectedImage, actualImage.convertToFormat(expectedImage.format())); +} + +void tst_QImageReader::dotsPerMeter_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("expectedDotsPerMeterX"); + QTest::addColumn<int>("expectedDotsPerMeterY"); + QTest::addColumn<QByteArray>("format"); + QTest::newRow("TIFF: 72 dpi") << ("rgba_nocompression_littleendian.tif") << qRound(72 * (100 / 2.54)) << qRound(72 * (100 / 2.54)) << QByteArray("tiff"); + QTest::newRow("TIFF: 100 dpi") << ("image_100dpi.tif") << qRound(100 * (100 / 2.54)) << qRound(100 * (100 / 2.54)) << QByteArray("tiff"); +} + +void tst_QImageReader::dotsPerMeter() +{ + QFETCH(QString, fileName); + QFETCH(int, expectedDotsPerMeterX); + QFETCH(int, expectedDotsPerMeterY); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImage image(prefix + fileName); + + QCOMPARE(image.dotsPerMeterX(), expectedDotsPerMeterX); + QCOMPARE(image.dotsPerMeterY(), expectedDotsPerMeterY); +} + +void tst_QImageReader::physicalDpi_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("expectedPhysicalDpiX"); + QTest::addColumn<int>("expectedPhysicalDpiY"); + QTest::addColumn<QByteArray>("format"); + QTest::newRow("TIFF: 72 dpi") << "rgba_nocompression_littleendian.tif" << 72 << 72 << QByteArray("tiff"); + QTest::newRow("TIFF: 100 dpi") << "image_100dpi.tif" << 100 << 100 << QByteArray("tiff"); +} + +void tst_QImageReader::physicalDpi() +{ + QFETCH(QString, fileName); + QFETCH(int, expectedPhysicalDpiX); + QFETCH(int, expectedPhysicalDpiY); + QFETCH(QByteArray, format); + + SKIP_IF_UNSUPPORTED(format); + + QImage image(prefix + fileName); + + QCOMPARE(image.physicalDpiX(), expectedPhysicalDpiX); + QCOMPARE(image.physicalDpiY(), expectedPhysicalDpiY); +} + +void tst_QImageReader::autoDetectImageFormat() +{ + // Assume PNG is supported :-) + { + // Disables file name extension probing + QImageReader reader(prefix + "kollada"); + reader.setAutoDetectImageFormat(false); + QVERIFY(!reader.canRead()); + QVERIFY(reader.read().isNull()); + reader.setAutoDetectImageFormat(true); + QVERIFY(reader.canRead()); + QVERIFY(!reader.read().isNull()); + } + { + // Disables detection based on suffix + QImageReader reader(prefix + "kollada.png"); + reader.setAutoDetectImageFormat(false); + QVERIFY(!reader.canRead()); + QVERIFY(reader.read().isNull()); + reader.setAutoDetectImageFormat(true); + QVERIFY(reader.canRead()); + QVERIFY(!reader.read().isNull()); + } + { + // Disables detection based on content + QImageReader reader(prefix + "kollada-noext"); + reader.setAutoDetectImageFormat(false); + QVERIFY(!reader.canRead()); + QVERIFY(reader.read().isNull()); + reader.setAutoDetectImageFormat(true); + QVERIFY(reader.canRead()); + QVERIFY(!reader.read().isNull()); + } + + if (QImageReader::supportedImageFormats().contains("jpeg")) { + QImageReader io(prefix + "YCbCr_rgb.jpg"); + io.setAutoDetectImageFormat(false); + // This should fail since no format string is given + QImage image; + QVERIFY(!io.read(&image)); + } + if (QImageReader::supportedImageFormats().contains("jpeg")) { + QImageReader io(prefix + "YCbCr_rgb.jpg", "jpg"); + io.setAutoDetectImageFormat(false); + QImage image; + QVERIFY(io.read(&image)); + } + { + QImageReader io(prefix + "tst7.png"); + io.setAutoDetectImageFormat(false); + // This should fail since no format string is given + QImage image; + QVERIFY(!io.read(&image)); + } + { + QImageReader io(prefix + "tst7.png", "png"); + io.setAutoDetectImageFormat(false); + QImage image; + QVERIFY(io.read(&image)); + } +} + +void tst_QImageReader::fileNameProbing() +{ + QString name("doesnotexist.png"); + QImageReader r; + r.setFileName(name); // non-existing / non-readable file + QCOMPARE(r.fileName(), name); + + r.size(); + QCOMPARE(r.fileName(), name); + r.read(); + QCOMPARE(r.fileName(), name); +} + +void tst_QImageReader::pixelCompareWithBaseline_data() +{ + QTest::addColumn<QString>("fileName"); + + QTest::newRow("floppy (16px,32px - 16 colors)") << "35floppy.ico"; + QTest::newRow("semitransparent") << "semitransparent.ico"; + QTest::newRow("slightlybrokenBMPHeader") << "kde_favicon.ico"; + QTest::newRow("sightlybrokenIconHeader") << "connect.ico"; +} + +void tst_QImageReader::pixelCompareWithBaseline() +{ + QFETCH(QString, fileName); + + static int enteredCount = 0; // Used for better error diagnostics if something fails. We + static int loadFailCount = 0; // don't know if the reason load() fails is that the plugin + // does not exist or because of a bug in the plugin. But if at + // least one file succeeded we know that the plugin was built. + // The other failures are then real failures. + QImage icoImg; + const QString inputFileName(QString::fromAscii("images/%1").arg(fileName)); + QFileInfo fi(inputFileName); + + ++enteredCount; + // might fail if the plugin does not exist, which is ok. + if (icoImg.load(inputFileName)) { + icoImg = icoImg.convertToFormat(QImage::Format_ARGB32_Premultiplied); + const QString baselineFileName(QString::fromAscii("baseline/%1.png").arg(fi.baseName())); +#if 0 + icoImg.save(baselineFileName); +#else + QImage baseImg; + QVERIFY(baseImg.load(baselineFileName)); + baseImg = baseImg.convertToFormat(QImage::Format_ARGB32_Premultiplied); + QCOMPARE(int(baseImg.format()), int(icoImg.format())); + QCOMPARE(baseImg, icoImg); +#endif + } else { + ++loadFailCount; + if (enteredCount != loadFailCount) { + QFAIL("Plugin is built, but some did not load properly"); + } else { + qWarning("loading failed, check if ico plugin is built"); + } + } +} + + +void tst_QImageReader::testIgnoresFormatAndExtension_data() +{ + QTest::addColumn<QString>("name"); + QTest::addColumn<QString>("extension"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("black.png") << "black" << "png" << "png"; + QTest::newRow("black.xpm") << "black" << "xpm" << "xpm"; + QTest::newRow("colorful.bmp") << "colorful" << "bmp" << "bmp"; + QTest::newRow("image.ppm") << "image" << "ppm" << "ppm"; + QTest::newRow("image.pbm") << "image" << "pbm" << "pbm"; + QTest::newRow("image.pgm") << "image" << "pgm" << "pgm"; + + QTest::newRow("bat1.gif") << "bat1" << "gif" << "gif"; + + QTest::newRow("beavis.jpg") << "beavis" << "jpg" << "jpeg"; + + QTest::newRow("fire.mng") << "fire" << "mng" << "mng"; + + QTest::newRow("image_100dpi.tif") << "image_100dpi" << "tif" << "tiff"; + + QTest::newRow("rect.svg") << "rect" << "svg" << "svg"; + QTest::newRow("rect.svgz") << "rect" << "svgz" << "svgz"; +} + + +void tst_QImageReader::testIgnoresFormatAndExtension() +{ + QFETCH(QString, name); + QFETCH(QString, extension); + QFETCH(QString, expected); + + SKIP_IF_UNSUPPORTED(expected.toLatin1()); + + QList<QByteArray> formats = QImageReader::supportedImageFormats(); + QString fileNameBase = prefix + name + "."; + + foreach (const QByteArray &f, formats) { + if (f == extension) + continue; + QFile tmp(QDir::tempPath() + "/" + name + "_" + expected + "." + f); + + QVERIFY(QFile::copy(fileNameBase + extension, QFileInfo(tmp).absoluteFilePath())); + + QString format; + QImage image; + { + // image reader needs to be scoped for the remove() to work.. + QImageReader r; + r.setFileName(QFileInfo(tmp).absoluteFilePath()); + r.setDecideFormatFromContent(true); + format = r.format(); + r.read(&image); + } + + tmp.remove(); + + QVERIFY(!image.isNull()); + QCOMPARE(format, expected); + } +} + + +void tst_QImageReader::saveFormat_data() +{ + QTest::addColumn<QImage::Format>("format"); + + QTest::newRow("Format_Mono") << QImage::Format_Mono; + QTest::newRow("Format_MonoLSB") << QImage::Format_MonoLSB; + QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8; + QTest::newRow("Format_RGB32") << QImage::Format_RGB32; + QTest::newRow("Format_ARGB32") << QImage::Format_ARGB32; + QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("Format_RGB16") << QImage::Format_RGB16; + QTest::newRow("Format_ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied; + QTest::newRow("Format_RGB666") << QImage::Format_RGB666; + QTest::newRow("Format_ARGB6666_Premultiplied") << QImage::Format_ARGB6666_Premultiplied; + QTest::newRow("Format_RGB555") << QImage::Format_RGB555; + QTest::newRow("Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied; + QTest::newRow("Format_RGB888") << QImage::Format_RGB888; + QTest::newRow("Format_RGB444") << QImage::Format_RGB444; + QTest::newRow("Format_ARGB4444_Premultiplied") << QImage::Format_ARGB4444_Premultiplied; +} + +void tst_QImageReader::saveFormat() +{ + QFETCH(QImage::Format, format); + + QImage orig(":/images/kollada.png"); + + QImage converted = orig.convertToFormat(format); + QBuffer buf; + buf.open(QIODevice::WriteOnly); + QVERIFY(converted.save(&buf, "png")); + buf.close(); + QImage stored = QImage::fromData(buf.buffer(), "png"); + + stored = stored.convertToFormat(QImage::Format_ARGB32); + converted = converted.convertToFormat(QImage::Format_ARGB32); + QCOMPARE(stored, converted); +} + + +void tst_QImageReader::readText_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("key"); + QTest::addColumn<QString>("text"); + + QTest::newRow("png, tEXt before img") << "txts.png" << "Title" << "PNG"; + QTest::newRow("png, zTXt before img") << "txts.png" << "Comment" << "Some compressed text."; + QTest::newRow("png, tEXt after img") << "txts.png" << "Disclaimer" << "For testing only."; + QTest::newRow("png, zTXt after img") << "txts.png" << "Description" << "Rendered by Persistence of Vision (tm) Ray Tracer"; +} + + +void tst_QImageReader::readText() +{ + QFETCH(QString, fileName); + QFETCH(QString, key); + QFETCH(QString, text); + + QImage img(prefix + fileName); + QVERIFY(img.textKeys().contains(key)); + QCOMPARE(img.text(key), text); +} + + +void tst_QImageReader::preserveTexts_data() +{ + QTest::addColumn<QString>("text"); + + QTest::newRow("Simple") << "simpletext"; + QTest::newRow("Whitespace") << " A text with whitespace "; + QTest::newRow("Newline") << "A text\nwith newlines\n"; + QTest::newRow("Double newlines") << "A text\n\nwith double newlines\n\n"; + QTest::newRow("Long") << QString("A rather long text, at least after many repetitions. ").repeated(100); + QString latin1set; + int c; + for(c = 0x20; c <= 0x7e; c++) + latin1set.append(QLatin1Char(c)); + for(c = 0xa0; c <= 0xff; c++) + latin1set.append(QLatin1Char(c)); + QTest::newRow("All Latin1 chars") << latin1set; + +#if 0 + // Depends on iTXt support in libpng + QTest::newRow("Multibyte string") << QString::fromUtf8("\341\233\222\341\233\226\341\232\251\341\232\271\341\232\242\341\233\232\341\232\240"); +#endif +} + + +void tst_QImageReader::preserveTexts() +{ + QFETCH(QString, text); + QString key("testkey"); + QString key2("testkey2"); + QString text2("Some other text."); + QString key3("testkey3"); + QString text3("Some more other text."); + + QImage img(":/images/kollada.png"); + img.setText(key, text); + img.setText(key2, text2); + QBuffer buf; + buf.open(QIODevice::WriteOnly); + QVERIFY(img.save(&buf, "png")); + buf.close(); + QImage stored = QImage::fromData(buf.buffer(), "png"); + QCOMPARE(stored.text(key), text); + QCOMPARE(stored.text(key2), text2); + + QImage img2(":/images/kollada.png"); + img2.setText(key3, text3); + QBuffer buf2; + QImageWriter w(&buf2, "png"); + w.setText(key, text); + w.setText(key2, text2); + QVERIFY(w.write(img2)); + buf2.close(); + QImageReader r(&buf2, "png"); + QCOMPARE(r.text(key), text.simplified()); + QCOMPARE(r.text(key2), text2.simplified()); + QCOMPARE(r.text(key3), text3.simplified()); +} + + +QTEST_MAIN(tst_QImageReader) +#include "tst_qimagereader.moc" diff --git a/tests/auto/gui/image/qimagewriter/.gitignore b/tests/auto/gui/image/qimagewriter/.gitignore new file mode 100644 index 0000000000..9355bcd1bf --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/.gitignore @@ -0,0 +1 @@ +tst_qimagewriter diff --git a/tests/auto/gui/image/qimagewriter/images/YCbCr_cmyk.jpg b/tests/auto/gui/image/qimagewriter/images/YCbCr_cmyk.jpg Binary files differnew file mode 100644 index 0000000000..b8aa9ea609 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/YCbCr_cmyk.jpg diff --git a/tests/auto/gui/image/qimagewriter/images/YCbCr_rgb.jpg b/tests/auto/gui/image/qimagewriter/images/YCbCr_rgb.jpg Binary files differnew file mode 100644 index 0000000000..8771224cb5 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/YCbCr_rgb.jpg diff --git a/tests/auto/gui/image/qimagewriter/images/beavis.jpg b/tests/auto/gui/image/qimagewriter/images/beavis.jpg Binary files differnew file mode 100644 index 0000000000..d55504779b --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/beavis.jpg diff --git a/tests/auto/gui/image/qimagewriter/images/colorful.bmp b/tests/auto/gui/image/qimagewriter/images/colorful.bmp Binary files differnew file mode 100644 index 0000000000..8ea6f4acd7 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/colorful.bmp diff --git a/tests/auto/gui/image/qimagewriter/images/earth.gif b/tests/auto/gui/image/qimagewriter/images/earth.gif Binary files differnew file mode 100644 index 0000000000..2c229eb110 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/earth.gif diff --git a/tests/auto/gui/image/qimagewriter/images/font.bmp b/tests/auto/gui/image/qimagewriter/images/font.bmp Binary files differnew file mode 100644 index 0000000000..28b8c66924 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/font.bmp diff --git a/tests/auto/gui/image/qimagewriter/images/gnus.xbm b/tests/auto/gui/image/qimagewriter/images/gnus.xbm new file mode 100644 index 0000000000..58d1ac845a --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/gnus.xbm @@ -0,0 +1,622 @@ +#define noname_width 271 +#define noname_height 273 +static char noname_bits[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x49,0xe0,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x97,0xaa,0x8a,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x57,0x2a,0x41,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0x52,0x16,0xfe,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4a,0x49,0x05, + 0xf9,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0x95,0xaa,0x58,0xf4,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xa5,0x54,0x26,0xe1,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x54,0x49,0x49,0xe4,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x2a,0xa5, + 0x2a,0xd1,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0xd5,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xaf,0x52,0x95,0x54,0xc4,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab, + 0x24,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x57,0x29,0xa9,0x92,0x11,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x57,0xd5,0xfa,0xff,0xff,0xab,0xea,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x4a,0x55,0x2a,0x41,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x25,0x29,0xe5,0xff,0xff,0x95,0xa4,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa7,0xa4, + 0x24,0xa5,0x14,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4a,0xa5,0xd4,0xff, + 0x3f,0x52,0xa9,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x29,0x55,0x55,0x55,0x41,0x7e,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xa9,0x54,0xea,0xff,0xdf,0x2a,0x55,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55,0x4a,0x49,0x12,0x7e,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0x55,0xa5,0x92,0xff,0x23,0xa5,0x4a,0xd6,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa5,0xa4,0x94,0xaa,0x42, + 0x7d,0xff,0xff,0xff,0xff,0xff,0xff,0x9f,0x4a,0x2a,0xa9,0xff,0xad,0x92,0x24, + 0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2a, + 0x95,0x52,0x52,0x29,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x52,0x49,0x55, + 0xfe,0x91,0x54,0x55,0x55,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0x49,0x29,0x55,0x25,0x85,0x7c,0xff,0xff,0xff,0xff,0xff,0xff, + 0x4f,0x95,0xaa,0x92,0x7e,0x55,0x55,0xa9,0x4a,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2a,0x50,0x95,0xaa,0x24,0x7e,0xff,0xff, + 0xff,0xff,0xff,0xff,0x57,0x2a,0x95,0x54,0x79,0x95,0x92,0x92,0x94,0xfc,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xb9,0x62,0x29,0x49, + 0x85,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x49,0x49,0x95,0xba,0xa4,0x54, + 0xaa,0x52,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf, + 0x1a,0xf8,0xa7,0xaa,0x22,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0x55,0x52, + 0x2a,0x75,0x55,0xa5,0x24,0xa5,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xbf,0x5a,0xfd,0x57,0x92,0x94,0x7e,0xff,0xff,0xff,0xff,0xff, + 0xff,0x4a,0x4a,0x55,0x49,0x89,0x92,0x94,0xaa,0x94,0xf4,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x1a,0xfc,0x2f,0x55,0x05,0x7c,0xff, + 0xff,0xff,0xff,0xff,0xff,0x55,0xa9,0x4a,0x55,0x2a,0x55,0x55,0x55,0x55,0xe5, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x4e,0xfd,0x5f, + 0x29,0xa5,0x7c,0xff,0xff,0xff,0xff,0xff,0xff,0xa4,0x54,0x52,0x4a,0x55,0xa9, + 0xa4,0x24,0xa5,0x94,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x2f,0x1d,0xfe,0x3f,0x95,0x04,0x7c,0xff,0xfd,0xff,0xff,0xff,0x3f,0x49,0xa5, + 0x54,0xa9,0xa4,0x92,0x4a,0x49,0x4a,0x55,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xaf,0x44,0xfe,0x5f,0xa9,0x52,0x7d,0xff,0xe5,0xff,0xff, + 0xff,0x5f,0x55,0x92,0x2a,0x95,0x52,0x4a,0x52,0xaa,0x52,0x4a,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x16,0xff,0xbf,0x4a,0x05,0x7c, + 0xff,0xd9,0xff,0xff,0xff,0x5f,0x95,0x42,0xa5,0x52,0x95,0xaa,0xaa,0xaa,0x94, + 0x54,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x43,0xfe, + 0xbf,0x54,0x52,0x7d,0x7f,0x25,0xff,0xff,0xff,0xa7,0xa4,0x28,0x92,0x54,0x4a, + 0xa5,0x4a,0x92,0xaa,0x4a,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xab,0x12,0xfe,0x7f,0xa5,0x02,0x7c,0x7f,0x55,0xfd,0xff,0xff,0x95,0x2a, + 0x82,0x54,0xa5,0x54,0x2a,0xa9,0x2a,0xa5,0x52,0xf5,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x27,0x4b,0xff,0xff,0x4a,0x29,0x7d,0xff,0x92,0xfe, + 0xff,0xff,0x55,0x92,0x20,0xa8,0x94,0x2a,0xa5,0x94,0x52,0x29,0xa9,0xf4,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97,0x01,0xff,0x7f,0x52,0x42, + 0x7c,0xff,0x25,0xf9,0xff,0x7f,0xaa,0x02,0x8a,0x40,0x29,0x49,0x09,0x41,0x4a, + 0x55,0x25,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x57, + 0xff,0xff,0x95,0x12,0x7d,0xff,0xa9,0xfa,0xff,0x7f,0x25,0xa9,0x20,0x2a,0xa5, + 0xaa,0x42,0x92,0x54,0x92,0x54,0x95,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xaf,0x83,0xff,0xff,0xa9,0x42,0x7e,0xff,0xaa,0xf4,0xff,0xaf,0x54, + 0x01,0x82,0x80,0xaa,0x54,0x14,0x08,0xa2,0xaa,0x4a,0xd2,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xef,0xcf,0xd7,0xff,0xff,0x52,0x12,0x7f,0xff,0x4a, + 0xea,0xff,0x57,0x92,0xaa,0x28,0x24,0x29,0x25,0x81,0x82,0x08,0x49,0x52,0x55, + 0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xdf,0xef,0xe7,0xff,0xff,0x2a, + 0x05,0x7e,0xff,0x55,0xd5,0xff,0xa5,0x2a,0x00,0x8e,0x10,0x4a,0x89,0x24,0x28, + 0xa0,0xaa,0x2a,0x49,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xe7,0xff, + 0xef,0xff,0xff,0xa5,0x50,0x7e,0xff,0x25,0xe5,0xff,0x2a,0xa5,0x52,0x7f,0x85, + 0x54,0x35,0x08,0x82,0x0a,0x55,0x95,0xaa,0xfc,0xff,0xff,0xff,0xcf,0xff,0xff, + 0xff,0xff,0xd7,0xff,0xff,0xff,0x7f,0x52,0x85,0x7e,0xff,0xab,0x94,0x1e,0x55, + 0x2a,0xc8,0xff,0x10,0x90,0x92,0xa0,0x08,0x20,0x24,0x52,0x25,0xfd,0xff,0xff, + 0xff,0xef,0xff,0xff,0xff,0xff,0xe9,0xff,0xff,0xff,0xff,0x94,0x10,0x7e,0xff, + 0x93,0xaa,0x6a,0x49,0x49,0xf2,0xff,0x85,0x52,0x09,0x0a,0xa2,0x4a,0x92,0x29, + 0xa9,0xf2,0xff,0xff,0xff,0xd3,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0x7f, + 0x55,0x25,0x7f,0xff,0x55,0x49,0x49,0x95,0x0a,0xf9,0xff,0x17,0x48,0x26,0x50, + 0x08,0x00,0xa9,0x4a,0x95,0xfa,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xf2, + 0xff,0xff,0xff,0xff,0x92,0x80,0x7e,0xff,0xa7,0x54,0xaa,0xa4,0x52,0xfc,0xff, + 0xaf,0x42,0x89,0xfa,0xbf,0x54,0x20,0xa9,0xa4,0xd4,0xff,0xff,0xff,0xcb,0xff, + 0xff,0xff,0xff,0xf5,0xff,0xff,0xff,0xff,0x54,0x29,0x7f,0xff,0x4b,0xa5,0x92, + 0x2a,0x01,0xff,0xff,0x1f,0xa8,0x22,0xff,0xff,0x01,0xa5,0x2a,0x55,0xa9,0xff, + 0xff,0xff,0xd4,0xff,0xff,0xff,0x7f,0xfa,0xff,0xff,0xff,0x7f,0xa5,0x04,0x7f, + 0xff,0x57,0x2a,0x55,0xa9,0x54,0xfe,0xff,0x3f,0x05,0x89,0xff,0xff,0x5f,0x48, + 0x92,0x2a,0x95,0xff,0xff,0xff,0xea,0xff,0xff,0xff,0xff,0xd2,0xff,0xff,0xff, + 0x7f,0x2a,0x91,0x7f,0xff,0xa9,0x54,0x4a,0x52,0x02,0xff,0xff,0xff,0x50,0xd1, + 0xff,0xff,0x1f,0x81,0xaa,0xa4,0x52,0xfe,0xff,0x3f,0xe9,0xff,0xff,0xff,0x7f, + 0x1d,0xff,0xff,0xff,0xff,0x54,0x41,0x7f,0xff,0x93,0x92,0x52,0x95,0xc8,0xff, + 0xff,0xff,0x8b,0xc4,0xff,0xff,0x7f,0x24,0xa5,0x2a,0x49,0xf9,0xff,0x7f,0xd5, + 0xff,0xff,0xff,0xbf,0x4a,0xff,0xff,0xff,0xff,0x4a,0x14,0x7f,0xff,0x28,0xa5, + 0x94,0x2a,0xa0,0xff,0xff,0x7f,0x22,0xf0,0xff,0xff,0x7f,0x12,0x94,0xa4,0xaa, + 0xea,0xff,0xaf,0xea,0xff,0xff,0xff,0x5f,0x8e,0xff,0xff,0xff,0x7f,0xa9,0x40, + 0x7f,0xff,0x48,0x55,0x55,0x12,0xca,0xff,0xff,0xff,0x0a,0xf5,0xff,0xff,0xff, + 0x80,0x52,0x95,0x54,0xaa,0xfe,0x55,0xc4,0xff,0xff,0xff,0x5f,0xa5,0xff,0xff, + 0xff,0xff,0x94,0x14,0x7f,0xff,0x52,0x2a,0xa9,0x4a,0xe1,0xff,0xff,0xbf,0x24, + 0xf0,0xff,0xff,0xff,0x0b,0x28,0xa9,0x92,0x24,0x55,0x49,0xe5,0xd7,0xff,0xff, + 0xa7,0x8a,0xff,0xff,0xff,0x7f,0xa5,0xc0,0x7f,0xff,0x50,0x49,0x95,0x04,0xf8, + 0xff,0xff,0x5f,0x1f,0xfd,0xff,0xff,0xff,0x47,0x45,0x55,0xaa,0xaa,0x4a,0xaa, + 0xea,0xaf,0xff,0xff,0x2b,0xc3,0xff,0xff,0xff,0x7f,0x55,0x94,0x7f,0x7f,0x4a, + 0x55,0x52,0x51,0xfe,0xff,0xff,0x5f,0x4e,0xf8,0xff,0xff,0xff,0x1f,0x50,0x92, + 0x52,0x49,0xa9,0x92,0xe4,0xd3,0xff,0xff,0x4b,0xd5,0xff,0xff,0xff,0xff,0x94, + 0xc0,0x7f,0x3f,0xa0,0xa4,0xaa,0x04,0xfe,0xff,0xff,0xa7,0x1d,0xfd,0xff,0xff, + 0xff,0x9f,0x84,0xaa,0x4a,0xaa,0x24,0x55,0xf2,0x2b,0xff,0x7f,0xa9,0xc1,0xff, + 0xff,0xff,0x7f,0x4a,0x95,0x7f,0xbf,0x2a,0x95,0x24,0x50,0xff,0xff,0xff,0x97, + 0x5e,0xfe,0xff,0xff,0xff,0x3f,0x92,0x24,0x95,0x92,0xaa,0xa4,0xf2,0xcb,0xff, + 0x5f,0xd5,0xe5,0xff,0xff,0xff,0xff,0x52,0x80,0x7f,0x3f,0xa0,0x52,0x15,0x85, + 0xff,0xff,0xff,0xd7,0x38,0xfe,0xff,0xff,0xff,0xff,0x20,0xaa,0x52,0x55,0x55, + 0x55,0xf9,0x29,0xfd,0xab,0xa4,0xf0,0xff,0xff,0xff,0x7f,0x29,0xa9,0x7f,0xff, + 0x42,0x25,0x49,0xe8,0xff,0xff,0xff,0x69,0x7a,0xff,0xff,0xff,0xff,0xff,0x82, + 0x52,0xaa,0x24,0x89,0x4a,0xf8,0x55,0x2a,0x49,0x95,0xf5,0xff,0xff,0xff,0xbf, + 0x2a,0xc4,0x7f,0x7f,0x90,0x54,0x15,0xe2,0xff,0xff,0xff,0x25,0xbc,0xff,0xff, + 0xff,0xff,0xff,0x29,0x48,0x49,0xaa,0xaa,0xa4,0xfa,0x95,0x92,0x54,0x52,0xf0, + 0xff,0xff,0xff,0xbf,0x4a,0xd1,0x7f,0xff,0x05,0xaa,0x40,0xf8,0xff,0xff,0x7f, + 0xaa,0xfc,0xff,0xff,0xff,0xff,0xff,0x43,0xa9,0xaa,0x4a,0x52,0xa9,0xf8,0xa4, + 0xaa,0x52,0x95,0xfc,0xff,0xff,0xff,0x7f,0x52,0xc0,0x7f,0xff,0xa1,0x00,0x24, + 0xfa,0xff,0xff,0xff,0x0a,0xfe,0xff,0xff,0xff,0xff,0xff,0x17,0x92,0x24,0xa5, + 0x2a,0x55,0xfe,0xaa,0xa4,0x2a,0x29,0xf9,0xff,0xff,0xff,0xbf,0x2a,0xea,0x7f, + 0xff,0x05,0x92,0x90,0xfc,0xff,0xff,0xbf,0xa4,0xff,0xff,0xff,0xff,0xff,0xff, + 0x4f,0xa0,0xaa,0x54,0x49,0x25,0x7c,0x49,0x95,0xa4,0x12,0xfc,0xff,0xff,0xff, + 0x7f,0x8a,0xe0,0x7f,0xff,0xa3,0x04,0x05,0xfe,0xff,0xff,0xbf,0x06,0xff,0xff, + 0xff,0xff,0xff,0xff,0x1f,0x49,0x95,0x52,0xaa,0x12,0x7f,0x55,0x52,0x55,0x0a, + 0xfd,0xff,0xff,0xff,0x3f,0x29,0xe8,0x7f,0xff,0x0f,0x50,0x50,0xff,0xff,0xff, + 0x5f,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x04,0xa9,0x4a,0x25,0x45,0x3e, + 0xa9,0x2a,0xa9,0xa2,0xfc,0xff,0xff,0xff,0x7f,0x55,0xe1,0x7f,0xff,0x27,0x05, + 0xc4,0xff,0xff,0xff,0x9f,0x91,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x41,0x4a, + 0x29,0xa9,0x12,0x5e,0x95,0x94,0x4a,0x0a,0xfe,0xff,0xff,0xff,0xbf,0x12,0xf4, + 0x7f,0xff,0x8f,0x50,0xf1,0xff,0xff,0xff,0xa7,0xc2,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x14,0x92,0xaa,0x4a,0xa2,0xbf,0xa4,0x52,0x95,0x22,0xff,0xff,0xff, + 0xff,0x3f,0x45,0xf2,0x7f,0xff,0x3f,0x04,0xf4,0xff,0xff,0xff,0xd7,0xe8,0xff, + 0xff,0xff,0xff,0x5f,0xff,0xff,0x83,0xa8,0x94,0x54,0x09,0x2f,0x55,0x4a,0x52, + 0x49,0xff,0xff,0xff,0xff,0x5f,0x99,0xf0,0x7f,0xff,0x7f,0x51,0xfc,0xff,0xff, + 0xff,0x6b,0xf1,0xff,0xff,0xff,0xff,0x5f,0xfd,0xff,0x2b,0x2a,0xa9,0x12,0x20, + 0x5f,0xa9,0xaa,0x54,0x00,0xff,0xff,0xff,0xff,0x5f,0x15,0xf2,0x7f,0xff,0xff, + 0x8f,0xff,0xff,0xff,0xff,0x2b,0xfc,0xff,0xff,0xff,0xff,0x2f,0xfd,0xff,0x87, + 0xa0,0x4a,0xaa,0x8a,0x9f,0x4a,0x52,0x15,0xa9,0xff,0xff,0xff,0xff,0x5f,0x8a, + 0xfc,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x94,0xf8,0xff,0xff,0xff,0xff, + 0x57,0xf2,0xff,0x2f,0x82,0x52,0x05,0xd0,0x2f,0x95,0x4a,0x49,0x84,0xff,0xff, + 0xff,0xff,0xbf,0x24,0xf8,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x12,0xfd, + 0xff,0xff,0xff,0xff,0x4b,0xd5,0xff,0x9f,0x28,0x54,0x48,0xc5,0xbf,0x52,0x55, + 0x0a,0xe1,0xff,0xff,0xff,0xff,0x9f,0x4a,0xfa,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x1a,0xfe,0xff,0xff,0xff,0xff,0x57,0xa9,0xff,0x3f,0x82,0x00,0x21, + 0xf0,0x5f,0x2a,0x49,0x21,0xc4,0xff,0xff,0xff,0xff,0xaf,0x1a,0xfd,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0x3f,0x85,0xff,0xff,0xff,0xff,0xff,0x29,0xa5,0xff, + 0xff,0x24,0x52,0x88,0xfc,0xbf,0x92,0x2a,0x09,0xf1,0xff,0xff,0xff,0xff,0x9f, + 0x4c,0xfc,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x15,0xff,0xff,0xff,0x7f, + 0xff,0xa5,0x4a,0xff,0xff,0x90,0x08,0x01,0xfe,0x3f,0x55,0x52,0x24,0xf4,0xff, + 0xff,0xff,0xff,0xaf,0x02,0xfd,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xc6, + 0xff,0xff,0xff,0xbf,0xfe,0x95,0x54,0xff,0xff,0x05,0x42,0xa8,0xfe,0xbf,0xa4, + 0x2a,0x41,0xf9,0xff,0xff,0xff,0xff,0x5f,0x55,0xfc,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0x4f,0xd0,0xff,0xff,0xff,0xbf,0x7c,0xaa,0x92,0xfc,0xff,0x53,0x08, + 0x01,0xff,0x1f,0x4a,0x01,0x04,0xfc,0xff,0xff,0xff,0xff,0x27,0x05,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xc5,0xff,0xff,0xff,0x4f,0xbf,0x52,0xaa, + 0xfe,0xff,0x07,0x42,0xea,0xff,0xbf,0x50,0x54,0x51,0xff,0xff,0xff,0xff,0xff, + 0x97,0x56,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xf0,0xff,0xff,0xff, + 0x2f,0x7f,0xa5,0x54,0xfd,0xff,0x3f,0x09,0xe0,0xff,0x1f,0x02,0x01,0x04,0xff, + 0xff,0xff,0xff,0xff,0xaf,0x02,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x4b, + 0xf5,0xff,0xff,0xff,0xab,0x9f,0x94,0x92,0xfc,0xff,0xff,0x40,0xfd,0xff,0x9f, + 0x48,0x48,0xa1,0xff,0xff,0xff,0xff,0xff,0xa7,0x56,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0x6b,0xf8,0xff,0xff,0xff,0xa4,0x5f,0xa9,0x2a,0xfd,0xff,0xff, + 0xff,0xff,0xff,0x3f,0x22,0x21,0xc4,0xff,0xff,0xff,0xff,0xff,0x2f,0x03,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0xfa,0xff,0xff,0x7f,0xd5,0x2f,0xa5, + 0xa4,0xfa,0xff,0xff,0xff,0xff,0xff,0xbf,0x08,0x08,0xf9,0xff,0xff,0xff,0xff, + 0xff,0x97,0x4a,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x94,0xfc,0xff,0xff, + 0x7f,0x69,0xac,0x2a,0x55,0xf9,0xff,0xff,0xff,0xff,0xff,0x7f,0xa2,0x22,0xf8, + 0xff,0xff,0xff,0xff,0xff,0x53,0x21,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0x15,0xfe,0xff,0xff,0x9f,0x2a,0x95,0x94,0x92,0xf4,0xff,0xff,0xff,0xff,0xff, + 0xff,0x08,0x88,0xfe,0xff,0xff,0xff,0xff,0xff,0x57,0x8b,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xa9,0xfe,0xff,0xff,0x5f,0x52,0xbc,0x52,0x55,0xf5,0xff, + 0xff,0xff,0xff,0xff,0xff,0x21,0x21,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xa1, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x7f,0x0d,0xff,0xff,0xff,0x57,0x15,0x3f, + 0x55,0x49,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xc8,0xff,0xff,0xff,0xff, + 0xff,0xff,0xd7,0x89,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xbf,0xd6,0xff,0xff, + 0xff,0x4b,0x45,0x3f,0x49,0xaa,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xf9, + 0xff,0xff,0xff,0xff,0xff,0xff,0xc9,0xe2,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0x3f,0x81,0xff,0xff,0xff,0x29,0x11,0x5f,0x28,0x55,0xf5,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0xc8,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0x5f,0xd6,0xff,0xff,0x7f,0xaa,0xc2,0x0f,0x55,0x49,0xea, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa5, + 0xe2,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x9f,0xe1,0xff,0xff,0xbf,0x4a,0xd1, + 0x5f,0x48,0xa5,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xe9,0xe0,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x27,0xf4,0xff, + 0xff,0xbf,0x94,0xc4,0x07,0x91,0x2a,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0xea,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xaf,0xf1,0xff,0xff,0x9f,0x52,0xe0,0x4b,0x44,0x52,0xe9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6a,0xe0,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0x4b,0xfc,0xff,0xff,0xab,0x2a,0xf5,0x0f,0x51,0xa5, + 0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x69,0xe5,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x55,0xf8,0xff,0xff,0x95,0x14, + 0xf0,0x5f,0x84,0x54,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0x75,0xf0,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x13,0xfd, + 0xff,0xff,0xa5,0x42,0xf9,0x7f,0x91,0x4a,0xf5,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xb2,0xfa,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0x54,0xfe,0xff,0x7f,0x52,0x12,0xfa,0xff,0x20,0xa5,0xe4,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x34,0xf8,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0x25,0xff,0xff,0xaf,0xaa,0x48,0xfc,0xff,0x0b, + 0x29,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xb5,0xf8,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0x52,0xff,0xff,0x2f,0x49, + 0x02,0xfe,0xff,0x43,0xaa,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x3f,0x3a,0xfa,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0x4a, + 0xff,0xff,0xa5,0x2a,0xa9,0xff,0xff,0x17,0x25,0xe9,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x9a,0xfc,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0x2a,0xff,0x7f,0x95,0x54,0x80,0xff,0xff,0x07,0xa9,0xea,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x1d,0xfc, + 0xff,0x7f,0xff,0xff,0xff,0xff,0x3f,0xa9,0xfe,0x7f,0xa9,0x12,0xe5,0xff,0xff, + 0x5f,0x4a,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x5f,0xad,0xfe,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0x95,0xea,0x97,0x54, + 0x4a,0xf0,0xff,0xff,0x1f,0xa8,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x5f,0x0e,0xfe,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f, + 0x52,0x55,0xa9,0x92,0x02,0xfd,0xff,0xff,0x5f,0x53,0xf5,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x5e,0xfe,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xbf,0x2a,0x49,0x4a,0x55,0x49,0xfc,0xff,0xff,0x3f,0x94,0xf8, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0x0f, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4f,0xa5,0xaa,0x92,0xa4,0x20,0xff,0xff, + 0xff,0xbf,0xa4,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x5f,0x57,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f,0x52,0x52,0xaa, + 0x2a,0x0a,0xff,0xff,0xff,0x7f,0x54,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x8f,0x07,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xa7,0x94,0x4a,0x55,0x4a,0xa0,0xff,0xff,0xff,0xff,0xa8,0xfa,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x57,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0x2f,0x55,0xa9,0x92,0x12,0xe9,0xff,0xff,0xff,0x7f,0x24, + 0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf, + 0x87,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0xa5,0x4a,0xaa,0x44,0xf4,0xff, + 0xff,0xff,0xff,0x55,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0xab,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xab,0x94,0xa4, + 0x92,0x12,0xf9,0xff,0xff,0xff,0xff,0xa8,0xfa,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xab,0x83,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0x47,0xa9,0x2a,0x55,0x40,0xfc,0xff,0xff,0xff,0xff,0x25,0xf5,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff,0xff,0xd7,0x97,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0x33,0x55,0xa9,0x24,0x15,0xfe,0xff,0xff,0xff,0xff, + 0x95,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff, + 0x93,0xc3,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0x25,0xa5,0x2a,0x40,0xff, + 0xff,0xff,0xff,0xff,0xa9,0xf4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xff, + 0xff,0xff,0xff,0xff,0xe7,0xd5,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4b,0x92, + 0x54,0x92,0xd4,0xff,0xff,0xff,0xff,0xff,0x55,0xf5,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xe9,0xff,0xff,0xff,0xff,0xff,0xd5,0xc1,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0x97,0xaa,0x4a,0x05,0xe2,0xff,0xff,0xff,0xff,0xff,0x25,0xf1,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xfd,0xff,0xff,0xff,0xff,0xd5,0xea,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0x57,0x55,0x25,0xa1,0xf0,0xff,0xff,0xff,0xff, + 0xff,0x95,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe8,0xfa,0xff,0xff,0xff, + 0xff,0xea,0xe0,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xa7,0x24,0x59,0x04,0xfa, + 0xff,0xff,0xff,0xff,0xff,0xa9,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe2, + 0xfd,0xff,0xff,0xff,0xff,0xc9,0xe9,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x4f, + 0x52,0x05,0xa1,0xfc,0xff,0xff,0xff,0xff,0xff,0xa5,0xfa,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x70,0xf9,0xff,0xff,0xff,0xff,0x74,0xe2,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0x47,0x95,0x92,0x04,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0xf8, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xe2,0xfa,0xff,0xff,0xff,0xff,0x72,0xe8, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x97,0xaa,0x20,0xd0,0xff,0xff,0xff,0xff, + 0xff,0xff,0x55,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xb8,0xfc,0xff,0xff, + 0xff,0xff,0xea,0xe2,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x07,0x04,0x82,0xc2, + 0xff,0xff,0xff,0xff,0xff,0xff,0x29,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x71,0xfd,0xff,0xff,0xff,0x7f,0x2a,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0x4f,0x91,0x28,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0xfc,0xff,0xff,0xff, + 0xff,0xff,0xff,0x1f,0x54,0xfe,0xff,0xff,0xff,0x7f,0x75,0xf2,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0x27,0x44,0x82,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0x29, + 0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0xb8,0xfc,0xff,0xff,0xff,0xbf,0x14, + 0xf1,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x0f,0x11,0x20,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x55,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x9a,0xfe,0xff, + 0xff,0xff,0x7f,0x5a,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x5f,0x40,0x85, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x09,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x4f,0x2d,0xfd,0xff,0xff,0xff,0x9f,0x12,0xf9,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0x3f,0x14,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0x07,0xa6,0xfe,0xff,0xff,0xff,0x5f,0x4d,0xfa,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0x40,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x09,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0x4b,0xfe,0xff,0xff,0xff,0xbf, + 0x2c,0xf8,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xf5,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x43,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x57,0xff, + 0xff,0xff,0xff,0x5f,0x0a,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x89,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xd5,0xa9,0xff,0xff,0xff,0xff,0xaf,0x5a,0xfc,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa3,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x81,0x95,0xff,0xff,0xff,0xff,0x9f,0x06,0xfd,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xca,0xa5,0xff,0xff,0xff,0xff, + 0x2f,0x95,0xfc,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0xea, + 0xff,0xff,0xff,0xff,0xaf,0x26,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd5,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xf5,0xf4,0xff,0xff,0xff,0xff,0xaf,0x86,0xfe,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc1,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0x70,0xe5,0xff,0xff,0xff,0xff,0x4f,0x2e,0xfe, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xb2,0xfa,0xff,0xff,0xff, + 0xff,0x57,0x83,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x78, + 0xf2,0xff,0xff,0xff,0xff,0xa7,0x22,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x5f,0x5d,0xfd,0xff,0xff,0xff,0xff,0x97,0x87,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0x3c,0xfd,0xff,0xff,0xff,0xff,0x53,0xa3, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xac,0xfe,0xff,0xff, + 0xff,0xff,0x57,0x95,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f, + 0x9e,0xfe,0xff,0xff,0xff,0xff,0x97,0x81,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0x57,0xfe,0xff,0xff,0xff,0xff,0xa9,0xa5,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xaf,0xff,0xff,0xff,0xff,0xff,0x4b, + 0x89,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0x93,0xff,0xff, + 0xff,0xff,0xff,0x95,0xa2,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x83,0xab,0xff,0xff,0xff,0xff,0xff,0xd3,0xc8,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff, + 0xff,0xff,0xff,0xff,0xe9,0xa5,0xff,0xff,0xff,0xff,0xff,0xa5,0xe1,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0xd5,0xff,0xff,0xff,0xff,0xff, + 0xd5,0xc8,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xea,0xea,0xff, + 0xff,0xff,0xff,0xff,0x14,0xc1,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xff,0xff, + 0xff,0xe0,0xe4,0xff,0xff,0xff,0xff,0xff,0x65,0xe8,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf, + 0xff,0xff,0xff,0xff,0x3f,0x72,0xe9,0xff,0xff,0xff,0xff,0xff,0x6a,0xe1,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xbf,0xb8,0xfa,0xff,0xff,0xff,0xff, + 0xff,0x52,0xea,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd3,0xff,0xff,0xff,0xff,0x1f,0x7a,0xf5, + 0xff,0xff,0xff,0xff,0x7f,0x2a,0xe0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xff,0xff,0xff, + 0xff,0x8f,0x58,0xfa,0xff,0xff,0xff,0xff,0x7f,0x25,0xf5,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xb5,0xff,0xff,0xdf,0xff,0x57,0x5e,0xfd,0xff,0xff,0xff,0xff,0xff,0x34,0xe0, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xca,0xff,0xff,0x8f,0xff,0x07,0xac,0xfc,0xff,0xff,0xff, + 0xff,0x7f,0x2a,0xf5,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd4,0xff,0xff,0x57,0xff,0x2b,0x2d, + 0xfd,0xff,0xff,0xff,0xff,0xff,0xb2,0xf0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd2,0xff,0xff, + 0x07,0xff,0x43,0x4a,0xff,0xff,0xff,0xff,0xff,0xbf,0x2a,0xf8,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x3f,0xc5,0xff,0xff,0x2b,0xfe,0x08,0xab,0xfe,0xff,0xff,0xff,0xff,0x7f,0xaa, + 0xf2,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xbf,0xea,0xff,0xff,0x83,0x36,0x20,0x55,0xff,0xff,0xff, + 0xff,0xff,0x3f,0x15,0xf0,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0xc2,0xff,0xff,0x48,0x4a,0x85, + 0x49,0xff,0xff,0xff,0xff,0xff,0x7f,0x59,0xfa,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0xf5,0xff, + 0x7f,0x10,0x29,0x50,0xa5,0xff,0xff,0xff,0xff,0xff,0x3f,0x15,0xf9,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x97,0xe4,0xff,0x7f,0x05,0x95,0x42,0xd5,0xff,0xff,0xff,0xff,0xff,0x7f, + 0x35,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xab,0xea,0xff,0xbf,0xa0,0x24,0xa8,0xd4,0xff,0xff, + 0xff,0xff,0xff,0x7f,0x19,0xf9,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x27,0xe5,0xff,0x3f,0x92,0xaa, + 0x50,0xe9,0xff,0xff,0xff,0xff,0xff,0x9f,0x4a,0xfc,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa9,0xe2, + 0xff,0x9f,0xa0,0xaa,0x2a,0xf5,0xff,0xff,0xff,0xff,0xff,0x5f,0x1a,0xf9,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x95,0xf8,0xff,0x5f,0x4a,0x92,0x4a,0xf5,0xff,0xff,0xff,0xff,0xff, + 0xbf,0x4a,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0x52,0xf2,0xff,0x1f,0x20,0x49,0xa5,0xfa,0xff, + 0xff,0xff,0xff,0xff,0x5f,0x1a,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaa,0xf8,0xff,0x47,0xa9, + 0x2a,0x29,0xf9,0xff,0xff,0xff,0xff,0xff,0xbf,0x0a,0xfc,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x49, + 0xf2,0xff,0x17,0x92,0xaa,0xaa,0xfe,0xff,0xff,0xff,0xff,0xff,0x9f,0xac,0xfe, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x9f,0x2a,0xf8,0xff,0x43,0xa8,0x24,0x25,0xff,0xff,0xff,0xff,0xff, + 0xff,0xaf,0x0a,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x94,0xfa,0xff,0x91,0x54,0xaa,0x52,0xff, + 0xff,0xff,0xff,0xff,0xff,0x2f,0x4d,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0x45,0xfc,0xff,0x03, + 0x92,0x52,0xaa,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x06,0xfc,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf, + 0x12,0xfe,0xff,0x50,0xaa,0x2a,0x95,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0xa5, + 0xfe,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0x44,0xff,0xff,0x0a,0x25,0xa5,0xa4,0xff,0xff,0xff,0xff, + 0xff,0xff,0x97,0x06,0xfc,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2b,0x15,0xff,0xff,0x40,0xa9,0x92,0xea, + 0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x55,0xfd,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xa1,0xff,0x7f, + 0x92,0x4a,0xaa,0xd4,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x06,0xfc,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x95,0x8a,0xff,0x3f,0x84,0x54,0xa9,0xea,0xff,0xff,0xff,0xff,0xff,0xff,0x2f, + 0x25,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x52,0xe0,0xff,0xbf,0x50,0xa9,0x4a,0xf2,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0x8e,0xfe,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xa9,0xea,0xff,0x3f,0x24,0x95,0x54, + 0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0x57,0x23,0xfe,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x4a,0xf0,0xff, + 0x9f,0x50,0x69,0x49,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x8b,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xa5,0xf4,0xff,0x0f,0x2d,0x75,0xaa,0xfa,0xff,0xff,0xff,0xff,0xff,0xff, + 0xaf,0x03,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x9f,0x14,0xfa,0xff,0x2f,0xa8,0xfa,0x25,0xfd,0xff,0xff, + 0xff,0xff,0xff,0xff,0x97,0xd7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xaa,0xfc,0xff,0x0f,0x4d,0xfd, + 0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0x83,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x12,0xfc, + 0xff,0x27,0x92,0xfe,0xcb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0xd7,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x97,0x0a,0xff,0xff,0x83,0x56,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xef,0xc7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xab,0x24,0xff,0xff,0x2b,0xaa,0xfe,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xe7,0xef,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x45,0xff,0xff,0x05,0x95, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0x82, + 0xff,0xff,0x51,0xa9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xa9,0xe8,0xff,0xff,0x85,0xca,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0x52,0xc1,0xff,0xff,0x90,0xd5,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x4d,0xe8,0xff,0xff,0xa5, + 0xe4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x51, + 0xf2,0xff,0x7f,0x40,0xd5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x3f,0x95,0xf8,0xff,0x7f,0xa9,0xea,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x15,0xfa,0xff,0x3f,0xa4,0xf4,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xa4,0xfc,0xff,0x7f, + 0x71,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f, + 0x15,0xfe,0xff,0x3f,0x94,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xa7,0x0a,0xff,0xff,0x1f,0x79,0xf2,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xab,0xa4,0xff,0xff,0x5f,0x8c,0xfa,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x53,0x82,0xff,0xff, + 0x1f,0x5c,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xa4,0x92,0xff,0xff,0xbf,0x56,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x9a,0xc4,0xff,0xff,0x0f,0x2e,0xfd,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa2,0xf0,0xff,0xff,0xaf,0xa7,0xfe, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x55,0xe4,0xff, + 0xff,0x0f,0x57,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xbf,0x54,0xf2,0xff,0xff,0x9f,0x4b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x9f,0x92,0xf8,0xff,0xff,0xc7,0xab,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x15,0xfe,0xff,0xff,0x97,0xd7, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xa7,0x94,0xfc, + 0xff,0xff,0xc7,0xe3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x2f,0x05,0xfe,0xff,0xff,0xcf,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x53,0xa9,0xff,0xff,0xff,0xd3,0xeb,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x05,0xff,0xff,0xff,0xe3, + 0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x54,0xc2, + 0xff,0xff,0xff,0xeb,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x95,0xc8,0xff,0xff,0xff,0xf3,0xfa,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xa5,0xd2,0xff,0xff,0xff,0xff,0xf5,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xaa,0xe0,0xff,0xff,0xff, + 0xff,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x49, + 0xf8,0xff,0xff,0xff,0xff,0xfa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x9f,0x2a,0xf5,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x4a,0xf8,0xff,0xff,0xff,0xff,0xfc,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x14,0xfd,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x97, + 0x4a,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xab,0x04,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x95,0x52,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x53,0x85,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x54,0xa2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x4a,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xa5,0xe0,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x94,0xe4,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x5f,0x55,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xbf,0x12,0xf9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x54,0xfa,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0x0a,0xfc, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x53,0x45,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x97,0x14,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4b,0x45,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x54,0x82, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x4a,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x52,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x55,0xe8,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x24, + 0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0x55,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x24,0xf9,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x15,0xfe,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f, + 0x49,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x2f,0x95,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x5f,0x01,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2f,0xd5,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x57,0x81,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x97,0xd4,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xaf,0xe0,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x93,0xf4,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x57,0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x2b,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x89,0xfc,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xfc, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x05,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x49,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x89, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xc1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xe9,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xf2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff, + 0xff,0xff,0xff,0x9f,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xf9,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xfc,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, + 0x6f,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff, + 0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f}; diff --git a/tests/auto/gui/image/qimagewriter/images/kollada.png b/tests/auto/gui/image/qimagewriter/images/kollada.png Binary files differnew file mode 100644 index 0000000000..2abd4bb763 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/kollada.png diff --git a/tests/auto/gui/image/qimagewriter/images/marble.xpm b/tests/auto/gui/image/qimagewriter/images/marble.xpm new file mode 100644 index 0000000000..e59830bbe9 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/marble.xpm @@ -0,0 +1,329 @@ +/* XPM */ +static char *dummy[]={ +"240 240 86 2", +"#t c #959595", +"#r c #9a9a9a", +"#l c #9b9b9b", +"#e c #9c9c9c", +"#f c #9d9d9d", +"#n c #9e9e9e", +"#q c #9f9f9f", +"#j c #a0a0a0", +"#k c #a1a1a1", +"## c #a2a2a2", +"#g c #a3a3a3", +"#s c #a4a4a4", +"#d c #a5a5a5", +"#b c #a6a6a6", +"#p c #a7a7a7", +".8 c #a8a8a8", +"#o c #aaaaaa", +".5 c #ababab", +"#a c #acacac", +".6 c #adadad", +".9 c #aeaeae", +".7 c #afafaf", +"#i c #b0b0b0", +"#. c #b1b1b1", +"#h c #b2b2b2", +".4 c #b3b3b3", +"#c c #b4b4b4", +".3 c #b5b5b5", +".U c #b6b6b6", +".O c #b7b7b7", +".1 c #b8b8b8", +".V c #b9b9b9", +".2 c #bababa", +".W c #bbbbbb", +".X c #bcbcbc", +".Z c #bdbdbd", +".L c #bebebe", +".Y c #bfbfbf", +".N c #c0c0c0", +".R c #c1c1c1", +".M c #c2c2c2", +".P c #c3c3c3", +".S c #c4c4c4", +".Q c #c5c5c5", +".T c #c6c6c6", +".H c #c7c7c7", +".E c #c8c8c8", +".K c #c9c9c9", +".F c #cacaca", +".I c #cbcbcb", +".J c #cccccc", +".B c #cdcdcd", +".G c #cecece", +".z c #cfcfcf", +".D c #d0d0d0", +".A c #d1d1d1", +".C c #d2d2d2", +".o c #d3d3d3", +".y c #d4d4d4", +".v c #d5d5d5", +".n c #d6d6d6", +".u c #d7d7d7", +".w c #d8d8d8", +".p c #d9d9d9", +".m c #dadada", +".h c #dbdbdb", +".s c #dcdcdc", +".g c #dddddd", +".x c #dedede", +".i c #dfdfdf", +".f c #e0e0e0", +".q c #e1e1e1", +"Qt c #e2e2e2", +".d c #e3e3e3", +".# c #e4e4e4", +".c c #e5e5e5", +".r c #e6e6e6", +".a c #e7e7e7", +".b c #e8e8e8", +".l c #e9e9e9", +".e c #eaeaea", +".t c #ebebeb", +".j c #ececec", +".k c #eeeeee", +".0 c #f0f0f0", +"#m c #f2f2f2", +"Qt.#.a.a.a.b.c.d.e.e.a.b.a.c.c.b.c.c.cQt.f.f.g.h.g.h.g.h.f.i.i.iQtQtQtQtQt.cQtQtQt.i.f.f.fQt.d.c.a.a.a.a.a.a.a.a.a.b.a.a.a.c.a.c.e.e.e.e.e.e.j.e.j.j.j.j.j.j.k.j.k.j.k.j.j.k.j.j.e.e.e.e.l.a.a.a.#.c.#.c.a.a.a.e.e.e.l.e.e.l.e.e.e.e.e.e.e.e.e.e.j.e.j.j.j.e.j.e.e.e.l.e.e.l.e.e.l.e.e.l.e.e.l.e.l.e.l.e.l.e.l.e.c.c.#.#QtQt.m.g.n.o.p.i.i.m.i.#.#.#.#.#QtQt.qQt.#.#.#.#.#.#.#.#.a.a.a.a.a.a.r.a.a.r.a.r.a.r.a.r.a.r.a.a.#.c.c.c.r.a.r.l.a.a.a.a.e.e.l.a.a.a.c.c.r.#.s.h.h.p.n.h.f.i.gQt.#.d.d.f", +".h.g.c.a.a.a.r.c.e.a.b.c.c.a.c.c.r.cQtQt.f.i.g.h.h.h.p.g.g.g.g.i.iQtQtQtQtQtQtQt.f.iQt.q.fQtQt.d.l.a.l.a.l.a.l.a.b.a.b.a.r.a.r.a.e.l.j.l.j.l.e.e.t.e.j.e.j.j.j.e.j.k.j.j.k.j.j.k.e.e.l.e.e.a.l.a.#.c.#.c.a.l.a.e.e.l.e.e.l.e.e.l.e.e.e.e.e.e.e.b.j.e.j.j.e.j.e.j.e.l.e.e.l.e.l.e.l.b.l.e.e.l.e.e.e.l.b.l.b.l.b.l.#.aQt.c.i.f.i.m.p.u.h.i.i.qQtQt.q.#.r.#Qt.#QtQtQt.#.#.#.c.c.#.c.r.l.r.l.a.r.a.l.#.a.r.a.r.a.r.a.r.a.r.c.r.c.a.c.r.a.r.a.c.a.c.a.l.e.e.a.b.cQt.c.qQt.i.m.p.v.p.m.f.sQtQt.q.cQt.q", +".v.h.i.f.a.r.a.b.a.b.a.c.a.r.c.c.c.cQtQt.f.f.g.h.u.u.u.p.u.h.g.hQtQtQtQtQtQtQtQt.i.fQt.fQt.d.c.c.a.a.a.a.a.a.a.a.a.r.a.c.a.c.a.c.e.e.e.e.e.e.j.e.j.l.j.j.j.j.k.j.k.e.j.j.j.j.j.e.e.e.e.e.l.a.a.r.cQt.c.c.a.a.b.a.l.e.l.e.e.l.e.l.e.b.e.e.b.e.e.e.e.j.j.j.e.j.e.t.e.l.e.l.e.b.l.e.b.a.e.b.l.e.b.l.b.a.e.a.e.a.e.a.a.a.#QtQtQt.i.g.p.p.pQtQt.#Qt.q.#.a.r.#.#Qt.#Qt.a.r.c.r.a.r.a.r.a.a.a.r.a.a.r.a.#.r.a.r.a.r.a.r.a.r.a.a.c.c.#.a.a.a.a.a.r.a.a.a.e.e.l.a.a.c.c.c.a.i.i.p.p.u.h.m.i.f.i.c.c.c.d.f", +".h.h.m.f.cQt.b.b.a.c.a.c.c.c.d.d.fQtQtQt.f.i.g.g.v.u.p.v.p.u.h.h.i.g.i.m.gQtQtQt.s.qQtQtQt.c.#.c.a.a.e.a.l.b.l.a.b.a.b.a.r.a.r.a.e.e.t.e.t.e.l.e.l.j.e.e.j.e.j.j.j.j.k.j.k.j.j.k.e.e.e.e.l.a.l.a.d.#.#.c.a.a.l.a.e.l.e.e.l.e.l.e.e.e.e.e.e.e.b.e.e.j.e.e.j.b.j.e.b.e.l.b.e.l.e.e.l.e.l.l.b.l.l.e.l.b.e.l.b.l.b.e.b.a.#.c.qQt.q.f.u.g.i.i.qQt.#.s.a.r.a.c.c.#.c.c.#.c.#.c.#.a.c.a.a.r.l.a.l.r.a.r.r.a.r.a.r.a.r.a.r.a.r.c.r.a.c.a.a.l.r.l.a.l.b.a.e.l.e.b.aQt.cQtQtQt.s.g.v.u.w.f.gQt.#.cQt.c.f.q", +".h.v.h.g.d.d.a.a.r.a.c.r.c.c.cQt.d.f.f.f.f.i.m.g.g.h.u.p.p.u.u.h.i.i.s.i.i.i.i.i.fQt.iQt.#.c.a.c.a.a.a.a.a.a.a.a.a.r.a.c.aQt.a.c.e.l.e.e.e.e.j.j.j.l.j.e.j.k.j.j.k.e.k.e.j.j.j.e.e.e.e.l.e.a.a.r.#.c.#.c.a.a.b.a.e.b.l.e.b.l.e.b.l.l.b.l.l.b.l.l.e.e.t.j.e.l.e.j.l.e.l.e.l.e.l.e.#.e.#.e.a.e.e.l.a.l.a.b.a.e.a.l.b.l.a.c.#.gQt.i.g.g.s.iQt.#.#Qt.r.a.r.a.c.c.c.c.l.a.l.a.l.r.a.r.a.l.a.r.a.a.a.a.r.a.r.a.r.r.a.r.a.r.a.a.c.c.#.a.a.a.a.a.a.b.a.b.l.e.b.a.a.c.cQtQt.i.i.m.p.w.i.f.d.#Qt.c.c.c.d.d", +".x.h.v.w.hQt.c.bQt.c.a.c.c.dQt.d.f.g.f.i.fQt.f.s.f.g.g.g.u.h.p.h.u.g.h.g.h.f.g.g.qQtQt.c.#.c.#.c.a.a.a.a.l.a.l.a.b.a.c.b.c.r.a.b.l.e.j.e.j.l.e.e.j.j.j.j.j.e.k.e.k.j.j.k.j.k.j.k.e.e.e.e.l.a.a.a.c.i.#.c.a.a.a.b.l.e.l.e.l.e.e.l.e.e.l.e.e.l.e.e.l.e.e.e.j.l.b.l.e.l.b.l.r.l.b.e.l.e.l.e.l.b.a.b.e.b.l.e.l.e.l.b.l.b.l.#.c.#QtQt.m.i.f.iQtQtQt.q.#.a.r.c.a.a.b.e.a.a.a.a.a.l.a.l.a.a.l.a.l.a.l.a.r.r.a.r.a.a.r.a.r.a.r.c.r.a.c.a.l.l.l.l.b.a.a.b.e.e.l.a.#.cQt.c.c.f.s.g.m.m.f.fQt.f.c.b.a.r.r.d", +".f.g.n.v.n.x.q.d.c.c.d.dQt.d.fQt.f.fQt.gQtQtQtQtQtQt.f.f.f.g.m.h.h.p.u.v.p.h.g.iQtQt.#Qt.c.a.c.c.a.l.a.l.b.a.a.a.b.a.r.aQt.c.a.b.b.l.e.l.e.e.j.e.t.e.j.e.j.j.k.j.j.j.j.e.k.e.j.j.e.e.e.l.e.a.l.rQt.#.c.c.a.a.a.a.e.e.e.l.e.l.e.e.l.l.l.l.l.e.l.l.e.j.e.j.l.b.l.e.b.l.b.l.e.l.a.b.a.b.a.e.#.e.l.l.a.e.#.e.#.e.a.e.l.e.a.a.q.#.fQt.f.gQt.iQtQtQtQt.#.#.r.a.a.b.e.b.l.l.e.l.e.l.a.l.a.a.a.a.a.a.a.a.a.r.a.r.a.r.a.r.a.r.a.a.c.c.c.a.l.e.l.a.a.a.b.l.e.b.a.a.c.c.c.q.d.g.f.m.g.sQt.c.dQt.c.#.b.r.c.r", +".f.f.g.o.y.s.f.q.c.c.d.#.f.dQt.q.f.f.fQtQtQtQtQtQt.q.dQt.f.f.x.g.p.u.p.u.u.h.p.h.iQt.#.#.c.#.c.l.a.a.a.a.l.a.l.a.b.a.c.a.cQt.c.a.l.e.j.e.j.e.l.e.j.e.j.e.j.j.j.j.j.k.j.k.j.k.j.j.e.e.e.e.l.a.a.aQtQt.#.c.a.l.a.a.b.l.e.b.l.e.b.l.l.b.e.l.b.l.l.b.l.j.e.j.e.l.e.l.a.e.l.b.a.b.e.l.e.l.b.l.e.l.b.l.b.e.l.e.l.b.l.r.l.b.l.#.c.#.qQt.gQt.fQt.qQt.qQt.dQt.a.a.a.e.e.e.l.a.l.l.a.e.l.e.e.a.l.a.l.a.l.a.r.a.r.a.r.a.r.a.r.a.r.c.r.c.a.a.l.a.a.b.a.e.b.b.#.l.e.a.#.cQt.d.d.f.s.m.iQtQt.cQtQt.a.b.#.b.c.#", +".b.i.f.x.w.z.A.pQt.d.g.x.g.g.h.g.f.d.dQt.dQt.c.c.#.c.#Qt.iQt.s.x.u.y.z.B.C.y.g.g.#QtQt.c.#.a.a.c.a.l.b.l.a.a.a.a.#.c.c.c.c.d.c.c.b.a.a.a.a.a.e.a.l.l.l.l.l.l.e.l.j.e.j.e.e.e.e.j.j.j.l.e.a.a.c.c.iQtQt.#.a.#.b.e.a.a.a.a.b.a.a.a.l.a.l.#.l.l.l.l.l.b.l.b.l.b.l.b.l.b.a.a.#.qQtQt.c.a.c.aQt.a.#.a.b.l.r.l.b.l.e.l.l.a.a.#.q.dQt.g.i.sQtQt.i.c.a.a.#.r.r.a.a.b.b.b.b.a.b.a.b.a.a.e.l.l.l.e.l.a.a.a.r.a.a.r.a.r.a.a.a.a.l.a.b.l.b.b.b.l.a.a.a.a.a.a.e.#.a.#.a.#.a.#.q.i.d.i.i.d.c.c.r.b.r.b.c.r.#.c", +".b.c.f.f.p.A.o.v.dQt.q.x.g.w.f.i.f.d.d.c.c.c.a.c.#.c.#.cQtQtQt.i.p.n.z.D.B.C.o.u.i.iQt.i.#.c.c.c.c.c.#.c.c.c.c.c.c.#.#.i.#.d.c.c.a.a.a.b.l.b.a.a.l.l.l.b.l.l.e.e.e.j.j.j.j.j.e.j.e.j.l.e.a.c.c.cQtQt.c.c.c.a.a.b.a.a.b.a.a.a.b.a.e.l.l.l.l.e.l.l.b.a.l.r.l.a.l.r.b.l.#.aQt.c.#Qt.a.a.#.a.a.a.c.a.b.e.l.b.e.a.b.a.b.l.#.#.cQt.i.f.g.f.x.fQt.c.c.r.r.r.#.a.a.a.e.b.a.a.a.a.a.b.a.e.l.l.l.l.l.l.a.l.r.#.a.r.a.a.a.l.a.l.b.a.e.b.e.e.a.a.b.a.a.b.#.a.a.a.#.a.#.a.#.a.c.qQt.i.dQt.c.#.b.b.#.b.r.c.c.b", +".b.aQt.f.m.h.o.o.m.s.g.s.h.g.sQt.dQt.c.c.c.c.c.c.a.c.c.c.#.dQt.g.i.h.y.A.C.v.v.p.m.g.g.f.f.fQt.#.c.c.a.c.#.c.#.c.#QtQtQtQt.#.c.c.a.a.a.l.a.l.l.l.l.l.l.l.l.l.e.l.e.e.e.l.e.l.e.l.e.e.e.#.b.aQt.c.i.f.q.c.a.c.b.b.a.#.a.b.#.a.a.#.l.e.l.b.l.l.b.l.l.l.b.l.b.l.l.l.r.a.#.q.#.c.i.c.#.c.a.c.#.a.#.a.a.l.b.l.l.b.l.e.l.a.aQt.#Qt.f.g.i.iQtQt.i.#.a.a.r.r.#.r.a.c.b.b.a.b.a.b.a.a.e.e.l.l.e.l.l.a.a.a.a.r.a.#.r.a.a.a.l.a.a.e.e.l.b.l.a.a.a.a.b.a.a.a.#.l.#.a.#.a.#.a.q.d.i.i.cQt.c.c.b.b.b.b.c.b.#.a", +".aQtQt.f.x.g.u.o.o.p.o.u.n.g.f.c.c.d.c.c.a.r.a.b.a.a.#.c.cQtQt.d.q.s.h.v.u.v.u.u.p.p.p.g.m.g.g.fQt.#Qt.#.#.c.#Qt.i.q.gQt.iQt.c.c.a.a.a.a.a.a.a.a.a.r.#.a.l.e.a.b.l.e.l.e.l.b.l.e.e.t.e.a.c.c.dQtQtQt.#.c.c.b.a.b.a.b.a.a.a.b.a.b.a.a.a.a.#.a.r.a.#.r.a.r.a.r.#.aQt.#Qt.c.#.c.#Qt.a.a.a.r.a.a.r.a.a.#.aQt.a.c.a.c.a.#.#.#.c.q.f.f.s.f.sQtQt.c.aQt.a.r.#.a.a.b.a.a.e.a.a.e.a.e.e.e.e.l.l.a.e.a.l.a.r.a.r.a.a.a.a.b.e.l.e.e.e.b.e.b.b.a.b.#.a.a.#.a.b.#.c.cQt.c.q.c.q.#.f.c.f.c.a.c.b.#.a.a.#.b.c.b", +".d.d.dQt.s.s.h.w.v.z.o.v.h.i.f.#.c.c.c.c.c.a.b.a.a.b.a.c.c.f.dQtQt.q.m.h.h.u.p.p.h.w.p.h.h.g.g.g.gQt.iQtQtQtQtQt.i.i.iQtQtQt.#.c.#.a.a.b.l.a.a.a.a.l.r.l.#.a.l.a.#.b.e.a.b.a.e.e.l.e.a.a.c.c.d.dQtQt.c.#.#.c.b.l.b.a.#.a.#.a.a.#.a.#.a.a.r.a.#.a.a.a.#.a.#.a.a.aQt.qQt.#Qt.#Qt.c.#.c.a.c.aQt.a.#.c.a.a.b.a.#.a.#.a.a.c.iQt.f.f.f.i.iQt.iQt.#.a.a.a.a.r.a.c.a.a.b.a.b.l.e.e.e.a.e.l.e.b.a.b.a.b.a.a.#.r.a.a.b.c.a.a.e.e.a.e.l.b.l.a.a.a.b.a.a.r.aQt.a.c.q.c.q.cQt.#QtQtQtQtQt.cQt.b.a.r.b.c.c.c.c", +".g.d.g.f.h.m.h.u.z.E.F.B.n.h.fQt.c.c.c.b.a.r.a.b.b.a.b.a.c.c.c.d.s.i.g.m.h.g.h.w.h.g.h.m.h.g.m.x.i.i.i.i.f.s.i.s.h.s.g.iQtQt.i.c.r.a.a.r.a.a.a.r.#.a.a.a.a.a.b.a.b.a.l.b.l.a.a.a.b.e.a.r.c.cQtQtQt.q.#.c.r.a.b.b.a.a.a.b.aQt.a.c.r.c.r.#Qt.#.a.cQt.#.#.c.#.#Qt.#.iQt.d.qQt.#.c.#.a.r.a.#.a.b.a.a.cQt.cQt.c.c.c.c.c.qQt.#.d.i.f.g.i.g.q.fQt.c.a.c.a.a.a.a.#.a.a.a.b.a.a.e.a.e.a.a.e.e.l.e.a.a.c.r.r.a.a.a.c.a.b.b.l.l.a.b.a.b.e.b.a.b.a.aQt.a.#.a.c.c.cQt.c.f.#.c.i.#QtQtQt.r.c.aQt.c.d.#.fQt.f.d", +".x.q.x.x.h.p.w.v.G.H.E.I.C.o.g.x.c.c.c.b.a.a.e.e.a.e.b.b.b.c.c.c.f.f.f.f.f.f.g.i.h.h.g.h.g.g.f.iQt.f.g.g.g.m.g.m.g.h.i.iQt.i.#.#.c.#.q.c.#.#.c.q.#.r.a.a.c.a.a.b.a.b.a.b.a.b.a.a.e.a.#.c.c.dQt.dQtQt.c.c.a.c.b.a.b.a.a.a.a.b.a.#.c.q.cQt.#Qt.#.#.c.q.c.q.c.q.c.q.f.f.iQt.c.i.a.q.a.c.a.c.aQt.aQt.c.c.c.c.cQt.cQt.#.a.#.i.f.f.f.g.s.iQt.iQt.#.c.#.a.a.a.a.a.c.a.r.a.e.a.e.e.a.b.l.e.e.e.b.e.b.b.#.a.a.cQt.b.c.b.b.l.a.e.a.l.b.a.b.#.a.#.a.a.a.c.aQt.c.i.#.i.c.f.#Qt.#.f.c.cQt.cQtQt.d.i.fQt.q.f.f", +".s.w.h.p.h.n.v.o.p.A.F.J.I.B.o.h.c.a.c.b.a.b.a.a.b.e.b.e.a.r.c.c.x.i.f.iQtQt.f.f.p.p.h.h.w.i.i.f.i.i.f.i.f.i.f.g.g.p.m.g.i.q.d.#.i.c.#.c.#.c.#.#.r.a.q.a.a.#.r.a.a.a.e.a.a.a.b.a.#.a.c.c.cQt.d.dQtQt.#.cQt.a.a.e.a.r.a.b.a.a.c.a.q.c.#.q.#Qt.#Qt.q.#Qt.#.c.qQtQt.g.g.dQtQt.#.#.c.a.a.#.a.r.a.a.a.c.cQt.cQt.c.c.c.c.#QtQt.f.f.m.x.g.f.q.fQt.c.c.a.a.a.a.a.a.r.#.a.a.a.a.e.a.e.a.a.e.e.e.b.e.a.b.b.a.a.a.c.a.b.l.b.a.l.a.b.a.b.e.b.a.a.r.aQt.b.#.aQt.#.f.fQt.iQtQtQtQtQtQtQt.cQt.c.fQt.f.h.x.x.h.s", +".h.u.v.u.v.u.h.gQt.f.n.o.B.B.D.B.h.fQt.c.a.a.b.a.e.l.e.e.a.c.c.f.#.cQt.#.fQt.i.f.q.i.s.p.h.g.p.p.s.i.i.i.i.g.f.i.iQtQtQt.i.i.s.iQtQt.#Qt.#.i.#.i.a.#.r.r.a.r.l.l.a.a.a.#.a.a.a.a.#.c.#.c.#Qt.#.#.iQt.c.c.a.b.b.e.l.e.l.#.b.c.b.c.dQt.iQt.f.i.s.g.s.s.i.s.i.m.sQt.f.iQt.q.c.#.a.bQt.d.c.#.a.a.#.a.#.#.c.#QtQt.i.f.q.#Qt.i.i.g.i.g.x.s.q.iQt.q.#.#.#.a.a.a.a.a.l.a.c.r.c.c.c.c.c.b.e.l.a.l.a.b.c.aQt.a.a.a.c.a.b.b.l.a.a.a.a.cQt.c.c.c.i.d.dQt.dQt.cQt.#QtQtQtQt.d.#.a.cQt.cQt.d.d.g.f.x.h.w.u.u.v", +".u.p.h.h.p.m.g.x.q.f.g.u.C.B.z.o.v.fQt.c.l.a.a.a.e.e.b.l.b.c.c.c.c.cQt.c.d.d.fQt.x.i.g.g.p.u.p.u.h.i.i.g.s.i.i.f.s.f.q.f.iQt.i.f.q.g.q.i.qQt.f.q.r.r.r.#.#.a.a.a.a.a.a.c.aQt.c.q.c.#.#Qt.#.#.c.#Qt.c.#.a.c.a.l.b.b.l.e.b.a.#.c.a.q.cQtQtQtQt.i.m.i.p.m.g.u.w.m.s.m.g.fQt.qQt.#.#.q.#.q.c.#.a.a.#.c.q.c.q.cQt.cQt.q.r.iQt.g.i.x.gQt.iQt.qQt.#.#.c.a.a.#.a.l.a.a.l.c.c.c.c.c.c.a.c.l.e.b.a.b.c.a.c.r.a.#.a.a.#.a.b.b.a.b.a.r.a.c.c.c.c.cQt.c.i.c.i.c.c.q.dQtQt.fQtQt.#Qt.#.d.i.d.i.i.g.m.g.n.v.u.p", +".h.h.m.g.g.f.fQt.#Qt.g.g.y.B.B.v.h.h.f.c.c.a.b.a.e.l.e.a.a.b.c.c.#.c.c.qQtQt.xQt.i.g.g.w.h.p.v.p.p.h.h.g.i.i.s.i.i.fQtQt.q.f.iQt.i.s.i.m.i.s.i.s.q.iQt.#Qt.#.i.#.c.c.c.c.#.c.#.c.#.c.#.#.c.#.#.cQt.i.c.c.a.r.b.e.a.e.l.a.a.r.a.r.c.q.#.iQt.i.q.s.i.h.n.o.z.A.z.v.w.g.m.f.f.d.g.dQt.dQt.c.c.c.#.c.#Qt.#.c.#QtQtQt.#.iQtQt.i.i.m.i.s.xQt.iQt.q.c.#.a.#.a.a.#.a.#.aQt.cQt.cQt.c.c.c.#.a.a.a.a.c.c.c.r.a.a.c.a.c.e.b.a.#.a.c.#.c.c.c.fQt.fQt.dQt.fQtQt.#Qt.c.i.cQt.dQt.dQt.fQt.dQt.f.h.g.g.g.v.h.n.v", +".f.f.f.fQtQt.d.d.b.c.f.f.p.C.A.v.h.v.i.c.a.c.a.r.e.e.c.b.c.a.b.a.a.#.#.c.cQtQt.d.m.f.g.h.h.p.u.u.o.u.u.g.g.i.fQt.s.i.s.fQtQtQtQt.i.f.g.g.g.g.m.g.i.s.i.xQtQtQtQt.#.c.q.c.#.c.c.#.c.#Qt.c.c.c.c.qQt.c.#.c.c.a.b.a.b.l.b.b.a.aQt.a.a.q.cQtQtQt.x.f.u.p.o.z.J.K.B.A.p.v.n.w.w.x.g.h.f.g.d.i.d.iQt.c.iQt.#.iQtQt.iQt.iQtQt.s.x.s.x.gQt.f.qQt.f.#.#.c.c.#.a.a.a.a.a.a.c.c.c.dQt.dQt.c.a.aQt.a.a.q.c.#.#.a.a.a.a.r.a.b.a.a.a.b.c.c.cQtQt.cQt.c.i.cQt.d.q.cQt.c.#.f.d.q.d.i.d.fQt.f.g.f.s.g.g.m.h.h.g.h", +"QtQt.#.f.c.c.c.c.a.cQt.d.x.v.v.u.p.w.f.c.#.c.a.c.a.a.b.a.b.a.a.b.a.a.a.c.#.d.#Qt.f.f.i.g.g.h.u.u.y.u.u.h.m.i.s.f.i.i.iQt.x.f.q.fQt.i.f.i.m.g.i.g.s.i.s.i.i.g.fQt.d.#QtQt.iQt.i.c.#.c.#.c.q.c.#.cQtQt.c.#.#.a.b.a.e.a.e.a.a.r.a.c.qQt.#.iQt.q.f.s.A.A.z.B.F.B.o.v.n.v.v.v.v.v.v.v.x.w.g.h.x.g.f.g.f.g.f.f.g.f.dQt.f.s.i.s.i.m.i.m.g.q.gQt.i.#.f.#.q.c.q.a.c.#.c.#.c.cQt.c.c.c.c.c.q.a.#.c.c.c.#Qt.a.rQt.a.c.#.b.b.#.aQt.cQt.c.dQt.fQt.fQt.dQt.fQtQt.c.r.fQtQtQt.d.gQtQt.i.f.gQt.g.f.f.g.f.f.f.f.f", +".c.c.c.b.b.b.b.b.b.a.a.cQt.x.v.A.p.p.iQt.c.c.c.c.c.c.a.r.a.a.b.a.a.a.c.aQt.#.d.qQtQt.f.i.i.g.m.p.v.u.u.p.p.g.g.i.g.i.i.fQtQtQtQt.s.i.gQtQtQtQt.i.i.q.f.i.f.q.g.i.i.gQt.f.#.d.#.d.c.q.c.#.c.q.c.#.iQt.q.c.cQt.b.a.b.e.#.a.#.cQt.c.cQt.g.iQt.s.i.m.z.A.z.B.B.z.v.p.h.w.h.n.p.v.A.I.I.B.A.v.h.h.w.h.h.h.m.x.x.f.i.f.s.g.m.x.m.g.g.g.q.f.sQtQt.#Qt.d.c.r.cQt.#.c.#.cQt.c.c.c.cQt.c.c.a.r.q.#.#.iQtQt.q.a.#Qt.a.r.a.b.c.a.a.b.a.c.i.cQt.fQt.c.i.cQt.c.q.cQt.#.dQtQt.fQt.f.x.d.d.f.d.d.i.d.c.c.c.c.a.c", +".a.b.b.l.e.b.j.e.b.e.e.a.cQt.g.o.v.g.g.x.#.c.c.c.r.c.c.a.b.a.e.e.#.a.a.a.a.c.c.c.#.cQtQt.fQt.i.g.p.u.p.p.w.p.w.h.i.i.i.i.s.f.q.fQt.qQt.q.gQtQt.i.#.#Qt.#QtQtQt.i.i.g.f.sQt.i.#.c.i.d.c.c.dQt.d.iQt.f.#.c.c.c.a.r.l.l.e.a.c.c.c.c.g.f.f.m.g.m.w.v.o.v.o.B.B.B.u.u.m.x.w.g.w.p.z.B.L.M.F.A.A.o.y.A.o.o.p.h.w.h.w.n.h.w.g.w.g.s.g.f.s.f.i.i.d.fQtQt.#.c.#.c.#.c.q.c.c.c.c.c.c.c.c.c.#.#.c.#.fQtQtQt.r.#.a.#.cQt.b.b.#.a.c.aQt.c.dQt.dQt.d.i.d.i.d.i.c.q.c.c.q.i.d.i.f.gQtQtQt.c.a.#.r.b.b.#.b.b.j.e", +".e.b.e.e.j.j.e.j.b.e.e.#.c.d.x.p.v.h.m.wQt.c.c.d.c.a.c.a.e.a.e.l.l.a.a.c.a.#.c.#.#.c.#.#.iQt.f.q.g.h.u.h.p.h.u.u.s.i.s.f.i.iQtQt.iQt.iQtQt.#QtQt.x.#Qt.#.#.#QtQtQtQtQt.g.f.g.f.g.dQtQt.f.#.f.#.dQt.i.d.q.cQt.a.b.a.a.#.a.#.cQt.c.f.m.g.w.w.p.A.z.v.u.A.B.z.o.p.w.g.m.h.w.w.n.o.o.N.H.I.D.F.F.N.O.N.P.I.A.v.h.n.h.m.h.u.g.w.g.m.i.s.f.gQt.i.dQt.dQtQtQt.#Qt.#.c.q.c.c.c.cQt.c.c.c.#.#Qt.qQt.gQt.i.#.#.#.#.c.c.a.c.c.a.r.a.c.c.c.i.cQtQt.d.i.dQt.d.q.cQt.c.fQt.iQt.g.d.dQt.a.a.b.l.e.r.e.e.b.e.e.k", +".e.e.e.e.e.j.j.j.e.e.b.b.c.d.q.g.u.z.J.D.p.g.c.l.c.b.c.b.a.a.e.e.c.c.a.c.q.c.c.#.c.#.c.#.c.#Qt.#.i.q.i.m.p.v.u.v.u.h.h.i.m.i.i.f.qQtQtQt.xQt.i.#.r.#.#.c.a.a.c.bQt.c.c.c.c.c.qQt.i.g.iQt.f.d.g.f.gQtQt.c.c.a.#.a.b.a.#.c.d.d.f.x.m.p.o.z.B.z.z.o.A.v.v.v.v.u.n.h.h.h.m.m.h.v.z.B.Q.R.F.A.v.z.z.F.B.B.B.F.I.I.J.B.B.z.A.w.p.m.x.g.g.p.g.m.i.iQt.f.#QtQtQtQt.cQtQt.cQt.c.c.c.c.c.cQt.cQt.#Qt.f.g.f.c.c.c.c.a.#.cQt.a.c.c.cQt.c.c.cQt.#Qt.cQtQt.fQt.q.#Qt.x.h.g.dQt.c.aQt.a.b.#.a.b.e.e.e.e.e.e.e.e", +".j.b.e.j.e.j.e.j.j.e.e.b.c.d.q.q.h.v.D.B.z.n.i.c.c.a.c.a.b.a.b.l.a.#.c.#.c.c.q.c.c.c.#.c.c.#.d.#Qt.i.i.h.p.u.y.A.p.h.w.i.f.iQtQt.xQt.qQt.#Qt.#Qt.r.#.r.#.c.a.#.c.c.cQt.cQt.c.cQtQt.f.f.f.g.f.g.i.h.g.f.i.dQt.c.c.c.c.dQt.g.f.h.m.m.m.u.A.z.o.A.v.v.v.p.v.p.u.h.w.f.g.x.m.w.n.B.I.M.S.E.A.z.z.y.z.o.o.o.v.z.B.E.E.P.Q.T.F.I.o.o.p.u.p.u.g.w.x.gQtQt.c.#.c.iQt.c.q.dQt.cQt.c.cQt.c.c.qQt.#Qt.g.f.f.qQt.cQt.c.c.c.c.c.rQt.c.c.cQt.c.cQt.c.c.i.c.i.d.qQt.f.g.x.q.f.c.c.#.b.a.b.a.b.r.b.e.b.e.b.e.e.e", +".e.j.e.k.e.j.j.j.j.k.e.a.r.c.d.q.q.m.v.C.A.u.gQt.c.cQt.c.a.a.a.a.c.c.a.c.#.c.c.#.c.q.c.c.q.c.#QtQt.f.i.m.g.v.u.A.p.u.h.i.m.iQt.fQtQtQt.xQt.#Qt.#.q.a.r.c.a.a.c.b.cQt.#.c.a.c.a.c.c.cQtQt.d.g.g.g.w.w.h.fQt.d.i.d.g.g.s.h.m.w.h.w.i.m.v.o.u.o.v.u.u.h.u.h.u.p.n.h.p.h.m.x.w.u.B.F.M.M.F.C.z.o.u.o.u.u.h.p.u.o.A.z.E.M.N.R.E.E.K.K.I.B.o.u.h.g.x.x.g.iQt.iQt.dQtQtQt.qQtQtQt.#Qt.i.#Qt.i.dQt.g.f.g.c.d.q.c.cQt.cQt.cQt.c.cQt.c.c.#Qt.rQtQtQt.d.i.d.#.i.g.fQt.d.dQt.a.b.a.r.a.r.a.e.e.e.e.e.e.e.e.e", +".e.j.j.e.e.j.e.j.e.e.e.b.c.r.c.dQt.i.g.w.v.o.h.x.c.c.c.c.b.c.b.a.a.c.c.#.c.c.#.c.#.c.#.c.#.c.cQtQtQt.i.i.g.p.v.o.u.p.h.g.i.i.gQt.x.#.i.#QtQt.qQt.a.rQt.a.a.c.a.c.a.a.a.a.a.#.a.aQt.c.c.fQt.dQt.f.x.x.x.h.g.f.g.h.u.n.g.g.g.g.m.g.m.m.p.o.u.v.o.u.w.p.w.w.h.w.m.h.h.x.w.g.n.o.B.Q.U.Q.D.o.C.o.u.v.w.w.u.g.w.h.h.v.v.z.C.B.I.I.E.N.N.Q.I.A.A.v.p.m.i.i.g.f.i.sQt.i.qQt.q.i.f.f.fQt.d.iQt.#.f.g.i.g.c.i.c.f.cQt.c.c.c.c.c.c.c.cQt.c.c.c.#QtQtQtQt.fQt.i.f.i.dQt.c.c.b.#.b.a.b.a.b.e.a.b.b.e.r.e.b.e", +".j.e.e.k.e.k.e.j.k.e.e.e.b.c.c.r.iQt.m.h.w.v.n.u.d.f.c.c.c.#.c.aQt.#.c.c.q.c.c.q.c.q.c.c.#Qt.#QtQtQt.f.s.i.m.p.p.u.p.u.g.m.i.f.qQtQtQtQt.i.#Qt.#.r.#.r.a.a.#.r.a.b.a.bQt.a.c.b.#.a.a.c.c.cQtQt.f.f.g.g.f.x.h.g.w.w.h.g.h.x.h.g.g.i.p.v.A.o.o.A.A.u.w.w.g.w.g.p.m.s.w.p.w.n.o.I.T.V.N.D.o.v.v.h.v.g.i.w.h.u.h.w.h.p.g.u.p.w.u.v.A.Q.T.E.P.F.I.z.u.m.g.g.i.m.g.g.i.g.f.f.f.f.f.f.m.f.g.f.g.f.g.x.gQtQtQtQtQt.c.q.cQt.c.q.c.q.c.c.c.#.q.c.f.c.iQt.i.f.gQt.iQt.a.b.#.b.e.b.b.b.e.e.e.e.e.e.e.e.e.e.e", +".e.k.e.k.k.k.j.e.e.e.e.b.l.b.b.b.c.d.f.w.p.n.v.v.cQt.c.c.c.c.a.r.#.c.c.#.c.#.c.cQt.cQt.c.q.cQtQtQt.iQt.f.g.i.g.m.u.p.u.h.m.i.s.f.i.q.i.dQt.#Qt.#.c.r.c.a.c.a.a.c.l.b.e.l.e.b.l.b.a.c.aQt.a.c.d.#.dQt.dQtQt.g.x.h.h.w.w.w.u.g.w.g.m.h.o.z.v.A.z.z.w.u.w.w.m.h.s.w.p.n.w.p.v.z.F.P.W.P.F.v.o.v.h.p.m.h.g.h.g.w.p.n.i.m.m.m.m.h.h.m.A.A.z.B.Q.Q.P.M.F.K.o.v.p.w.p.u.g.g.g.s.g.m.g.w.x.m.m.g.g.m.g.gQt.i.c.f.#Qt.dQt.c.#.cQt.c.cQt.#.c.cQtQt.i.f.i.d.m.f.i.cQt.a.#.b.a.b.a.e.a.b.a.e.e.e.e.e.e.e.e.e", +".e.j.k.j.j.j.e.k.e.e.e.e.e.e.e.l.rQtQt.f.h.g.p.v.d.dQt.f.c.c.c.a.c.#Qt.c.#.c.#.c.q.c.q.cQt.#.i.c.qQt.g.q.s.f.s.s.p.p.u.g.m.g.f.q.q.i.qQt.iQt.#.i.r.#.r.a.#.a.c.a.b.a.l.r.l.e.l.b.l.b.a.c.aQt.c.i.cQt.cQt.dQt.dQt.s.s.g.p.w.u.p.u.v.o.z.B.B.A.B.H.v.u.w.h.w.h.w.p.h.n.n.o.o.B.I.E.L.X.E.o.o.u.w.h.w.g.w.h.g.s.h.w.h.m.s.m.h.h.g.g.o.u.w.u.o.J.M.Y.L.N.N.H.B.z.o.u.w.w.g.h.m.h.w.p.w.h.w.w.g.m.g.i.f.iQt.f.#QtQtQt.cQt.cQtQtQt.c.cQt.rQt.c.iQt.g.i.x.g.d.#.l.r.a.b.b.e.e.b.e.e.e.b.e.e.e.e.e.e.e.e", +".j.e.k.k.k.k.j.e.e.e.e.e.b.e.b.e.d.d.f.f.f.w.p.p.dQt.d.c.c.c.c.c.q.c.c.#.c.cQt.#.c.c.#.c.#.f.#Qt.dQt.f.g.f.s.s.m.h.u.p.u.m.m.s.g.q.f.xQt.qQt.#Qt.a.r.a.c.a.c.a.r.l.e.l.e.l.e.e.a.e.a.a.a.b.c.a.cQt.a.a.a.c.dQt.d.a.rQt.s.g.w.v.A.z.z.F.F.D.B.E.Q.C.v.v.n.w.p.w.n.n.n.D.A.G.B.F.P.Y.W.T.C.v.v.p.w.g.x.h.w.h.w.h.h.y.u.n.x.x.h.h.h.s.w.u.v.A.A.z.B.K.N.L.N.H.Q.B.o.u.u.u.w.p.w.p.u.h.v.w.w.w.m.s.g.iQt.f.#.f.c.c.i.cQtQt.d.q.cQt.cQt.c.q.d.iQt.f.f.m.x.q.a.b.e.b.#.l.e.l.e.l.b.e.l.e.e.e.e.e.e.e.e", +".k.k.e.j.e.j.e.j.j.j.e.e.e.e.b.e.c.d.dQt.x.x.x.h.h.i.d.c.r.r.r.b.c.c.c.cQt.c.c.c.cQt.cQt.c.c.cQt.i.iQt.i.f.s.f.m.g.m.g.m.h.h.p.gQt.i.qQt.q.r.q.r.b.l.b.r.a.a.q.#.#.a.a.a.a.a.a.l.b.l.b.a.cQt.c.c.#.cQt.cQt.c.#.c.#QtQtQt.i.f.g.m.v.z.I.H.I.I.Q.U.K.J.A.y.y.n.y.y.z.z.B.B.F.I.K.T.M.Z.X.G.u.o.v.u.h.u.g.h.h.v.w.v.w.m.g.h.m.h.x.g.h.m.w.v.w.v.w.u.o.o.A.I.K.N.Z.U.I.z.n.v.h.w.m.u.o.n.w.g.m.f.s.g.i.i.c.f.cQt.cQt.dQtQtQt.c.i.c.q.#QtQt.i.f.g.f.m.cQt.r.c.c.bQt.b.b.r.e.b.e.l.e.e.j.j.j.k.j.k.k.k", +".k.0.j.k.e.j.e.j.e.k.e.e.e.b.l.b.c.dQt.q.f.f.f.f.m.i.g.d.c.r.a.b.c.c.c.c.c.c.c.c.c.c.c.c.cQt.c.c.#.iQt.i.i.g.h.i.m.g.p.g.w.g.w.h.s.iQtQtQt.#.#.#.r.l.r.#.r.a.#.c.a.a.a.b.a.l.#.a.b.l.b.a.a.a.cQt.a.q.c.c.c.c.c.c.c.c.q.dQt.f.f.f.g.h.o.z.B.B.S.1.O.Y.P.K.A.A.K.P.Q.H.B.B.I.I.Q.K.M.W.W.I.v.o.p.v.w.h.h.u.p.v.p.v.w.h.m.h.m.h.h.g.m.m.h.m.w.w.w.w.n.u.n.o.o.B.B.K.Z.Z.P.Q.H.z.z.z.A.B.A.n.u.w.h.m.f.gQt.i.cQt.r.c.f.#.f.#.dQtQt.f.c.qQt.iQt.s.f.g.rQt.c.#.c.#.c.r.#.a.e.a.b.b.e.e.j.k.j.j.k.k.0.k", +".k.j.k.j.k.k.b.j.j.j.e.e.e.e.b.e.c.c.d.q.d.g.f.f.g.g.f.f.d.d.c.c.cQt.c.c.c.c.cQt.cQt.c.cQt.c.c.q.c.q.#.iQt.i.f.g.s.i.s.g.p.g.p.g.m.i.s.i.i.q.i.#.#.r.r.r.a.a.#.c.l.a.a.r.a.a.a.l.b.l.b.a.b.c.#.c.c.#.cQt.c.#.cQt.c.c.cQtQtQt.i.d.s.i.m.v.v.o.z.Q.2.3.2.Z.N.L.Z.U.Y.T.F.F.Q.Q.R.N.S.Y.U.R.B.v.u.o.u.v.v.u.v.u.v.n.m.m.m.x.h.h.g.h.h.m.m.h.m.h.m.m.m.m.w.w.n.n.o.o.z.z.H.N.L.L.L.W.H.S.I.A.u.v.v.u.m.h.f.gQt.f.cQtQt.f.f.i.iQt.fQt.f.#.dQt.f.f.f.g.a.b.r.b.r.b.#.b.a.e.r.e.b.e.e.b.e.e.e.e.k.j.j.j", +".k.k.e.k.j.k.e.j.e.k.e.e.e.e.l.b.c.a.c.cQt.d.d.f.i.s.g.x.f.dQt.c.c.c.c.cQt.c.c.c.a.a.#.a.a.a.a.c.i.#QtQt.iQt.s.f.s.f.s.i.g.i.g.m.g.g.s.i.i.iQt.q.#.#.c.r.#.r.a.#.a.l.#.l.a.l.a.a.e.l.e.a.a.a.r.a.a.a.#.a.a.b.a.b.a.aQt.c.cQt.d.i.f.i.f.m.h.w.v.z.Y.M.M.2.4.5.6.O.1.L.N.T.N.R.Z.Z.N.W.7.L.I.o.u.A.o.p.o.v.v.w.p.p.m.x.m.g.g.g.g.x.g.g.i.g.i.i.g.s.s.h.g.m.h.m.p.h.n.o.o.A.I.E.T.N.M.Z.M.I.B.z.A.v.w.h.m.f.g.f.d.f.f.i.g.f.g.q.i.d.#.f.d.i.dQt.fQt.r.b.l.r.l.b.e.r.b.b.b.e.a.b.e.l.b.l.b.j.e.k.j.k", +".k.j.k.j.e.j.e.j.j.j.e.e.e.e.b.e.a.b.a.c.c.cQt.dQt.f.g.s.xQt.#.c.c.c.c.c.c.c.c.c.a.a.c.aQt.a.#.a.c.q.c.#QtQt.iQt.iQtQt.i.i.g.i.g.i.m.f.i.g.i.g.i.#.#.#.c.#.#.a.a.#.a.a.a.a.#.a.a.l.e.e.#.a.r.a.c.#.a.a.a.#.b.#.b.r.a.b.aQt.c.c.cQt.#.i.g.m.w.u.C.M.T.H.E.Z.4.4.4.U.4.U.U.2.N.N.R.2.U.8.V.Q.z.v.B.u.v.u.w.p.w.s.m.g.g.g.i.g.f.f.i.x.x.f.x.f.x.x.f.q.q.f.s.i.g.i.g.s.g.m.w.n.v.o.B.K.N.1.Z.N.P.F.C.o.v.h.x.f.g.gQt.g.f.g.g.f.g.f.i.d.i.cQt.cQt.c.a.e.b.e.e.b.e.b.e.e.a.e.r.e.e.b.e.l.e.l.b.e.e.e.e", +".j.j.e.k.e.e.e.e.j.j.e.e.e.e.e.e.e.b.e.a.b.c.a.c.cQt.i.h.g.fQtQt.c.cQt.c.c.c.c.c.b.e.l.b.l.e.a.a.#.a.q.c.qQt.qQt.#.q.iQtQtQt.i.f.qQt.x.f.i.i.g.i.i.f.i.#.c.q.a.r.l.a.l.a.l.a.l.a.b.e.l.b.a.#.c.a.b.l.a.b.a.e.b.e.l.e.r.e.b.r.aQt.#.i.i.f.m.m.v.n.z.F.Q.H.E.Q.L.N.1.4.6.6.9.U.U.U.3#.##.V.F.B.o.A.o.u.n.g.h.x.g.x.g.i.d.i.f.f.fQtQtQtQtQtQtQtQtQtQtQtQt.qQtQtQtQt.#.#.q.w.m.v.v.z.B.S.Y.Q.F.Q.Q.Q.I.A.v.h.m.x.x.g.g.g.f.g.f.g.f.g.q.f.dQt.c.b.a.r.e.r.e.r.e.e.e.e.b.b.b.l.e.e.e.e.l.#.l.b.e.e.e.j", +".k.k.k.j.e.e.e.e.j.j.e.e.e.b.e.b.e.l.e.e.e.a.b.cQtQt.f.g.h.gQtQt.c.c.c.c.c.a.c.c.l.b.b.a.e.#.e.b.r.#.r.c.#Qt.cQtQt.#.c.q.iQtQtQt.q.#.#.xQt.i.i.iQtQtQtQt.#.c.r.a.a.a.a.a.a.a.a.a.l.l.b.a.a.r.a.c.l.l.b.l.e.r.l.r.j.e.l.b.a.aQt.cQt.i.i.g.m.h.w.w.v.B.K.I.B.B.F.B.M.L.1.9#..9#a.9.6#b##.V.E.I.A.C.n.w.h.h.f.i.g.f.i.f.i.f.fQtQt.r.r.#Qt.#.#Qt.#.rQtQtQtQt.fQt.rQtQtQtQt.w.s.g.m.m.D.I.A.v.w.A.H.Q.F.H.I.v.h.w.m.f.h.m.h.g.f.g.f.g.d.i.c.cQt.b.e.b.e.b.e.e.b.e.b.e.b.a.e.r.b.#.b.r.a.a.a.a.a.b.e.l", +".j.k.e.k.e.e.b.e.j.k.e.e.e.e.e.e.e.j.e.l.e.r.a.a.cQt.x.h.u.g.f.i.c.c.c.c.c.c.c.c.b.l.l.e.l.e.l.l.r.#.#.#.c.#.q.c.q.a.q.cQt.i.c.i.#.qQt.q.i.qQt.i.i.f.i.f.q.#.a.#.l.r.b.a.l.#.l.a.b.a.e.a.a.aQt.c.b.a.e.a.e.l.b.e.e.b.#.e.b.#.bQt.c.i.f.g.x.m.n.n.o.o.o.o.v.B.I.B.E.Q.M.Z.1#c#c.4#d#e#f.V.K.F.A.o.u.w.h.g.i.dQt.c.i.i.fQt.cQtQtQt.r.b.r.b.r.r.r.r.#.r.#.r.r.r.r.r.f.f.i.g.m.h.m.v.h.C.o.w.n.u.v.n.E.N.M.z.n.h.m.m.m.h.g.g.g.g.g.f.f.dQt.c.#.a.#.e.b.e.e.b.e.b.e.b.b.e.b.l.e.e.l.e.l.a.a.#.a.a.b.b", +".e.e.e.e.e.e.e.e.e.j.j.j.k.j.j.e.e.e.e.e.b.a.b.b.dQt.f.i.w.h.u.h.fQt.q.a.#.a.a.c.e.a.b.a.b.a.b.b.#.a.#.a.#.a.#.a.rQt.r.c.#.a.a.#.r.#.#.aQt.#QtQtQtQtQtQtQtQtQtQt.r.a.r.r.a.r.a.#.l.l.b.a.c.c.d.d.#.l.b.l.b.a.b.l.b.l.b.#.a.c.#.c.c.i.i.g.h.g.m.m.w.D.v.o.o.A.A.A.B.K.P.Q.T.Y.W.W.6#g#g#c.R.P.E.D.m.h.g.x.q.f.q.gQtQtQtQt.#.#.rQt.b.r.r.r.b.r.a.r.b.e.b.b.b.b.b.b.fQt.g.f.f.g.f.h.m.m.m.m.g.h.h.h.o.o.J.Q.Q.B.z.o.v.u.w.w.h.m.x.h.#.#.a.r.b.r.b.e.r.#.r.a.b.e.e.j.j.e.j.b.e.r.b.r.b.l.e.a.e.l.e.l", +".e.e.e.e.e.e.e.e.e.k.j.j.j.j.j.j.e.e.e.e.e.b.e.b.cQt.g.i.p.p.v.p.fQt.c.c.a.#.b.c.l.b.l.e.l.e.l.l.a.b.a.a.#.a.#.a.#.a.#.a.r.#.a.a.l.a.#.r.c.q.c.#Qt.iQt.i.f.i.fQt.r.#.a.a.a.a.r.r.l.l.r.a.cQt.dQt.a.a.e.a.e.l.e.l.b.b.a.#.b.#.c.a.fQt.i.f.g.f.h.h.m.w.n.n.v.y.o.A.o.B.Q.R.R.P.R.Y#h.9#i.L.P.R.E.J.v.w.i.x.#.x.f.d.#Qt.#.cQtQt.r.#.#.a.#.a.r.b.r.r.b.b.j.b.e.b.#.b.cQt.f.x.g.f.x.f.m.m.m.g.g.g.h.f.p.w.v.A.B.I.Q.Q.z.z.v.p.w.w.p.h.aQt.e.r.e.e.b.r.b.c.b.r.e.e.e.b.j.j.j.e.e.e.e.b.l.b.l.b.l.b.e.e", +".j.e.j.k.j.k.j.k.j.e.k.j.j.k.e.k.e.e.e.b.l.b.a.b.c.i.f.f.h.A.C.v.m.fQt.a.a.a.c.a.b.a.e.#.e.#.e.b.l.a.#.l.#.a.a.#.a.a.#.a.#.a.a.#.#.a.a.#.a.c.cQtQt.f.q.fQt.i.f.f.#.#.#.q.#.#.c.#.#.r.#.#.c.c.d.d.#.l.#.l.b.a.e.#.e.e.a.b.#.cQtQtQt.i.g.g.g.s.g.g.h.w.n.v.y.n.A.A.B.B.Q.N.Y.H.Q.Z#h.2.P.K.K.Q.H.B.o.o.h.p.s.x.#.r.#.a.#.rQt.b.r.r.b.r.b.r.b.r.b.#.b.e.e.b.j.b.b.b.#.c.f.g.f.g.fQt.g.s.f.g.f.f.g.x.f.g.x.w.v.o.A.I.Q.Q.B.o.y.h.x.gQt.a.#.b.r.e.r.bQtQt.b.#.e.b.j.j.j.e.j.e.e.b.e.e.b.l.b.l.e.j.l.j", +".k.j.k.j.j.j.k.e.j.k.j.k.e.k.j.j.e.e.e.e.b.b.e.a.c.c.f.m.u.o.C.D.g.fQt.#.a.#.a.c.e.l.e.l.e.l.e.a.l.e.#.a.l.#.l.a.b.l.e.l.e.b.l.e.l.b.l.e.c.#.c.c.iQtQt.gQt.g.f.gQt.iQtQtQt.iQt.i.#.q.#.cQt.#.f.c.a.#.a.b.l.b.l.e.l.r.a.r.aQt.aQt.d.g.f.g.f.g.g.g.h.w.n.n.v.y.A.z.H.Q.P.P.N.R.Z.O.O.Q.J.A.G.y.D.z.z.A.o.h.h.q.#.bQtQtQt.b.r.r.r.bQt.r.r.b.#.b.r.b.b.k.e.j.e.b.j.e.r.#Qt.f.f.g.f.f.f.g.g.f.f.g.d.x.f.g.g.x.w.w.h.v.Q.F.K.B.o.n.h.q.dQt.dQt.c.f.a.r.c.c.r.b.e.e.b.e.b.k.e.k.e.k.j.e.e.e.e.e.e.j.j.j", +".j.j.j.j.j.j.j.j.k.e.j.j.j.j.j.j.e.e.e.a.e.b.a.r.bQtQt.x.h.o.C.C.w.i.f.#.a.a.aQt.e.#.e.#.e.#.e.b.l.e.l.#.a.a.b.l.e.e.b.e.l.e.e.b.e.e.e.b.b.a.b.a.c.c.#.dQtQt.fQt.fQt.f.s.f.i.g.i.#Qt.qQt.dQtQt.c.#.a.b.a.l.b.l.r.e.b.a.a.#.cQt.c.i.f.g.g.f.g.h.i.h.g.w.w.p.n.A.K.F.P.N.M.N.U#i.O.P.G.o.v.h.h.w.n.I.z.A.p.x.s.x.f.x.cQt.#.c.r.b.b.b.r.c.r.b.r.b.b.e.j.e.k.j.e.b.e.bQtQtQtQt.d.f.g.i.i.c.f.i.d.f.f.c.f.f.h.h.w.m.n.o.A.o.o.o.C.n.w.g.g.q.f.c.#.r.b.c.r.e.e.b.e.e.e.j.b.k.b.k.j.0.0.j.j.j.j.e.j.j.k", +".k.j.j.j.k.j.j.k.j.j.k.j.j.e.k.j.e.e.e.e.a.b.b.a.b.d.f.f.h.u.o.v.p.h.f.d.c.#.a.b.l.e.l.e.l.e.l.a.e.#.e.a.#.l.e.l.e.b.l.e.e.b.e.l.j.b.l.e.l.b.b.#.a.#.c.#.#.c.c.iQt.iQt.s.f.s.f.sQt.i.d.#.i.c.cQt.a.#.a.#.l.b.l.e.l.b.b.#.aQt.aQtQt.g.g.f.m.f.w.x.m.p.w.w.o.A.B.K.K.M.Z.U.9#j.8.Z.A.v.w.s.s.s.h.u.v.D.z.A.o.w.s.x.g.x.q.d.r.r.r.b.r.r.b.r.b.r.b.r.j.e.k.k.e.j.e.e.r.bQt.#.#Qt.c.f.i.d.i.f.c.fQt.d.f.f.x.g.x.h.h.n.u.u.h.w.x.n.o.y.o.w.w.x.dQt.c.#Qt.b.r.e.e.e.e.b.e.k.e.j.k.0.e.0.j.e.e.k.e.k.e.k", +".j.0.j.0.j.k.k.j.k.e.k.e.j.j.e.e.e.e.e.b.b.#.b.b.a.fQtQt.h.g.h.h.p.h.gQt.#.a.a.a.b.a.b.a.b.a.b.l.e.l.e.#.a.e.#.e.b.l.e.e.l.j.j.e.j.j.e.b.e.b.a.e.e.l.e.l.a.#.c.cQt.fQtQtQt.iQt.s.f.i.iQt.d.i.cQt.a.#.a.l.#.a.#.a.r.a.#.a.r.cQt.c.g.f.g.f.h.m.w.w.w.n.n.n.A.I.I.K.T.N.2.9#k#l#i.Q.p.w.sQt.f.x.h.h.f.h.D.E.F.z.y.n.m.p.x.q.x.r.r.#.b.b.r.b.r.b.r.b.k.e.k.e.k.e.b.j.r.b.#.c.#.#Qt.#.cQtQt.cQt.cQtQt.f.d.d.g.f.h.h.h.m.f.g.f.m.g.p.n.n.n.w.h.g.xQtQt.c.r.b.e.b.b.e.e.b.k.b.k.k.0.0#m.k.k.k.j.j.k.j.k", +".j.j.k.j.j.k.j.j.j.k.j.b.j.j.e.j.e.b.e.e.b.a.b.a.r.d.d.d.f.g.g.m.u.p.iQt.c.#.a.b.l.e.l.e.l.e.l.e.#.e.#.a.#.l.e.l.e.b.j.e.j.b.j.e.j.b.j.e.l.e.r.e.e.b.l.b.e.a.e.#.#.#.#.q.#QtQt.i.i.s.f.f.i.d.f.c.#.l.a.#.a.a.a.#.a.b.bQt.aQt.aQt.f.g.f.h.i.p.h.w.w.n.v.D.A.J.B.z.Z.M.N#h#n#b.N.z.p.n.s.#.#.x.s.gQt.g.u.z.B.K.F.E.y.y.p.p.x.q.#.r.r.b.r.b.b.r.b.e.e.k.k.k.b.k.e.b.l.r.#QtQt.c.r.cQtQt.c.f.c.#.#Qt.q.d.x.x.h.p.x.h.q.#.i.f.g.w.s.w.s.p.p.w.p.f.d.#.cQt.b.r.e.e.b.k.e.j.j.0.0.e#m#m.k.j.j.j.k.e.j.j", +".k.j.k.k.k.j.k.k.j.k.k.k.j.k.e.j.j.e.e.e.e.e.a.r.a.aQtQt.g.x.h.h.f.s.f.gQt.d.c.c.b.e.b.b.b.a.b.b.a.e.l.e.e.e.#.e.l.l.l.b.l.l.e.b.e.e.e.b.e.l.e.l.e.l.e.l.e.b.a.c.a.#.a.c.a.#.c.c.iQt.i.iQtQt.qQt.b.#.b.#.b.r.a.b.b.l.r.aQt.c.c.c.g.i.s.m.w.w.n.o.w.C.C.A.B.A.I.z.Z.P.N.4.5.O.G.p.s.g.f.s.#Qt.#.#.f.x.g.p.u.v.C.J.Y.E.C.u.s.g.q.f.b.#.e.r.e.b.b.e.r.j.e.j.j.b.j.eQt.cQtQtQtQt.cQt.a.#.cQt.cQt.cQt.f.g.i.g.dQtQt.cQtQtQtQtQt.g.g.g.g.s.h.g.m.n.w.xQt.a.e.b.#.e.e.e.e.j.e.k.0.0.0.e.0.k.e.0.k.0.k.0", +".j.k.j.k.j.k.k.j.k.j.j.j.k.j.j.e.j.j.e.e.b.a.b.e.a.c.c.d.f.f.x.x.i.i.iQtQt.c.c.c.e.e.a.b.a.b.r.c.#.l.b.l.r.l.l.b.e.b.l.e.l.b.l.l.e.l.b.l.e.e.b.e.e.j.l.b.e.a.a.#.a.r.a.#.a.c.#.a.i.#Qt.iQt.iQt.i.a.#.a.r.a.a.#.a.b.b.e.#.cQtQt.d.s.g.i.h.h.v.n.o.v.v.D.D.A.G.z.K.P.Y.N.U.6.Y.D.n.s.s.f.#.f.#.f.rQt.f.f.g.x.p.n.n.B.B.z.A.y.w.h.q.cQt.c.b.r.b.r.e.b.j.b.j.b.j.e.rQt.cQt.cQt.cQt.c.#.bQt.cQt.c.f.d.f.g.dQt.f.dQt.cQt.c.q.d.f.g.f.g.f.g.f.g.m.D.n.wQt.cQt.e.b.b.e.e.e.k.0.k.k.e.k.0.e.0.k.0.k.e.k.k", +".k.e.j.k.j.k.j.j.j.j.j.e.e.e.k.e.j.b.e.e.b.b.a.b.#.cQtQt.f.d.f.g.f.f.iQt.g.#.d.d.l.r.e.a.bQt.a.c.#.e.l.e.l.e.a.l.l.e.b.l.e.l.b.e.b.e.e.e.b.l.e.l.e.e.l.e.l.e.a.a.a.a.#.c.a.#.a.c.cQt.dQt.cQt.dQt.c.r.a.a.r.a.b.#.a.#.aQt.c.f.d.f.g.i.i.h.w.u.n.n.C.C.o.D.o.B.I.z.K.P.N.4#h.P.y.w.s.f.f.#.#.#.#QtQt.c.f.d.f.f.x.p.u.h.o.A.B.A.u.u.g.q.f.d.#.b.r.e.b.r.e.b.r.b.r.bQtQt.cQt.cQt.cQt.cQt.cQt.c.f.d.f.f.gQt.x.f.cQt.#.#.bQt.cQt.d.f.f.g.g.g.x.m.o.o.v.f.iQt.c.#.e.l.b.j.j.e.k.0.k.k.k.k.k.e.k.k.0.k.e", +".k.j.k.j.k.e.k.j.k.j.k.e.k.e.e.e.k.e.e.e.e.#.e.b.c.c.c.cQtQt.d.d.iQt.fQt.f.dQt.q.a.b.a.r.a.c.c.a.a.l.b.l.r.l.b.e.b.l.l.l.b.e.l.l.e.l.b.e.l.e.b.e.j.l.e.e.l.e.a.b.a.b.a.b.a.c.a.aQt.c.#.fQtQtQtQt.cQt.c.#.a.r.a.b.a.#.cQt.d.f.f.x.i.g.m.g.h.n.v.v.n.o.D.o.D.A.G.I.K.Q.M.1.3.P.o.w.x.fQtQt.#Qt.r.#.b.r.#.rQt.f.g.f.x.h.p.y.A.B.A.D.w.s.x.x.d.c.r.b.r.b.e.r.b.r.bQt.cQt.cQt.cQt.c.cQtQtQt.dQt.d.i.d.f.f.i.dQt.cQt.r.#.b.r.cQtQtQt.x.m.m.w.w.w.w.v.w.g.i.iQt.c.#.b.a.b.k.e.k.e.k.j.k.e.0.k.0.e.k.0.0", +".j.j.e.j.j.k.j.j.j.j.j.e.e.j.e.e.e.j.e.b.e.b.a.bQt.c.c.c.cQt.dQtQtQt.f.f.f.fQtQt.cQt.c.c.cQt.cQt.a.b.l.e.l.e.a.l.e.b.l.e.l.b.l.b.e.e.l.b.e.e.e.e.e.e.l.j.e.b.a.a.#.a.a.#.a.#.aQt.c.cQt.cQt.cQt.cQt.aQt.a.c.a.#.cQt.c.c.fQt.fQt.g.h.m.h.w.u.v.y.D.v.o.o.D.o.o.A.G.I.K.H.N.3.Y.y.h.sQt.f.#.#.r.#.r.r.b.r.a.rQt.c.iQt.d.x.x.n.o.D.B.y.o.n.g.q.f.cQt.r.b.r.b.c.bQt.r.iQtQtQtQt.cQt.c.i.cQt.fQt.dQt.fQt.fQt.d.f.cQt.c.r.aQtQt.d.f.x.i.w.n.C.C.w.m.g.f.f.i.x.q.c.c.b.b.e.e.e.j.j.j.j.k.k.k.e.k.0.k.0.k", +".k.j.k.j.k.e.k.e.j.k.e.j.j.b.e.j.b.e.e.b.e.l.b.l.c.cQt.c.c.c.c.c.d.fQtQt.fQt.f.gQt.d.c.cQt.c.c.a.e.#.a.#.a.b.l.b.l.e.l.b.l.e.l.e.l.b.e.e.b.l.e.e.j.j.j.e.l.e.a.a.b.a.b.c.a.r.a.a.bQt.a.cQt.cQt.cQt.c.cQt.cQt.cQt.aQt.d.iQt.g.x.h.u.n.p.w.n.u.o.D.n.o.D.o.D.o.C.o.I.I.I.Z.1.P.w.v.fQt.f.#Qt.#Qt.r.l.r.a.r.#.cQt.c.#Qt.d.g.s.h.y.v.z.A.o.v.g.x.q.gQt.c.#.c.#.c.rQtQt.i.i.c.fQt.q.d.q.dQtQt.f.f.f.f.f.f.f.dQt.c.#.c.c.#.d.f.d.g.x.h.x.w.o.w.o.m.m.g.f.g.g.g.iQt.c.#.e.b.e.e.j.e.e.e.e.k.j.k.e.j.e.k", +".e.k.e.k.e.k.j.j.k.e.k.e.e.j.e.e.e.j.b.e.b.r.a.rQt.c.cQt.cQt.cQtQt.#.d.iQt.s.i.i.iQt.i.#.c.r.#.a.l.a.#.e.a.e.a.e.b.l.e.l.b.l.b.l.e.e.l.e.e.e.j.e.j.e.j.e.e.l.b.a.a.a.a.#.a.#.a.a.b.aQt.c.#.cQt.cQt.dQt.r.c.cQt.c.#Qt.i.f.g.x.m.h.v.u.n.n.v.o.D.v.o.C.o.v.n.v.D.o.B.z.H.M.W.K.v.h.x.f.f.#Qt.r.#.r.#.a.r.b.#Qt.cQt.c.c.f.d.g.q.h.x.o.o.v.v.u.n.w.h.f.cQt.cQt.cQt.fQt.iQtQt.i.#Qt.i.cQtQtQt.#.d.f.fQt.fQt.dQt.dQt.#.iQt.g.f.g.f.g.m.x.h.h.m.m.h.g.g.g.f.g.g.g.fQt.a.r.e.r.e.b.j.j.j.j.e.k.j.k.j.k.j", +".b.k.e.j.k.e.k.j.k.j.k.j.j.j.e.e.e.b.l.r.l.b.a.bQtQt.c.c.c.c.a.a.fQt.fQt.i.f.f.g.g.f.dQt.q.c.a.#.a.b.a.a.#.l.b.l.l.l.b.l.e.l.e.l.b.e.b.l.b.j.e.e.j.t.e.e.l.e.#.a.b.#.b.a.r.a.c.#.bQt.a.#.cQt.cQt.cQt.c.cQt.cQt.c.iQt.g.i.g.g.w.g.o.o.v.u.v.D.o.o.A.y.C.n.n.n.n.D.A.I.H.P.Y.I.w.h.s.fQt.fQt.#.c.#Qt.b.r.cQt.cQt.aQt.cQt.cQt.c.f.f.u.u.h.v.A.o.o.p.g.g.i.q.f.f.f.f.iQt.iQt.#.i.c.#Qt.q.#QtQt.i.f.g.f.d.i.dQt.rQt.c.g.h.m.h.m.h.h.w.n.w.w.h.gQt.dQt.d.d.f.c.f.iQt.c.#.r.a.b.e.b.e.b.k.j.k.0.e.k.e.k", +".j.k.j.k.j.b.e.e.e.j.j.b.e.r.e.b.r.a.a.r.a.#.r.a.q.c.#.c.#.qQtQtQt.iQtQt.iQt.sQt.g.p.h.iQt.i.a.e.a.a.b.l.e.e.l.b.e.e.e.b.e.b.e.e.l.e.e.e.e.e.j.e.j.j.e.j.e.j.e.e.e.e.e.r.a.bQt.c.e.a.r.c.#.a.#.a.#Qt.cQt.i.d.i.f.i.g.f.g.s.x.m.w.w.h.w.w.v.n.v.n.v.w.o.w.n.m.v.w.C.v.B.Z.1.Q.o.p.h.gQt.r.r.b.r.e.b.#.e.r.b.#.#Qt.d.fQt.d.g.d.gQt.g.g.x.n.o.A.z.K.z.v.u.v.p.s.s.i.f.q.q.d.dQt.d.i.dQtQt.d.i.d.qQt.iQtQt.i.f.g.f.s.s.g.s.g.f.g.d.f.cQt.c.c.rQt.r.r.b.r.a.b.b.e.b.b.b.b.r.b.e.b.e.j.j.e.0.k.k.0.k.0", +".j.e.j.e.e.e.e.j.j.k.e.e.l.e.b.e.a.r.a.a.r.a.r.a.#.c.#Qt.#.d.#.i.#Qt.#Qt.fQtQt.s.i.g.p.s.iQt.#.bQt.c.a.#.a.#.e.l.e.b.l.e.l.e.l.b.e.b.l.b.e.e.e.e.e.e.e.j.l.e.a.a.e.b.e.e.a.b.a.c.a.r.a.#.b.#.bQt.#.a.q.c.i.f.f.f.i.i.g.s.x.m.m.m.w.u.m.w.v.v.o.o.w.n.w.h.h.h.p.n.w.o.A.S.Z.Z.H.y.h.x.fQt.r.r.e.r.b.b.a.r.a.#.a.rQt.d.i.d.i.d.i.d.g.f.g.g.h.u.A.z.J.B.A.v.w.s.p.s.f.x.f.g.d.i.dQt.i.f.g.g.f.f.f.xQtQt.g.f.g.f.g.q.#Qt.#.dQt.c.d.d.c.rQt.r.r.r.b.r.a.e.r.e.b.e.b.e.r.e.e.b.b.e.e.b.0.k.e.0.e.k.e.k", +".j.k.0.e.j.e.e.b.j.e.b.e.e.e.a.b.#.a.a.c.a.c.a.aQt.c.cQt.cQt.c.c.#Qt.#.c.q.cQtQtQt.s.u.g.iQtQt.cQt.c.a.a.#.a.b.l.b.e.b.e.b.e.e.l.e.e.e.l.e.e.e.e.j.j.e.j.e.l.a.a.b.l.b.a.aQt.cQt.c.a.#.cQt.#Qt.c.qQt.c.q.i.d.g.g.g.g.f.g.g.m.x.m.p.m.m.w.w.v.n.w.n.h.h.h.h.h.h.h.g.u.o.I.M.1.Z.Q.h.w.gQt.#.r.r.r.b.a.r.#.b.#.c.fQt.fQt.d.i.dQt.d.i.d.f.f.m.s.n.u.A.J.J.B.A.u.h.p.w.x.g.x.f.f.f.g.i.q.f.f.fQt.fQt.g.i.s.m.h.f.q.f.#Qt.cQt.a.r.a.b.r.b.b.e.e.e.b.e.b.e.e.e.e.e.e.e.j.b.j.e.j.j.e.j.k.k.0.k.k.0.k.0", +".j.e.j.e.j.b.j.e.e.e.l.e.r.a.b.a.a.a.a.#.a.a.#.a.c.#.c.a.c.a.a.#.a.aQt.a.c.c.cQtQt.f.m.g.s.f.dQt.c.c.#.a.a.#.e.a.e.#.e.l.e.l.e.b.l.b.e.b.e.l.e.e.l.b.l.l.b.e.r.a.e.a.a.#.c.c.c.c.cQt.d.#.cQt.d.q.c.q.c.fQt.i.i.gQt.g.s.g.f.g.m.h.m.x.m.g.m.p.w.h.h.p.h.h.x.g.h.h.x.h.u.A.I.L.Y.N.D.n.x.fQtQt.r.#.a.r.#.b.#Qt.rQt.d.i.d.i.dQt.fQtQtQt.c.g.f.g.g.w.u.v.z.z.z.v.o.v.w.g.w.g.w.g.m.x.g.f.m.i.g.f.i.f.g.m.g.f.x.i.d.d.a.a.a.a.b.a.r.r.e.e.b.e.r.e.b.e.e.e.b.e.e.b.e.b.j.e.e.j.b.j.b.e.0.e.k.e.0.k.e.k", +".j.j.j.e.j.e.l.e.b.l.e.b.a.a.b.a.a.#.a.a.a.a.a.a.b.a.b.#.b.b.a.b.b.e.b.aQt.c.c.c.c.q.i.i.f.fQt.d.f.c.cQt.a.a.e.b.e.e.e.b.e.b.e.e.e.l.e.l.b.e.b.e.j.j.l.b.l.l.a.a.a.#.a.c.aQt.c.c.qQt.#.iQt.iQt.#.f.d.i.c.fQt.i.i.i.i.f.g.g.x.h.h.s.g.g.f.h.m.h.h.h.g.g.x.f.x.g.g.x.h.p.y.A.B.E.N.K.y.h.q.i.fQt.r.#.b.#.bQt.c.f.c.fQt.dQt.d.q.dQt.#.cQt.c.i.g.g.s.u.v.h.h.p.n.A.z.n.v.p.w.p.h.h.n.h.m.g.g.f.x.g.g.w.h.g.fQt.c.d.c.a.b.b.b.a.b.b.b.b.e.e.e.e.e.b.j.e.j.e.e.b.e.e.e.e.b.j.b.e.e.j.e.e.k.0.k.0.k.0.k", +".j.j.e.e.j.e.e.e.l.e.l.a.a.a.c.c.b.e.l.e.e.b.l.b.b.b.e.e.e.e.b.b.b.e.b.e.r.b.b.#.a.c.c.f.m.g.h.dQt.i.c.c.a.#.a.l.e.l.b.l.e.l.e.l.b.e.b.e.e.e.l.e.t.b.l.e.a.b.b.a.a.a.a.a.#.c.#Qt.cQt.d.iQt.#.iQt.dQt.i.f.#Qt.q.i.d.f.i.f.g.g.g.x.g.f.g.g.h.g.x.g.x.h.q.g.x.g.q.x.g.x.h.n.u.y.A.Q.R.K.n.g.f.fQtQt.#.#.rQt.dQt.rQtQt.d.i.fQt.dQt.f.cQt.d.x.d.g.g.f.m.h.w.x.g.p.w.u.v.u.o.o.z.A.A.v.v.u.p.m.g.m.x.m.i.fQt.c.c.c.b.c.e.b.e.e.b.e.b.e.e.b.e.e.b.j.e.b.e.k.b.j.j.j.j.k.e.0.k.0.k.0.e.k.0.k.k.k.e.k.e.k", +".j.e.j.e.e.e.b.l.b.l.a.a.a.c.a.#.e.e.b.e.e.e.b.e.l.e.e.e.l.e.l.e.e.e.e.b.e.b.b.b.e.#.cQt.f.h.x.x.f.dQtQt.c.c.aQt.e.b.e.e.b.e.b.e.l.e.l.e.b.l.b.e.b.j.l.b.l.l.a.#.a.r.a.q.c.#.cQtQtQt.iQt.fQtQtQt.i.d.i.cQt.#Qt.qQtQtQt.f.f.f.g.g.g.i.i.i.x.d.f.g.f.f.f.x.d.f.f.g.g.f.g.s.h.w.o.G.Q.H.A.w.x.d.d.f.bQtQt.rQt.c.f.rQt.fQt.d.#.fQt.d.f.d.f.d.d.g.f.f.q.q.x.h.m.s.h.s.p.w.v.o.o.B.B.B.v.o.v.u.h.g.f.fQtQt.c.c.a.b.e.r.l.e.l.b.e.j.j.e.j.j.j.e.j.j.e.k.j.b.k.e.e.j.e.e.k.k.e.k.e.k.0.k.e.k.e.0.k.0.k.0", +".j.e.e.j.j.e.e.e.l.l.a.#.a.a.a.c.b.e.e.b.b.e.e.e.e.e.b.e.e.b.e.b.j.b.e.j.e.b.b.r.e.b.cQt.f.g.x.hQt.i.d.c.c.cQt.a.b.e.r.l.b.l.e.l.e.b.e.b.e.e.e.e.t.e.e.l.b.e.a.a.a.a.r.c.#.#.d.#.iQtQtQtQt.iQt.iQt.dQt.f.#Qt.a.#.c.cQt.i.f.g.g.f.i.f.fQt.f.f.d.f.d.f.d.i.c.f.d.f.i.g.g.x.s.A.C.n.T.H.K.y.x.cQt.x.#.#.cQt.d.#.c.f.d.i.d.i.dQt.d.i.d.q.f.d.f.qQt.d.fQt.f.q.x.h.s.p.u.v.v.v.A.C.o.D.z.y.o.v.w.i.g.f.#Qt.q.a.a.l.e.j.e.e.e.j.e.j.b.e.k.e.j.j.j.b.k.b.j.k.e.k.e.k.e.k.e.k.0.k.0.k.e.k.0.k.0.e.k.k.e.k", +".0.e.k.e.j.b.e.b.a.b.l.e.e.#.e.l.e.b.e.e.e.j.k.j.k.j.j.j.k.j.j.k.e.e.j.b.e.b.e.b.c.f.c.#Qt.h.v.y.x.gQt.i.cQt.c.c.#.q.a.a.l.b.b.e.b.l.e.l.e.b.l.b.e.b.l.b.e.b.e.e.b.l.a.a.bQt.a.cQtQtQtQtQt.fQt.f.dQt.cQt.cQt.c.#.#Qt.r.#.c.f.q.x.f.f.d.f.d.f.f.dQt.cQt.c.f.d.g.q.f.g.x.g.h.p.n.y.J.H.L.N.z.p.h.d.f.g.f.fQt.f.d.d.f.c.q.a.#.r.b.#.q.i.dQt.fQt.g.q.cQt.d.d.f.h.s.p.p.h.u.v.v.o.A.A.w.m.g.f.fQt.d.c.r.r.b.b.b.b.b.b.k.j.k.j.k.j.k.k.j.k.j.b.k.k.e.k.k.e.e.j.e.b.j.e.k.e.0.e.0.k.0.e.k.j.k.j.k.e.0.k", +".e.j.e.b.e.e.b.b.l.e.l.b.l.e.l.e.j.j.e.j.e.e.e.j.e.j.k.k.j.k.j.k.e.e.e.e.e.e.e.e.b.c.dQtQt.w.y.C.h.m.i.f.dQt.d.d.q.#.a.#.l.b.l.b.a.e.b.e.b.l.e.e.l.e.e.e.l.e.l.b.a.l.b.#.c.a.r.a.f.iQtQt.iQtQt.i.c.#Qt.c.cQt.b.#.b.#.#.rQt.r.f.f.i.f.cQt.i.c.f.cQtQt.f.d.f.q.i.q.g.q.f.x.g.p.n.y.B.F.N.1.E.o.s.h.g.f.g.f.f.f.f.cQtQt.cQt.cQt.c.#Qt.fQt.d.g.g.f.f.g.f.g.x.h.s.h.h.u.v.y.o.z.C.o.v.i.g.fQt.i.c.c.c.r.b.b.b.b.b.b.b.k.e.j.k.e.k.j.j.j.j.j.k.e.j.e.k.e.k.k.b.j.j.e.j.e.k.0.k.k.e.k.0.k.e.k.e.j.j.k.j", +".e.e.e.e.e.#.a.#.e.l.b.l.e.e.e.j.e.e.j.e.b.k.e.e.k.j.e.e.k.b.k.j.b.k.e.j.b.j.e.b.b.cQt.#Qt.p.v.J.p.h.w.g.m.f.xQt.#.q.#.a.c.e.#.a.b.e.l.e.e.b.e.b.e.b.l.b.e.e.b.e.l.b.l.b.a.a.c.a.c.#.#.#.#.#.#.#.cQt.c.c.#.b.r.b.r.b.b.rQtQt.c.f.d.f.c.#.cQt.cQt.rQt.cQt.d.f.q.xQt.x.g.q.h.p.y.y.I.H.Y.3.N.I.o.p.g.i.g.gQt.f.d.dQtQtQt.c.f.c.f.d.iQt.iQt.g.x.g.i.h.g.h.h.w.p.n.p.B.D.z.A.v.w.h.g.iQtQt.dQt.c.c.c.e.e.e.j.e.e.e.e.b.k.j.j.j.j.e.k.e.e.e.e.e.j.k.e.0.k.j.k.j.b.e.e.k.e.k.e.k.j.k.e.j.k.j.k.e.b.e.b", +".c.#.aQt.a.c.a.c.b.e.e.e.b.l.e.e.k.e.j.k.k.k.e.k.j.j.k.k.j.k.j.j.k.j.k.j.k.j.k.k.e.#.aQt.s.h.y.C.v.n.A.u.p.g.g.s.#QtQt.c.#.a.b.#.b.b.e.b.l.e.l.e.l.e.e.l.b.e.l.e.e.l.b.l.b.#.b.c.q.c.c.c.c.c.cQt.c.c.aQt.a.r.a.b.b.r.r.b.b.#Qt.r.fQt.cQt.dQt.#Qt.dQt.d.#.d.d.x.d.f.x.f.g.h.p.n.A.F.T.N.Z.Z.M.B.u.x.m.x.f.g.d.i.c.f.#.fQt.f.d.x.g.i.s.f.s.g.s.g.m.p.h.n.v.o.v.z.D.B.B.o.u.h.g.fQt.dQt.cQt.c.b.b.b.e.j.b.e.j.b.j.e.j.e.e.e.e.j.e.e.e.e.e.j.e.e.b.j.0.e.j.e.k.j.j.e.b.j.e.e.j.b.j.e.e.e.e.b.e.e.b.e", +".a.a.a.a.a.#.a.a.e.l.b.l.e.e.j.j.b.k.k.j.e.k.e.k.e.k.k.e.k.k.e.k.j.k.b.k.j.k.j.k.e.e.eQt.f.p.v.v.n.A.C.z.y.u.g.i.iQt.#.#.c.a.#.b.e.l.e.e.b.e.b.e.e.b.l.e.e.e.b.e.b.l.b.l.e.a.a.a.c.c.#.a.a.#.a.a.a.#.a.b.a.r.e.r.l.b.b.r.b.#.rQt.c.#.c.rQt.rQt.rQt.r.cQt.d.f.d.f.h.f.x.f.p.h.y.z.M.M.Q.Q.M.2.N.z.h.w.g.h.f.f.dQtQtQtQt.g.f.g.f.g.m.g.w.h.w.p.w.h.u.o.o.z.o.z.o.B.v.v.p.w.fQt.d.#Qt.#.c.a.b.#.b.b.b.e.e.e.e.e.j.e.b.e.b.e.k.e.e.e.b.e.b.e.e.e.j.e.e.k.e.e.e.b.b.e.e.b.e.b.e.b.e.b.b.b.a.e.a.b.a.a", +".c.aQt.e.#.e.e.e.b.e.e.k.e.e.j.j.k.j.k.e.k.0.k.0.k.k.k.k.e.k.k.0.e.k.k.k.k.e.0.k.k.b.e.c.f.v.C.D.o.y.z.C.y.u.p.sQt.#.iQtQt.c.a.b.#.e.b.e.l.e.l.b.l.e.e.b.l.b.l.e.t.e.l.e.a.b.b.a.q.a.a.c.a.c.a.c.a.c.e.a.b.b.b.e.r.e.b.b.r.r.#.#Qt.cQt.rQt.dQt.c.f.cQt.r.d.f.q.f.x.h.g.h.h.n.A.z.Q.M.E.K.F.3.O.K.v.w.s.h.f.i.c.f.c.g.d.g.f.m.h.w.u.v.o.v.A.A.A.o.o.A.o.v.v.u.v.u.h.w.g.fQt.cQt.a.c.c.a.b.b.e.e.e.j.e.k.e.k.e.b.j.e.e.j.e.b.e.b.e.e.l.e.e.b.e.b.j.e.e.b.e.#.b.aQt.a.#.b.#.r.#.r.#.a.a.a.#.a.c.a.a", +".b.e.e.e.e.e.b.j.e.e.j.e.e.k.e.e.k.k.k.0.0.e.0.k.e.0.e.0.0.0.e.0.k.0.e.0.0.k.0.k.0.j.e.b.i.h.A.D.o.y.A.C.z.u.h.q.gQt.i.#.dQt.c.c.e.b.l.e.b.e.e.e.e.b.l.e.e.e.e.b.e.e.l.b.l.l.l.b.a.c.a.a.a.a.a.#.e.b.l.r.e.e.b.b.e.e.b.e.r.b.r.cQt.#.cQt.rQt.r.c.#.cQt.c.f.q.g.q.m.s.h.w.w.o.A.I.Q.F.I.I.F.N.1.Y.B.v.h.w.f.x.i.d.f.f.g.f.m.h.u.u.B.z.J.B.J.D.B.z.o.u.v.h.g.m.g.g.g.i.sQtQt.a.l.eQt.a.b.a.b.e.j.b.k.e.e.k.b.k.e.e.b.e.b.e.e.e.j.e.r.e.r.e.e.e.b.e.#.b.a.c.c.d.f.d.aQt.c.aQt.a.c.#.c.cQt.c.cQt.c.b", +".b.b.b.k.b.k.0.e.j.j.j.e.k.b.j.j.0.e.0.k.0.k.e.0.0.0.0.0.e.0#m.e.k.0.k.0.k.0.k.0.k.e.j.eQt.g.o.C.o.v.z.C.v.u.i.sQtQt.d.qQt.c.c.c.b.e.e.l.e.l.b.l.b.l.e.e.b.l.b.e.t.e.j.l.e.r.l.b.a.a.#.b.a.#.b.a.l.e.l.e.l.b.e.e.e.k.r.e.r.bQt.r.rQtQt.r.c.f.c.#.dQt.c.f.f.q.f.g.s.g.w.x.n.o.z.K.Q.B.I.K.I.I.Y.V.K.A.p.h.g.f.f.iQt.g.g.m.w.w.v.o.F.E.F.E.F.B.B.D.w.m.g.h.g.x.m.x.iQt.c.a.a.e.a.b.a.a.b.b.e.e.e.j.b.j.j.j.j.j.e.b.e.e.e.e.e.b.e.b.e.a.e.b.b.r.b.r.c.c.d.f.d.f.d.f.b.b.#.b.aQt.a.cQt.c.c.c.c.b.c.c", +".k.k.e.k.k.k.e.k.k.e.k.e.k.k.k.e.k.k.0.k.0.k.0.k.e.0.0.0.0.k.0.0.0.k.0.e.0.k.e.0.k.k.k.j.a.x.A.z.u.u.h.h.n.h.m.gQtQtQt.c.a.r.e.b.a.e.b.e.b.e.e.e.e.e.b.l.e.e.l.e.b.j.b.l.e.l.a.a.#.a.a.a.a.b.a.a.l.#.e.b.l.b.e.r.e.j.b.k.#.bQt.d.f.cQt.fQt.d.i.f.fQt.x.f.f.g.f.g.n.h.w.p.o.B.E.R.Q.F.B.z.K.I.E.R.U.M.v.w.p.g.q.x.i.x.f.w.h.z.D.E.2.Q.B.v.w.p.u.s.h.f.f.f.g.f.fQt.f.iQt.#.c.q.c.a.a.a.a.a.b.a.a.a.e.e.b.l.e.b.l.e.a.#.cQtQt.dQtQt.dQt.#.c.qQt.q.c.c.#.c.a.c.c.c.#.e.b.e.e.r.e.b.e.b.b.e.b.e.b.e.b", +".k.e.k.0.e.k.0.e.k.j.j.k.j.e.0.k.0.e.k.e.0.k.e.0.k.k.e.k.0.k.0.k.e.0.k.0.k.0.0.k.k.e.j.e.b.i.u.B.p.p.h.p.h.g.i.xQt.q.dQt.a.#.a.e.b.l.e.l.e.l.b.l.b.e.l.e.b.e.b.e.j.l.l.b.e.e.a.b.a.b.a.b.a.a.a.b.l.l.l.a.e.#.e.b.b.b.j.e.b.r.c.d.c.i.d.i.d.g.f.f.g.f.g.f.g.m.x.m.p.u.n.v.o.I.T.R.E.B.A.z.z.B.E.P.L.Z.A.w.m.f.h.h.g.g.w.h.o.B.E.T.H.F.y.w.h.p.i.x.f.f.iQt.f.gQt.fQt.c.i.c.c.a.a.aQt.a.#.a.a.#.a.#.a.a.aQt.a.c.aQt.a.a.a.c.q.#.d.i.#.#Qt.qQtQtQt.i.c.cQt.c.c.#.c.c.#.e.a.b.l.e.l.e.b.e.e.e.e.e.e.e", +".k.k.k.k.0.k.k.k.j.e.k.e.k.0.k.e.k.k.0.0.k.e.0.k.e.0.k.0.e.0.k.0.0.k.0.k.0.k.k.0.j.b.k.e.aQt.g.y.u.h.u.h.g.x.f.f.iQt.d.c.a.b.e.e.l.e.b.e.b.e.l.e.e.l.b.e.l.e.l.e.b.j.e.l.l.e.#.a.#.a.a.a.r.a.a.b.b.l.b.l.e.b.e.b.j.r.j.r.b.bQt.d.i.d.i.d.i.f.g.d.g.f.g.x.h.g.w.h.w.p.w.o.z.F.P.N.z.o.u.A.A.z.B.I.M.Z.I.n.x.h.h.x.w.h.v.o.B.F.E.E.z.u.h.g.f.i.q.sQt.dQt.dQtQt.dQt.d.c.c.c.c.a.a.a.a.b.c.#.c.b.a.a.cQt.c.c.cQt.c.c.a.#.a.a.c.c.i.d.cQt.c.c.cQt.c.c.b.b.b.b.r.b.b.b.e.e.b.e.e.b.e.e.e.b.e.b.j.b.e.j", +".0.e.0.e.k.e.0.e.j.k.j.0.k.e.k.0.e.k.k.e.0.k.k.0.k.e.k.k.0.k.0.k.0.e.k.0.e.0.0.e.k.j.k.b.eQt.s.h.p.h.g.g.m.i.g.i.d.#.i.c.a.b.a.b.e.b.e.e.l.e.e.l.b.e.e.b.e.e.b.e.t.b.t.e.e.e.a.b.a.a.b.a.a.b.a.a.l.a.e.a.b.e.#.e.r.b.b.e.r.c.f.q.i.q.dQt.f.f.gQt.x.h.x.h.x.s.s.w.p.w.u.o.B.F.T.S.o.v.n.n.y.y.z.B.P.2.H.o.w.g.p.w.u.o.y.B.F.B.B.C.g.h.f.q.d.d.d.d.c.d.i.dQt.c.c.c.cQt.a.c.a.#.e.e.#.a.a.b.a.a.bQt.c.c.c.a.c.a.cQt.e.l.b.a.#.c.a.a.e.b.e.b.b.b.e.e.b.e.b.e.e.e.b.e.e.e.e.j.e.j.e.j.b.j.e.j.j.e.k.j", +".k.k.k.k.0.k.k.0.e.k.e.k.k.0.k.j.k.0.e.k.k.e.0.e.k.0.k.e.0.k.0.k.0.k.0.k.0.k.0.k.k.e.k.e.e.rQt.s.g.m.g.g.f.i.f.i.#.d.c.c.a.b.e.e.l.e.l.b.e.b.e.e.l.e.l.e.l.b.l.e.e.j.e.b.l.e.a.a.#.b.a.a.a.a.a.e.l.l.b.l.l.b.e.b.e.b.e.b.aQtQt.gQt.fQt.fQt.g.f.f.x.f.m.f.x.w.s.h.w.n.v.o.B.E.H.F.v.v.w.w.n.o.A.H.2.Z.I.o.w.h.h.o.z.B.z.B.C.v.u.p.f.iQt.#.a.r.cQt.aQt.a.c.b.b.aQt.b.a.b.b.e.e.e.e.e.e.b.l.e.e.b.l.a.b.#.a.a.b.a.a.b.b.e.b.e.r.e.b.l.b.l.e.l.e.b.l.e.e.e.e.b.e.e.e.e.j.b.k.b.k.b.k.e.j.e.j.e.j.e.j", +".0.e.0.k.e.0.e.k.j.0.k.0.e.k.e.k.e.k.0.k.j.k.k.0.k.e.0.k.0.k.0.e.k.0.k.0.k.0.k.0.k.k.j.j.e.#.a.#.g.i.i.sQt.iQtQtQt.#.c.a.#.b.l.b.e.b.e.e.e.e.l.b.e.b.e.b.e.e.e.e.e.j.j.j.l.e.#.b.a.a.a.a.b.#.b.a.l.l.e.l.b.b.l.r.e.b.e.r.a.i.f.gQt.fQt.d.i.qQt.f.g.f.g.x.g.x.h.g.n.h.o.o.B.E.I.B.v.o.n.u.n.D.z.K.X.Z.B.o.u.w.z.J.J.B.A.u.w.h.m.iQtQt.c.a.b.a.a.r.b.a.b.a.r.a.b.b.l.b.e.e.b.e.e.j.b.l.l.e.e.l.l.l.b.e.l.e.b.l.e.e.a.e.e.b.e.j.j.j.k.j.e.k.e.j.j.k.b.k.b.k.e.j.j.e.k.e.k.j.k.j.k.k.k.e.k.k.k.j.j.k", +".k.k.k.e.0.k.k.0.e.k.e.0.k.0.k.j.0.e.k.e.k.e.0.k.j.k.k.e.0.k.0.0.0.e.0.k.e.0.k.e.0.k.k.e.j.b.l.b.i.qQtQtQtQtQtQt.#.d.c.c.b.e.e.e.l.e.l.b.e.e.e.e.l.e.l.e.e.j.e.t.e.j.e.e.e.l.a.a.#.b.a.b.a.a.a.b.l.l.e.l.e.a.b.b.b.b.b.aQt.i.f.g.dQtQt.g.dQt.f.g.f.g.f.g.f.m.x.w.h.v.A.z.I.F.B.C.n.y.n.n.u.A.K.I.W.W.I.v.o.z.K.F.o.u.h.g.f.f.d.f.d.cQt.a.b.a.r.c.r.e.b.b.b.e.b.a.b.b.e.e.e.j.e.j.l.e.b.l.b.l.b.e.l.l.b.l.e.l.b.l.e.e.e.j.j.e.k.j.e.0.k.0.k.e.0.k.0.j.k.e.k.e.k.k.k.k.k.e.k.e.0.e.j.k.0.e.j.e.k.k", +".0.e.0.k.k.0.e.k.j.0.k.k.0.e.k.e.k.k.k.j.j.k.k.e.k.e.0.k.0.e.0.k.k.0.k.0.0.k.0.0.j.k.e.j.e.b.l.lQt.iQtQt.#QtQt.qQt.cQt.a.a.b.e.e.e.b.e.e.j.l.j.e.e.e.b.j.e.l.e.e.j.e.e.t.b.e.a.b.a.a.a.a.#.b.a.a.l.b.e.a.b.e.b.e.c.#.aQt.#.i.f.g.#.d.i.d.i.dQt.f.iQt.i.f.g.f.m.g.n.v.A.D.I.E.I.o.p.u.n.n.y.A.z.K.N.V.E.B.I.H.E.z.h.h.w.i.f.c.a.bQt.c.a.b.a.b.b.c.a.b.b.l.b.l.b.e.b.l.b.e.j.j.j.e.e.l.e.l.e.l.e.l.e.j.e.j.e.j.j.j.b.e.e.j.k.k.e.0.0.k.0.e.0.0.0.e.k.e.k.0.k.0.k.0.e.0.e.k.0.k.k.0.k.j.e.k.j.k.j.j", +".j.k.j.e.0.k.0.0.k.0.e.k.k.k.0.k.e.j.j.j.e.j.j.k.j.k.j.e.0.k.0.k.0.k.0.e.k.0.k.0.k.e.k.j.j.e.e.b.e.#Qt.q.fQtQt.c.c.#.c.bQt.l.b.#.e.e.e.e.e.b.e.e.b.a.e.a.b.e.e.e.j.j.j.e.e.e.b.l.aQt.a.b.a.a.a.r.e.l.l.b.l.a.#.a.b.#.aQt.c.d.gQtQt.f.#.f.cQt.cQt.d.g.f.h.x.p.h.p.n.u.o.F.P.T.I.o.n.o.n.u.C.z.B.K.Q.2.V.M.E.F.z.p.f.i.d.dQt.c.cQt.b.#.b.e.e.a.b.a.e.b.l.r.e.r.e.e.e.e.e.j.e.j.j.j.e.e.b.e.j.e.e.b.j.b.j.k.j.e.j.j.0.k.0.k.0.k.0.k.e.k.e.k.k.e.k.0.k.j.e.k.e.k.e.k.k.j.k.k.j.e.k.j.j.k.k.j.k.e.k.k", +".k.e.k.k.k.e.k.0.e.k.k.0.e.k.e.k.j.j.k.j.k.e.j.j.k.e.0.k.k.0.k.0.0.e.k.0.k.0.e.k.0.0.0.k.e.k.e.j.e.a.c.#.qQtQt.c.c.c.a.c.b.a.b.e.e.e.j.e.e.j.e.e.e.e.e.k.e.j.j.e.0.e.j.j.e.l.e.b.a.b.#.a.a.b.a.a.l.e.e.a.e.l.b.a.#.a.#.c.f.f.f.g.d.#.f.c.q.cQt.fQt.g.f.m.x.s.w.p.u.v.B.F.E.E.B.A.f.h.n.o.o.A.o.A.2.2.N.K.B.z.n.g.qQtQt.d.d.c.c.c.a.b.b.l.b.b.l.r.b.b.b.e.a.e.#.e.e.e.l.e.k.b.j.e.e.j.e.l.b.e.j.e.k.k.e.k.e.k.j.k.k.0.k.0.e.0.k.0.0.0.k.0.k.0.k.k.e.k.k.0.k.j.0.k.k.j.k.e.k.j.j.j.e.e.k.b.j.j.j.j", +".j.j.k.e.0.k.0.k.k.0.e.k.k.0.k.k.e.j.j.e.j.j.j.e.0.k.0.k.0.k.e.0.k.0.0.k.0.k.0.0.k.k.k.j.k.e.e.j.e.a.a.cQt.#.c.#.c.a.c.a.a.b.e.e.j.k.e.k.k.j.k.j.e.k.j.e.k.k.k.k.j.j.k.e.j.b.e.e.#.c.a.a.#.a.a.b.e.b.l.b.l.b.a.#.l.#.aQt.d.g.g.i.fQt.d.i.dQt.fQt.f.g.f.h.g.w.p.n.w.v.B.E.E.F.B.v.g.m.m.w.u.o.J.F.1.Z.F.B.u.h.f.f.i.d.d.c.c.#.c.b.r.e.e.e.b.e.e.e.l.b.e.e.r.e.e.e.e.e.j.e.j.e.k.b.j.e.e.j.e.e.e.j.j.k.e.k.j.k.e.e.0.k.e.0.k.0.k.0.k.k.e.k.0.e.k.e.k.j.e.0.e.k.e.k.e.k.j.e.k.j.k.e.k.k.b.j.j.e.e.k", +".j.k.e.0.k.k.e.0.e.k.0.j.k.e.k.e.j.j.k.j.e.j.j.k.e.0.k.0.e.0.k.0.k.0.k.0.k.0.k.0.0.e.k.j.k.b.e.j.e.e.a.a.c.c.#.c.#.c.b.a.b.b.l.b.j.j.j.j.j.j.e.j.j.b.e.j.e.j.j.e.e.k.e.j.e.b.e.b.a.a.a.b.a.b.a.#.e.l.l.b.l.l.b.a.#.a.#.cQt.g.f.gQt.f.iQt.fQt.i.d.g.f.g.x.h.p.p.p.u.v.z.E.M.E.A.p.v.n.u.u.z.E.Y.V.Z.F.o.u.g.f.dQt.d.d.c.#.c.b.b.a.e.e.a.e.b.e.b.e.r.e.e.e.e.l.b.e.e.j.e.e.j.j.e.j.e.j.e.b.l.j.e.e.e.k.e.k.b.j.k.k.k.0.0.0.k.0.0.0.e.0.0.0.k.0.k.0.j.e.k.k.0.k.0.k.k.j.j.j.j.b.j.b.k.j.e.k.e.j.j.j", +".j.k.j.k.e.0.k.k.k.0.e.k.j.j.0.k.j.b.j.e.k.e.e.j.k.k.e.k.0.k.e.k.e.0.k.e.0.k.e.0.k.0.k.j.k.e.j.e.e.k.e.j.a.a.c.c.c.a.c.a.b.a.e.b.j.e.k.e.j.b.j.e.e.k.k.j.e.e.e.k.e.j.e.b.e.e.a.b.#.a.#.a.a.a.a.a.e.e.b.l.b.a.a.#.l.#QtQt.d.g.f.s.g.f.f.g.f.g.f.g.f.g.f.h.h.w.p.n.w.o.B.E.H.F.B.v.A.o.B.B.Q.Y.N.P.F.v.p.g.f.i.cQt.aQt.b.a.b.a.b.e.e.j.b.e.e.l.e.j.e.e.a.b.b.e.e.b.j.e.k.e.j.e.k.e.b.e.e.j.e.e.j.e.k.j.k.j.k.k.e.k.0.k.k.0.k.0.0.0.0.k.k.e.0.0.e.k.k.0.k.e.k.e.k.j.e.j.j.j.j.j.j.j.e.j.e.j.e.j.e.j", +".e.k.e.j.k.e.k.j.e.k.j.e.k.e.k.e.j.k.j.j.j.j.j.k.e.k.0.k.e.k.0.k.0.k.0.0.k.0.k.0.j.e.k.b.k.e.j.e.j.e.j.e.e.a.c.#.#.c.a.r.a.e.b.e.e.e.l.e.e.e.l.e.b.e.e.b.e.e.e.e.e.e.e.e.e.a.e.b.a.c.a.a.b.a.r.a.e.l.l.e.l.a.#.a.#.a.r.cQt.f.g.g.g.g.f.g.f.g.f.g.f.g.f.h.m.p.n.n.p.z.H.Q.T.K.K.Q.L.N.P.N.T.E.I.o.u.m.f.f.d.c.c.r.c.r.b.b.b.e.e.e.j.e.e.j.e.j.b.e.b.e.e.e.e.e.l.e.j.e.e.j.j.j.b.j.e.j.l.e.e.b.j.e.k.e.j.j.j.j.k.e.k.0.e.0.0.e.k.0.k.0.0.0.k.k.0.k.j.e.0.k.j.k.e.k.e.k.b.j.b.k.b.j.j.j.e.e.e.k.e.j", +".j.k.j.k.j.j.k.e.k.j.k.j.j.k.k.k.e.e.e.e.e.e.j.j.k.0.e.k.0.k.e.0.k.e.k.e.k.e.k.0.e.k.j.j.k.b.e.e.e.j.k.e.k.e.c.#.c.a.a.a.b.a.b.a.a.a.a.a.aQt.a.c.a.a.#.a.a.a.e.l.e.b.e.b.a.r.b.a.#.b.#.c.a.a.a.a.e.b.l.r.l.#.a.#.l.q.a.f.f.g.f.g.f.g.f.g.f.g.f.g.f.g.x.m.s.n.h.o.v.B.E.L.N.N.N.R.3.O.M.B.A.p.h.x.sQtQt.i.d.c.b.b.b.b.b.b.e.e.b.k.j.k.j.j.e.j.j.j.b.l.b.e.b.b.b.e.j.j.j.j.b.j.j.j.e.e.b.j.e.j.e.k.j.j.j.e.k.k.j.k.0.k.0.k.0.0.0.e.0.k.e.k.0.e.k.e.k.j.j.e.j.j.k.0.e.e.k.e.k.e.k.b.e.b.e.e.e.j.b.k", +".k.e.k.e.k.e.j.j.k.j.e.k.e.k.e.k.j.j.j.j.k.e.j.k.e.k.0.e.k.0.k.0.k.0.k.0.k.0.k.k.j.k.e.e.k.e.j.j.e.j.k.0.k.e.a.#.c.c.a.r.a.b.#.b.a.#.cQt.c.c.cQt.r.#.#.r.#.a.a.a.e.b.e.e.e.a.b.b.a.c.a.#.a.#.b.a.e.l.e.l.e.l.a.#.a.#.rQt.d.f.f.s.g.f.f.g.f.f.g.f.g.f.m.h.g.n.n.n.A.z.T.W.9#a.V.T.K.J.B.v.g.q.f.d.q.#Qt.c.c.f.c.#.r.e.e.e.b.e.k.k.j.j.e.j.j.j.b.j.b.e.b.e.l.e.e.e.e.k.j.e.k.e.j.e.e.j.e.e.e.e.j.b.k.j.k.k.k.j.k.j.0.k.0.k.0.k.k.0.k.0.0.e.k.k.0.k.k.e.j.k.k.e.j.e.e.k.e.e.j.e.e.j.b.e.e.j.b.k.e.k", +".j.j.j.e.j.j.e.k.j.e.j.j.j.j.k.j.k.j.k.j.j.j.k.j.0.k.k.j.k.j.e.e.e.j.e.e.b.l.j.e.e.j.k.j.e.j.e.e.e.e.l.e.b.e.e.e.a.#.c.a.#QtQtQt.#.#.cQtQt.iQtQt.#.#.#.#.#.#.#.a.c.a.cQt.a.c.a.c.#.a.b.a.b.a.a.#.e.l.r.l.r.l.#.l.#.a.q.cQtQt.f.i.dQtQt.cQtQt.cQt.x.g.g.x.g.w.p.o.B.M.U.4.1.N.I.z.D.v.h.x.gQt.q.d.cQt.b.e.e.e.b.e.e.j.e.j.j.j.j.j.e.k.k.e.j.e.j.e.e.e.b.b.r.e.b.e.j.j.j.e.j.k.j.e.j.e.t.j.j.k.k.k.e.k.j.k.j.k.k.j.k.j.k.j.e.k.j.k.k.0.k.0.k.e.0.e.j.k.e.e.e.k.k.e.e.j.j.e.e.e.b.e.e.e.e.j.e.e.b.e", +".j.j.e.e.e.e.j.j.j.j.j.j.k.j.j.j.e.j.j.e.j.k.j.j.0.j.0.j.e.e.k.e.j.e.e.l.t.e.e.j.k.k.j.j.e.e.b.e.l.b.e.e.e.j.b.e.a.c.r.c.#.cQtQt.#.c.#Qt.i.fQtQt.#.c.#.c.#.c.#.c.aQt.a.c.b.c.b.c.b.a.a.a.a.a.b.a.#.e.l.e.l.e.a.a.#Qt.c.q.c.iQt.gQt.cQtQt.cQt.cQt.q.g.q.g.g.g.y.A.E.Z.4.W.P.Q.o.n.u.w.x.f.d.f.d.f.b.r.e.b.b.e.j.e.b.j.e.e.k.b.k.e.k.j.j.j.e.e.j.e.e.e.e.l.e.a.e.e.e.k.j.k.j.j.j.j.j.e.j.b.e.k.e.k.j.k.k.j.k.j.k.j.k.k.j.k.k.j.j.j.0.e.k.k.e.k.j.k.e.e.b.e.b.e.b.e.k.b.j.b.l.b.e.r.l.b.e.e.b.l.e.e", +".j.e.j.j.j.e.k.j.e.e.e.k.j.j.k.j.k.j.k.j.k.j.j.0.j.e.0.j.k.j.e.j.e.j.e.e.e.l.e.e.e.e.e.l.b.e.l.e.l.l.l.b.e.e.e.j.a.r.a.c.c.#.f.#.c.q.#QtQtQtQt.i.#.c.q.c.#.c.q.#.r.a.r.a.c.#.c.a.#.a.b.a.b.a.#.a.e.l.r.l.r.a.#.#.c.qQtQt.i.gQt.gQt.f.cQt.cQt.cQt.g.f.g.g.x.w.A.I.T.W.2.E.B.A.v.m.h.m.f.iQt.f.d.d.b.b.e.j.e.j.j.k.j.e.j.e.k.e.k.e.k.j.k.b.j.j.e.j.e.b.b.b.b.b.a.e.e.e.e.e.e.b.e.e.e.e.e.j.k.j.k.k.e.k.j.k.k.k.j.k.k.j.k.k.j.k.e.k.k.0.k.e.0.j.e.k.b.e.e.b.e.e.b.e.j.j.j.e.e.e.a.e.b.l.e.b.l.e.b.e", +".j.e.j.e.j.j.j.k.j.j.k.j.j.k.e.j.j.j.j.j.j.e.j.j.0.0.k.j.j.e.e.e.j.b.j.j.j.e.l.e.l.j.l.e.l.e.l.b.l.r.e.b.e.e.j.j.a.#.a.c.a.a.c.c.#.#.cQtQtQtQtQt.c.#.c.#.a.c.c.c.a.c.a.c.a.r.a.r.a.b.a.a.#.a.c.a.c.#.a.a.a.a.cQt.#QtQt.i.f.f.g.g.f.i.fQt.f.d.i.d.f.f.g.m.w.w.B.E.Z.L.P.B.v.v.w.h.f.gQt.d.d.d.c.c.e.b.e.b.e.j.k.j.k.j.j.j.e.j.j.j.e.j.k.e.e.b.e.e.a.b.a.b.a.b.b.a.e.e.e.b.e.e.e.j.l.e.j.e.e.k.e.k.j.k.k.j.k.j.k.k.j.k.k.j.j.j.j.j.k.e.j.k.j.k.e.j.e.b.e.b.e.b.e.e.j.e.e.b.l.b.e.r.e.e.l.e.e.e.l.e", +".j.j.j.e.j.e.k.j.b.j.j.j.e.j.k.j.k.e.k.j.k.j.k.j.j.k.k.j.k.j.j.j.e.j.l.b.j.l.j.e.b.l.b.l.b.l.a.a.l.e.l.e.e.e.e.j.l.a.a.a.a.a.c.c.c.#.c.#.iQtQtQt.c.c.#.c.c.#.c.c.a.#.a.b.a.c.a.c.a.#.a.b.c.#.a.#.a.a.c.#.cQt.c.q.d.iQt.g.f.g.g.g.gQt.g.i.d.i.x.f.f.f.g.h.u.A.F.N.6.W.H.o.o.w.m.gQtQt.fQt.i.cQt.r.e.b.e.j.e.e.k.e.j.j.b.k.e.k.e.k.k.e.k.e.k.e.j.e.#.a.a.#.a.a.#.a.e.b.l.e.e.e.e.b.e.l.j.e.k.e.k.k.e.k.j.k.k.j.k.j.k.j.k.j.e.k.j.k.e.0.k.e.k.e.k.j.b.e.e.b.e.e.b.e.b.e.j.e.e.l.b.l.e.b.e.b.l.b.e.e", +".j.e.j.e.e.k.j.j.j.k.j.k.j.k.j.j.j.j.j.j.j.j.e.j.0.e.0.j.e.e.j.e.j.e.j.j.e.j.l.b.l.l.l.l.l.r.a.#.e.l.e.e.e.e.k.e.l.a.a.a.a.a.a.a.a.c.#Qt.cQt.iQt.c.q.c.c.q.c.a.c.a.c.a.r.a.bQt.b.a.b.a.#.a.a.b.cQt.cQt.c.c.#Qt.d.q.d.i.g.g.g.m.h.g.f.x.f.x.d.gQt.x.h.h.g.o.F.V#i.U.H.v.v.v.g.g.f.i.#.d.c.c.b.a.r.e.e.e.k.b.k.k.k.j.j.k.j.j.j.e.e.j.k.e.e.e.j.e.j.a.b.c.cQt.c.a.c.e.e.e.e.e.e.e.e.e.e.j.e.e.e.j.j.k.j.k.k.e.k.j.k.k.k.j.k.j.k.e.k.k.k.k.j.j.k.e.j.b.e.b.e.e.b.e.b.j.e.b.l.b.e.b.b.b.e.l.e.e.e.l.e", +".j.e.j.k.j.e.j.k.j.e.j.j.j.j.k.e.k.j.k.e.k.j.k.j.k.k.k.j.k.j.b.j.e.e.e.j.e.e.l.l.t.b.l.#.r.#.r.a.l.b.l.e.b.e.e.e.e.e.a.a.c.b.a.c.a.a.#.c.#QtQtQt.c.c.c.c.c.c.c.c.a.r.a.a.b.c.a.c.a.a.a.c.aQt.a.a.c.c.c.cQt.cQtQt.i.g.f.g.m.f.h.m.g.g.f.g.f.g.g.f.s.w.u.n.I.W.6#c.B.A.w.h.m.g.x.q.#Qt.c.#.a.e.b.e.e.b.j.j.j.k.e.0.j.j.e.k.k.e.k.j.k.j.k.e.b.j.e.b.a.a.q.c.#.c.#.a.b.a.b.a.r.a.a.b.l.e.l.e.j.e.e.k.e.k.j.k.j.k.e.k.j.k.j.j.j.j.e.k.e.k.e.k.e.j.k.e.e.b.e.b.e.e.b.e.e.b.l.e.e.l.b.l.e.b.e.b.l.b.e.b", +".j.e.e.e.e.j.e.e.j.j.k.j.k.e.j.j.j.j.j.j.j.j.j.j.0.j.0.j.j.j.j.j.l.e.j.l.j.e.e.b.l.r.l.l.a.r.#.r.b.l.e.e.e.b.e.j.l.e.a.b.a.a.r.a.a.c.c.#.cQtQtQt.c.c.c.c.a.c.a.cQt.a.a.r.a.a.r.a.r.a.b.a.r.a.a.aQt.cQt.c.c.#.f.c.i.f.g.m.h.m.m.w.h.p.g.s.g.x.s.g.x.p.n.v.E#.#i.N.G.z.n.m.g.hQt.qQt.#.c.a.a.#.e.r.e.e.e.j.e.k.0.0.j.j.e.e.k.j.j.j.k.e.k.e.k.e.e.e.a.c.a.#Qt.r.c.a.b.a.r.b.a.b.b.#.e.l.e.e.k.b.e.k.k.j.k.k.j.e.k.j.k.k.j.k.e.j.k.j.0.k.j.k.j.k.e.j.r.e.b.e.e.b.j.e.b.j.b.e.b.e.r.e.r.l.b.l.e.e.l.e", +".e.e.e.e.e.j.j.j.e.b.e.e.j.j.j.j.0.0.e.0.k.k.j.k.b.j.j.j.j.e.j.e.j.j.e.e.e.j.l.j.t.b.r.q.#.c.c.b.b.l.e.b.e.e.j.e.b.e.l.#.b.a.a.b.r.a.r.dQtQt.#.c.#.c.c.a.c.a.b.a.a.a.a.l.a.b.a.b.c.#.c.#.c.c.c.c.fQtQt.iQtQtQt.s.i.g.g.g.h.w.o.o.m.g.f.h.g.x.x.h.p.w.C.S.V.U.N.K.v.w.m.h.g.f.f.d.#Qt.a.a.b.e.a.e.e.k.e.k.j.k.e.e.k.k.k.k.j.j.k.j.e.j.e.e.l.e.a.b.#.c.#.#QtQtQtQt.b.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.j.k.j.j.j.k.e.j.e.j.k.e.j.j.e.e.e.j.e.j.e.e.e.b.e.e.e.b.e.b.e.b.t.e.l.b.l.e.b.l.a.#.a.a.#.a.#.a", +".e.e.b.e.e.b.e.j.j.e.k.b.e.e.e.b.k.e.k.k.j.k.j.j.t.e.e.e.j.e.e.e.j.j.j.e.j.e.j.e.t.l.r.#.#.c.a.a.l.b.j.e.j.e.j.e.e.l.e.b.a.a.r.a.a.r.c.#Qt.i.d.#.c.#.c.#.c.c.b.a.a.l.a.a.a.a.b.b.#.c.cQt.#.c.#.qQt.iQt.fQt.f.iQt.f.s.f.g.x.w.n.z.o.p.h.x.h.w.w.n.v.o.K.N#..U.Q.o.v.w.m.h.f.g.d.d.c.#.#.a.a.e.b.b.k.e.k.j.j.j.k.k.0.0.k.e.k.k.j.k.e.j.e.j.e.b.a.a.a.a.#.cQt.iQtQt.e.a.r.l.e.e.b.e.e.e.b.e.e.e.e.e.j.j.e.k.e.j.k.e.k.b.j.k.j.k.j.e.j.j.j.e.j.j.t.e.e.l.e.l.e.e.t.e.b.t.b.j.e.b.t.e.b.a.l.#.e.e.l.e", +".a.b.l.l.e.e.e.e.e.e.e.e.e.e.e.e.k.k.j.k.e.k.j.e.j.e.e.j.e.j.e.j.j.e.j.j.j.e.e.e.e.l.#.r.#Qt.a.r.l.e.l.b.e.b.e.e.b.l.e.a.a.r.a.a.q.a.#.cQtQt.#.cQt.#.c.#.c.a.a.a.a.r.#.l.b.a.b.a.#.c.a.c.cQt.c.cQt.#Qt.qQt.qQtQt.qQt.i.g.g.m.n.v.u.w.w.w.n.h.y.o.B.H.3#..W.E.A.n.u.w.m.f.g.d.dQt.r.a.a.b.b.l.e.e.j.j.j.e.k.k.b.k.k.k.0.k.j.k.e.e.j.j.e.l.e.l.e.a.a.a.a.c.c.#.d.#.r.e.b.e.b.l.b.e.a.e.b.e.e.e.e.e.j.k.j.k.j.k.e.j.e.k.j.e.k.e.e.b.e.e.b.e.b.e.b.e.l.e.e.j.l.b.e.b.l.e.b.l.e.b.e.b.a.l.b.l.e.b.l.b", +".l.l.e.l.b.l.b.l.b.l.r.l.e.b.e.e.e.j.e.e.k.j.j.j.e.j.e.t.e.e.l.j.e.j.j.e.j.j.e.t.l.l.r.q.#.a.a.b.l.b.l.e.e.e.k.e.e.a.b.a.a.c.a.b.r.#.cQtQtQt.#.cQt.#Qt.c.#.c.c.c.l.a.l.a.a.a.b.b.b.c.a.r.a.c.cQt.c.cQtQt.#.d.#Qt.q.c.f.i.g.h.v.z.o.v.o.n.v.v.o.A.N.4.8#i.T.o.p.n.w.m.f.gQt.f.c.c.#.c.b.l.b.e.b.e.k.j.k.k.j.j.k.j.j.0.k.j.k.j.j.e.j.j.j.j.j.e.e.e.a.l.a.q.c.#.iQt.e.b.l.r.e.b.e.e.e.b.l.e.e.e.e.e.j.j.e.k.e.j.k.b.j.e.k.j.k.e.j.j.b.e.e.e.e.e.l.e.e.b.e.b.e.e.l.e.b.e.b.b.e.r.l.b.#.a.c.#.c.a.c.a", +".a.#.a.a.a.a.r.a.a.a.a.a.a.a.a.#.l.b.e.e.e.e.j.e.j.b.j.e.j.e.j.j.e.j.j.j.j.j.e.j.b.r.r.#.a.a.e.b.l.e.l.b.l.b.e.e.b.l.e.a.b.#.r.c.a.#QtQt.f.d.c.#Qt.#Qt.cQt.c.#.c.a.a.a.a.b.a.b.b.a.b.r.b.b.b.b.a.c.c.c.cQt.cQt.c.f.#Qt.f.f.w.v.A.A.z.z.B.B.B.Q.S#i.U.W.N.E.A.n.x.s.g.f.f.d.cQt.c.a.e.b.b.e.e.j.j.e.j.j.e.j.k.e.k.e.0.k.k.j.e.b.j.e.e.e.j.l.e.e.e.a.b.a.r.c.i.d.#.r.e.b.e.a.e.b.e.b.e.b.e.e.e.e.e.j.k.j.j.k.j.e.k.e.j.j.j.e.j.j.e.e.l.e.e.l.b.b.b.l.e.l.e.e.b.e.b.a.#.a.b.l.a.r.a.a.a.a.a.a.#.a.a", +".a.a.a.a.a.a.a.#.r.l.r.l.r.#.r.r.#.c.#.a.a.e.e.e.e.j.e.j.e.j.e.j.j.j.j.e.j.e.j.l.a.r.q.r.a.#.l.j.l.b.l.e.e.j.e.e.e.l.e.a.a.c.a.a.c.cQt.f.fQtQt.c.#Qt.#Qt.c.#.c.#.l.a.l.a.c.a.b.a.e.b.a.e.l.b.#.b.a.aQt.c.c.c.c.cQt.c.f.f.g.n.A.F.B.B.B.C.I.E.1.U.W.L.N.H.H.o.w.h.f.gQt.i.cQt.a.a.e.#.e.l.e.k.b.e.k.j.k.e.j.k.e.k.0.k.0.k.b.j.j.e.j.j.j.j.e.e.l.e.e.e.a.a.c.#.dQt.b.e.#.e.r.e.e.l.b.e.e.e.e.e.e.e.j.j.e.k.e.k.j.k.j.k.j.j.k.b.j.e.e.e.e.b.b.e.a.e.e.e.b.l.b.e.l.e.#.b.a.r.a.r.a.#.cQt.cQt.c.cQt.c", +".a.#.r.a.#.r.a.r.a.#.r.#.r.r.r.#.#.#.#.a.#.a.e.l.e.l.j.b.t.e.e.e.j.e.j.e.j.b.j.e.a.#.#.#.r.a.e.e.e.l.e.b.j.e.j.b.e.e.b.a.a.b.cQt.r.cQt.f.f.fQt.c.#.#QtQt.#.d.#.c.c.#.c.c.a.c.r.c.b.e.b.e.b.l.b.e.b.#.a.a.#.a.a.#.dQt.x.q.w.u.z.F.F.I.B.K.N.W.4.W.H.M.M.M.I.A.n.p.s.i.f.fQtQt.c.#.b.e.e.b.j.b.k.0.e.k.j.k.j.j.j.j.k.0.e.k.k.e.e.j.e.j.e.j.e.e.e.e.b.e.b.b.r.cQt.c.#.a.e.b.l.e.b.e.b.e.a.e.e.e.e.e.j.k.j.j.k.j.e.k.e.j.j.j.k.j.k.j.b.a.b.e.a.b.b.a.b.l.e.e.l.b.#.a.c.r.a.b.a.b.a.#.c.c.c.c.c.c.c.c", +".#.r.a.r.l.r.#.r.#.r.r.r.r.r.#.r.x.q.q.#.r.#.l.b.l.b.j.e.j.e.t.e.j.j.b.j.e.t.e.e.a.r.#.q.#.#.l.j.l.b.l.e.j.e.j.e.e.l.e.a.#.cQt.c.#QtQt.f.i.fQt.c.#Qt.#Qt.#Qt.c.#.a.#.a.c.c.c.c.r.a.e.a.e.a.b.b.a.b.a.b.b.b.r.b.c.d.f.q.h.h.A.B.F.M.H.E.P.3.5.4.P.Q.Q.Q.Q.Q.J.A.u.g.gQtQt.c.aQt.c.b.e.b.e.k.e.k.k.k.b.j.j.j.k.j.k.0.k.0.k.j.k.k.b.j.j.j.l.e.l.e.a.e.b.l.b.a.cQt.c.a.r.a.r.e.r.e.b.e.e.e.e.e.e.e.e.e.k.e.k.e.j.k.j.k.j.k.j.e.k.e.j.e.e.e.b.e.l.e.a.e.r.b.b.r.a.#.b.#.b.a.b.#.b.#.a.c.cQt.cQt.cQt.c", +".e.l.b.e.b.e.e.e.l.l.b.l.b.a.r.aQt.iQtQt.i.#.#.#.l.l.l.e.l.e.e.e.e.k.l.j.e.e.l.l.#.d.q.r.a.l.b.b.e.j.e.j.j.b.e.r.l.e.b.c.c.d.c.d.#QtQt.i.g.g.iQt.c.#Qt.f.fQtQt.#.#.c.c.a.a.b.e.e.b.b.b.b.b.b.r.b.c.r.c.f.d.d.c.xQt.qQt.h.n.C.P.2.2.L.2#i#o.4.M.Q.P.E.M.T.F.A.w.m.f.f.g.d.f.c.r.b.l.b.e.r.e.r.l.e.b.k.k.j.e.j.j.b.k.j.k.e.k.j.k.j.e.e.e.e.e.e.e.e.b.e.b.a.r.c.a.c.r.a.b.a.b.a.e.a.e.b.b.e.e.e.e.e.e.e.e.e.e.j.j.e.e.k.e.k.j.j.k.j.j.j.e.j.e.e.b.e.e.l.e.b.e.b.e.b.l.b.r.e.b.e.b.eQt.a.b.a.b.e.b.e", +".r.b.b.e.a.b.b.e.l.b.l.l.l.a.a.#.#.#.qQt.#.#.c.#.l.b.l.b.e.r.e.e.k.j.j.b.j.l.b.l.r.r.r.a.#.l.b.e.k.b.e.b.j.b.e.b.b.l.a.c.c.dQt.f.#Qt.f.f.h.g.gQt.r.c.#.f.iQt.#Qt.c.#.c.a.a.b.l.b.b.b.b.b.b.b.b.b.cQt.c.d.d.d.d.d.gQt.d.g.h.D.N.6.6#h#h#i.3.M.E.B.B.I.E.K.B.A.u.m.m.f.gQt.dQt.b.a.b.b.a.e.a.e.r.e.e.k.j.j.k.j.k.j.k.e.k.j.k.j.k.k.b.e.b.e.b.e.b.b.l.e.e.e.a.c.#.c.a.b.a.r.l.b.a.b.e.e.e.e.e.e.e.e.e.e.e.e.e.j.e.e.k.j.j.k.e.k.e.j.k.j.k.e.k.j.e.j.e.b.e.b.a.b.a.e.r.e.a.b.a.e.#.e.#.a.b.e.b.a.b.b", +".e.e.l.b.e.e.l.e.b.l.l.r.lQt.a.a.a.a.r.#.#.#.#.r.#.l.a.e.l.b.e.e.e.e.j.e.j.l.e.#.r.q.#.a.a.b.a.e.b.e.j.e.e.e.b.b.c.cQtQt.i.d.f.q.qQt.i.f.i.g.gQt.#QtQt.f.i.fQtQt.#.c.c.c.a.c.b.e.b.b.b.b.b.b.b.rQt.b.cQt.c.d.f.q.g.s.w.v.A.D.R.1#k#o#h.W.H.B.o.B.A.o.z.z.B.z.o.p.w.h.m.f.gQt.d.#.a.b.r.e.b.l.e.e.j.k.e.k.e.k.j.k.j.k.j.k.k.k.j.k.e.e.e.e.e.e.e.e.e.r.e.b.b.a.c.a.r.a.b.a.b.b.e.e.e.b.e.e.e.e.e.e.e.e.e.e.e.j.j.e.j.j.j.j.k.j.k.j.e.k.j.j.j.k.e.j.e.b.e.e.e.e.e.e.a.e.b.e.b.b.b.e.a.b.e.a.b.e.a.e", +".e.e.b.e.b.e.b.e.l.l.e.l.e.a.a.#.a.c.a.#.c.a.c.c.l.l.e.l.b.a.b.e.j.j.l.e.l.e.b.a.r.c.r.#.a.b.b.e.e.e.e.e.b.b.b.#.cQtQt.dQt.q.f.f.cQtQtQt.f.i.g.fQtQtQt.fQtQtQtQt.c.#.#.c.c.a.b.b.a.b.b.b.b.b.a.b.l.b.c.d.f.d.f.g.u.n.h.u.o.B.N.9#i.2.Q.F.B.v.o.v.v.v.o.o.A.B.z.v.p.u.g.g.iQt.#.c.r.a.a.a.r.b.a.b.e.b.e.k.b.j.j.j.k.j.k.k.j.k.j.k.e.e.e.e.e.e.e.e.e.e.e.e.a.r.a.b.b.#.b.#.e.a.#.b.l.e.e.e.e.e.e.e.e.e.e.e.e.j.j.e.j.k.j.k.e.j.j.j.k.j.e.k.e.k.j.k.e.e.e.l.b.e.b.e.e.e.b.e.e.e.l.e.b.e.r.e.#.e.r.e", +".e.e.b.e.e.e.b.e.e.e.b.e.b.b.a.b.a.a.a.c.a.a.#.a.#.l.r.l.e.b.e.a.b.l.e.b.l.e.a.a.q.r.#.a.a.e.e.b.b.e.b.e.r.rQt.rQt.d.d.i.d.d.i.q.c.#QtQtQt.f.i.x.iQtQtQtQt.fQt.g.#.c.c.c.a.c.b.e.b.e.a.e.a.e.b.b.aQt.#QtQt.i.m.g.p.h.u.z.B.Q.W.U.H.F.z.v.v.p.w.p.w.w.h.v.z.B.B.C.m.g.i.fQtQt.c.#.a.a.#.a.a.a.e.a.e.j.j.e.k.k.e.k.k.k.j.k.j.k.k.j.k.j.j.k.j.j.e.j.e.e.e.l.b.b.b.a.a.b.a.b.b.b.e.b.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.k.e.j.j.j.k.j.j.j.j.k.j.j.k.e.j.e.e.b.e.b.e.e.b.b.l.b.e.a.e.b.b.l.b.e.e.e.b.l.e", +".e.b.l.b.e.a.e.b.j.e.e.b.e.#.b.#.a.a.#.a.a.a.a.a.l.l.e.l.e.l.r.e.l.b.l.l.e.a.#.a.c.rQt.a.#.b.b.e.b.e.b.a.r.a.c.a.d.iQt.d.dQt.d.d.c.c.c.qQt.f.f.g.h.g.f.iQtQt.i.xQtQtQt.c.c.c.c.c.a.a.a.a.b.c.aQt.c.dQt.f.x.g.h.h.u.z.K.M.Y.Q.F.D.o.o.u.h.p.m.p.x.p.w.w.h.v.z.B.D.x.g.f.iQt.f.cQt.c.r.a.r.a.b.a.a.j.e.j.e.j.j.j.j.k.j.k.j.k.k.j.k.j.k.j.j.k.j.k.j.e.e.e.b.a.b.a.b.r.a.r.a.b.l.b.l.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.j.j.k.j.k.j.e.k.j.k.e.j.j.j.j.j.e.e.e.e.b.e.b.l.e.e.e.e.b.e.e.e.e.b.e.e.a.b.b.e", +".e.e.e.e.b.e.e.e.b.l.e.b.a.b.b.a.b.a.a.a.a.#.a.a.b.a.e.b.a.e.b.e.l.e.l.b.a.a.c.c.#.#.#.a.#.e.b.r.b.#.b.#.c.cQt.c.c.c.cQt.c.c.#.c.c.cQt.c.#.i.g.x.h.g.gQtQt.f.g.h.#Qt.c.d.c.c.r.c.r.c.c.c.c.c.c.c.d.f.f.f.u.o.y.z.Q.Q.S.J.J.C.o.v.h.p.w.x.h.x.q.g.s.w.w.w.v.A.C.B.i.g.fQt.d.a.a.b.a.a.a.a.a.a.a.a.e.b.l.e.e.e.e.j.j.k.k.k.j.k.j.k.j.j.k.j.j.k.j.j.e.e.e.e.b.r.a.b.a.b.a.e.a.e.b.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.k.e.k.e.j.j.j.k.e.j.k.j.k.j.k.j.e.e.e.b.l.e.e.e.r.e.b.e.b.e.b.e.b.l.b.b.b.l.b.e", +".r.b.#.e.b.e.b.l.e.e.e.b.b.b.a.r.a.a.a.b.a.a.b.a.l.l.l.l.b.a.b.b.l.b.a.e.a.aQt.c.r.q.cQt.c.#.r.b.a.#.a.cQt.a.c.c.cQt.c.c.c.a.a.#.d.c.c.c.#.f.g.h.g.h.iQtQt.i.h.gQtQtQt.d.c.c.c.r.c.c.c.cQt.c.c.i.x.g.x.w.y.E.R.S.A.z.z.G.n.u.p.p.g.g.w.g.f.x.f.x.s.p.w.h.m.A.J.D.g.f.d.f.c.r.b.e.#.c.aQt.a.a.a.a.e.l.e.e.l.e.l.e.k.j.k.j.k.j.k.k.k.j.k.j.k.j.j.k.e.e.e.a.b.a.b.b.b.#.b.b.b.e.b.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.j.k.j.j.k.j.k.j.j.k.e.k.e.j.j.j.e.e.e.e.b.e.b.e.e.l.b.e.e.l.b.e.e.e.e.a.e.b.b.e", +".e.e.e.e.b.l.b.e.l.e.l.l.e.l.b.l.e.e.l.b.l.e.b.a.b.e.b.e.e.e.e.b.b.b.r.e.b.e.b.b.#.d.iQt.dQt.d.fQt.cQt.a.r.r.a.r.a.#.a.#.cQt.c.c.a.#.c.c.fQt.f.f.q.q.i.f.f.fQt.d.iQt.#.#.#.a.b.b.c.d.d.d.d.q.q.q.p.h.v.B.S.Z.E.o.w.g.m.f.m.i.h.i.g.fQt.g.f.f.g.f.g.g.p.w.o.o.z.J.gQt.a.b.r.b.c.c.a.a.a.a.b.a.b.l.j.j.j.j.j.k.k.j.k.j.k.k.j.k.k.j.k.j.k.k.j.k.k.j.j.k.e.e.e.b.a.b.#.a.a.l.b.e.j.j.e.e.l.e.e.e.j.e.e.e.j.e.j.e.j.e.j.e.e.e.e.e.e.e.j.j.j.j.k.k.j.k.e.j.e.j.e.b.l.j.b.e.b.l.b.e.b.l.b.e.e.b.l.l.l.e", +".e.l.b.l.e.e.l.e.b.l.b.e.e.l.e.l.e.l.e.l.b.l.c.a.b.a.b.b.l.r.l.b.#.a.a.a.b.b.#.b.iQt.iQt.i.f.d.c.c.a.c.#.a.b.a.b.#.b.b.b.c.c.b.b.c.aQt.c.d.f.d.f.s.g.g.i.g.i.gQt.p.h.fQt.d.d.d.d.r.c.d.g.f.s.w.g.g.v.J.R.M.F.o.p.i.m.i.i.f.f.f.fQt.xQt.q.i.dQt.g.f.g.w.n.p.o.B.A.g.dQt.r.a.r.b.rQt.a.r.a.a.b.a.a.e.e.j.j.e.k.j.k.e.k.j.k.k.j.k.j.k.k.j.k.k.j.k.k.k.j.e.e.e.a.b.a.a.l.b.l.e.e.e.k.l.j.e.j.l.j.e.j.t.e.j.e.j.e.j.e.j.e.j.j.j.j.j.e.j.j.e.k.e.j.j.j.j.j.k.j.e.e.j.e.e.e.e.e.b.e.e.e.j.j.l.l.b.e.b.l", +".e.e.e.e.e.e.b.b.l.e.l.e.b.l.r.l.b.l.e.l.a.a.#.c.c.#.c.aQt.c.c.c.cQt.cQt.c.c.cQt.#Qt.c.f.cQt.cQt.b.b.b.e.b.b.b.e.b.l.r.a.e.b.a.b.#.a.c.c.c.dQt.f.g.h.w.h.h.g.h.i.v.p.h.h.i.f.x.x.i.q.f.g.h.h.u.o.o.z.F.B.J.v.s.h.f.f.f.f.i.f.i.f.d.dQt.fQt.f.g.d.g.f.p.h.n.A.D.J.s.f.c.b.#.b.a.c.a.a.a.a.b.a.l.b.j.e.j.e.k.j.k.k.k.j.k.j.k.k.j.k.j.k.k.j.k.k.j.k.j.e.e.e.e.b.a.b.a.a.a.e.j.e.j.j.e.e.l.j.e.j.e.j.e.e.e.j.e.j.e.j.e.j.e.e.e.e.j.e.j.j.j.j.k.k.j.k.e.j.j.j.j.e.b.e.e.e.e.b.e.b.e.b.l.e.e.l.e.l.e.e", +".b.e.e.b.e.e.a.e.a.a.a.a.a.a.a.a.l.e.c.#.c.b.c.b.c.c.d.f.d.d.d.f.#.d.#Qt.#Qt.iQt.q.c.q.a.c.#.r.b.e.e.e.b.e.e.b.e.b.e.e.e.b.a.r.b.a.a.a.cQt.f.d.f.m.p.v.u.v.h.h.h.o.u.h.h.f.g.f.h.x.m.h.h.v.y.J.F.J.C.y.n.h.x.x.q.i.fQtQt.dQt.dQt.cQt.f.f.i.qQt.f.f.g.s.w.n.C.B.J.w.f.i.c.a.#.b.c.aQt.b.a.l.b.a.a.j.e.j.e.j.k.j.k.j.k.k.k.j.k.k.j.k.k.j.k.j.k.j.k.j.k.e.e.r.e.b.l.a.l.a.e.l.e.k.j.e.j.e.j.e.j.e.j.l.e.j.e.j.e.j.e.j.e.j.j.j.e.j.e.j.j.e.j.e.j.j.k.e.k.j.j.k.e.j.e.e.e.e.e.e.e.l.b.e.l.b.e.l.e.l.e", +".a.a.a.a.a.a.a.#.b.a.#.b.a.a.#.c.#.aQt.c.c.c.c.c.c.c.f.#QtQtQt.cQt.qQtQtQt.#Qt.c.cQt.c.b.#.b.r.r.e.e.b.e.j.e.j.e.e.e.e.e.#.b.a.b.a.r.c.c.dQt.d.g.h.h.o.o.v.u.v.v.y.u.h.m.i.g.w.g.h.u.o.z.J.J.G.A.u.p.p.h.h.f.d.r.f.d.f.dQt.dQt.d.d.dQt.f.d.gQt.g.f.g.w.s.n.A.z.F.p.i.d.d.b.a.cQt.b.a.a.a.b.a.e.a.e.b.l.e.e.e.j.e.k.j.k.j.k.j.k.k.j.k.k.j.k.k.j.k.j.e.e.e.e.b.a.r.a.a.a.j.e.e.j.k.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.e.j.e.j.e.j.j.j.k.j.k.k.j.k.j.j.j.j.e.e.e.e.e.e.e.e.r.e.b.a.a.a.a.a.a.b.a", +".b.a.a.a.#.b.a.aQt.c.a.c.a.c.c.c.b.c.c.cQt.d.i.d.i.dQt.dQt.dQtQt.c.c.c.cQt.cQt.c.#.a.a.#.b.b.b.e.k.e.j.k.e.k.e.k.e.t.b.e.b.b.a.r.a.a.a.c.d.f.f.f.x.p.u.A.C.v.v.A.v.A.u.h.h.v.v.C.F.F.F.J.J.y.u.u.g.g.g.i.gQtQt.d.i.dQtQt.d.d.d.i.dQt.d.i.f.d.f.d.f.g.x.w.p.A.J.F.p.wQt.f.c.r.c.c.a.#.a.b.#.a.a.a.e.l.e.e.e.e.e.j.j.k.k.j.k.k.j.k.j.k.j.k.k.j.k.k.j.k.e.e.e.l.b.e.a.l.a.e.e.e.j.j.e.j.e.j.e.j.e.j.e.j.e.e.e.e.j.e.j.e.j.e.j.e.j.e.j.j.e.k.e.k.e.k.e.j.j.j.j.k.e.e.e.e.e.b.l.e.e.e.a.b.a.a.r.a.a.a", +".a.a.a.a.a.a.#.a.c.cQt.cQt.cQt.c.c.c.fQt.f.fQt.f.c.q.c.#.#.#.#.c.a.r.a.b.a.b.a.b.e.b.e.b.e.b.e.b.k.0.k.0.k.k.0.k.j.e.e.j.l.b.e.b.aQt.c.c.dQtQt.x.g.g.v.v.v.v.z.z.E.K.J.F.B.B.T.P.2.S.J.C.u.w.h.i.m.g.f.g.c.cQt.i.d.d.f.d.d.c.d.d.d.d.g.dQt.fQt.g.d.g.x.n.p.A.J.F.v.p.f.d.c.a.aQt.a.a.c.#.a.b.a.b.a.a.b.e.e.b.j.e.k.j.k.k.j.k.k.j.k.k.j.k.j.k.j.k.j.e.e.e.e.b.a.b.#.a.b.j.l.e.k.j.e.j.e.j.e.j.e.j.e.j.e.t.e.j.e.j.j.e.j.e.j.e.j.e.j.j.j.j.j.k.k.j.k.j.j.e.j.j.j.e.e.b.e.e.b.b.e.b.#.a.a.b.a.a.b.a", +".l.a.l.a.#.a.a.aQt.c.c.c.c.c.c.c.fQt.dQt.d.i.dQt.#.c.a.a.a.a.a.c.b.b.e.e.b.e.b.e.b.e.e.e.b.b.j.b.0.e.0.e.0.e.0.e.j.e.j.e.e.b.a.b.a.a.c.c.d.i.d.f.f.g.h.o.v.v.y.z.Z.Y.R.R.R.Y.U#c.H.F.C.v.u.g.h.x.f.f.dQtQtQt.#.#.d.d.d.d.r.c.r.dQt.dQt.d.dQt.dQt.dQt.h.s.w.o.B.J.z.v.h.i.c.#.a.c.a.#.a.a.a.a.a.l.b.l.a.b.e.b.b.j.j.k.k.j.k.j.k.k.j.k.j.k.k.j.k.k.j.k.e.e.e.b.r.l.a.l.a.e.e.e.j.k.e.j.e.j.e.j.e.j.e.j.e.e.e.e.j.e.j.j.e.j.e.j.e.j.j.e.j.e.k.e.k.e.k.e.j.e.j.j.e.j.e.a.e.b.e.l.e.e.a.b.#.a.a.a.#.a", +".c.q.a.c.a.#.q.cQtQt.iQt.#.iQtQtQt.iQtQt.#.c.cQt.b.l.r.e.b.b.b.e.e.b.j.e.j.e.e.e.k.j.e.k.k.e.k.e.k.k.k.k.k.k.k.k.k.j.j.b.b.a.b.b.a.#.a.q.cQt.d.i.i.s.w.u.o.n.h.o.M.M.2#c.8#p.U.S.A.y.u.w.h.x.x.g.f.f.d.d.c.c.c.cQt.cQt.#.dQt.d.f.c.q.c.cQt.c.cQt.c.i.f.x.m.p.y.A.z.C.o.h.d.r.c.#.c.c.b.a.b.c.c.d.a.a.b.a.e.e.e.e.j.j.j.k.j.k.j.j.e.e.e.e.e.e.e.e.e.l.e.#.a.a.c.c.a.a.a.a.e.e.e.e.j.e.j.e.e.e.e.e.j.e.j.j.j.j.e.e.j.e.j.e.j.e.j.e.j.j.j.j.j.j.j.j.e.e.e.e.e.e.e.e.e.e.e.e.e.b.a.b.l.e.a.b.a.r.a.c", +".#.c.c.q.c.c.#.c.qQt.#.fQt.d.#.iQtQtQt.q.cQt.c.c.b.e.b.e.e.e.e.b.k.e.k.b.j.b.k.b.0.e.0.k.0.k.e.k.0.e.0.e.0.e.0.e.j.e.e.e.l.r.c.c.b.a.a.cQt.f.f.g.m.h.h.v.B.F.F.E#i#o.8#c.P.H.F.Q.C.A.v.h.g.s.x.xQtQt.d.iQt.c.c.cQtQt.f.#.d.f.d.d.a.a.a.a.c.c.c.cQt.d.d.g.x.w.u.y.z.z.o.u.hQt.f.d.#.f.c.#.a.c.cQt.l.a.a.a.e.e.e.e.k.j.k.j.k.k.j.0.e.e.e.e.e.e.e.e.e.e.e.a.a.c.b.c.#.a.c.e.e.e.e.e.e.e.e.e.j.j.j.j.e.e.j.e.e.e.j.e.j.e.j.e.j.e.j.e.j.j.e.j.e.j.e.j.e.e.e.e.e.e.e.e.e.b.e.e.b.a.b.r.l.b.a.aQt.a.c.c", +".c.q.c.#.c.q.c.#Qt.dQt.#.d.iQtQtQt.q.c.c.c.c.b.l.b.a.e.b.j.e.j.j.e.b.j.e.j.j.j.j.k.k.k.e.k.k.0.k.e.k.k.k.k.k.k.k.j.j.b.b.a.c.a.c.a.aQt.c.f.f.g.x.g.v.B.F.P.V#o#q#o.1.S.F.A.v.y.v.A.u.u.u.h.g.x.f.f.dQt.d.dQt.c.c.#.#.c.#.c.c.c.c.c.a.c.c.b.r.b.a.c.fQt.f.h.g.n.p.A.B.z.A.p.x.f.f.dQt.#.c.a.c.c.d.a.a.b.a.e.e.e.e.j.0.j.k.j.k.j.j.e.e.e.e.e.e.e.e.j.l.e.e.a.b.a.c.a.a.b.e.a.e.e.e.e.t.e.j.e.e.e.j.e.l.j.e.j.j.e.j.e.j.e.j.e.j.e.j.j.j.j.j.j.j.j.j.e.e.e.e.e.e.e.e.e.j.b.e.e.b.l.b.a.a.a.r.a.c.c.c", +"QtQtQt.iQtQtQt.fQt.q.d.i.#Qt.c.i.c.#.cQt.c.e.a.b.e.e.e.e.e.e.e.j.j.j.j.b.k.j.j.j.0.e.k.0.e.k.e.k.k.j.e.e.k.b.j.j.e.e.l.e.bQt.dQt.r.#.d.g.q.h.s.n.o.F.Z.1#i#d#r#r.Y.B.v.u.u.u.h.g.h.u.v.u.h.h.h.xQtQt.d.iQt.c.c.cQt.#.c.c.c.c.d.#.a.a.#.b.e.a.b.#.c.a.f.d.x.x.x.p.v.C.z.z.v.v.p.w.f.gQt.c.#.c.a.c.a.a.a.e.e.e.e.e.j.j.k.j.k.j.k.j.j.j.k.j.j.k.j.j.e.j.l.e.b.a.a.b.a.a.c.e.e.e.e.e.l.e.e.e.j.j.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.e.e.e.e.e.e.e.e.e.e.l.e.e.a.b.b.a.b.a.c.cQt.c.c", +"Qt.xQt.f.f.g.f.f.g.fQt.iQt.dQtQt.c.q.c.a.b.b.b.e.e.r.e.e.j.e.e.e.b.j.e.j.e.b.j.b.k.0.k.k.0.k.0.e.e.e.j.e.b.k.j.e.e.b.b.a.b.c.r.d.d.f.x.x.s.n.o.B.N.4.9#o#j#f.6.X.D.z.p.h.hQtQtQt.g.h.o.y.v.p.x.f.f.d.dQt.d.c.a.c.r.a.#.a.c.a.b.a.b.a.b.a.b.b.b.b.a.c.c.d.d.f.x.x.p.v.u.o.y.v.o.y.h.h.f.#.c.c.c.c.a.a.b.e.l.e.e.e.k.e.j.j.j.e.k.j.j.j.e.j.e.e.j.j.e.e.e.a.a.b.a.b.a.l.b.l.b.e.e.e.j.e.j.j.e.e.j.j.e.j.e.j.e.j.e.e.j.e.j.e.j.e.j.e.j.j.j.j.j.j.j.j.e.e.e.e.e.e.e.b.e.b.e.b.b.a.e.#.a.cQt.c.c.c.d.d", +".f.f.f.g.f.f.g.iQtQt.gQtQt.qQt.q.c.c.c.a.b.e.e.e.e.e.e.e.e.j.r.e.j.j.j.e.e.k.e.k.e.k.0.e.k.e.k.k.e.j.b.j.e.j.e.b.e.e.b.b.#.d.d.f.q.x.x.w.v.I.M#c.U#i#p.8#a.U.P.D.z.v.v.g.fQtQtQt.h.h.p.A.v.p.g.x.fQt.dQt.f.c.c.c.#.#.a.a.c.#.b.a.e.e.e.e.b.e.e.b.r.b.#.a.f.d.d.f.x.h.h.n.u.o.C.B.u.p.fQtQt.c.cQt.a.a.a.b.e.e.e.e.j.j.k.j.k.j.j.k.e.e.e.e.e.e.e.e.e.j.l.b.a.a.b.a.a.a.c.e.e.e.e.e.j.e.j.e.j.e.j.j.j.j.j.e.j.e.t.e.e.j.e.j.e.j.e.j.j.e.j.e.j.e.j.e.e.e.e.e.e.e.b.e.e.l.e.e.e.b.a.b.r.a.cQt.c.d.fQt", +".x.m.x.g.x.g.f.x.iQtQt.d.#.d.c.c.c.a.r.b.b.e.j.e.e.b.e.b.e.e.j.e.b.j.b.e.j.b.e.j.k.0.e.k.0.k.0.e.j.b.b.e.b.j.e.j.e.a.a.c.d.f.d.f.h.s.v.B.Q.Z.1#h.2#i.9.U.Q.B.v.h.y.o.g.i.fQt.d.f.d.i.p.y.z.v.m.x.i.dQt.dQt.c.c.c.r.a.a.a.a.b.a.e.b.b.e.e.e.e.e.e.r.a.r.r.c.b.d.d.x.x.x.g.v.o.D.J.D.A.gQt.i.#.c.c.a.a.b.l.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.l.e.a.#.b.c.a.b.l.a.e.b.j.e.k.e.j.e.j.e.j.e.e.e.j.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.j.j.j.j.j.j.e.e.e.e.e.e.b.e.l.b.e.e.r.l.b.e.aQt.c.cQt.d.iQt.f", +".x.f.g.f.h.f.f.f.cQt.c.#.f.#Qt.d.a.c.e.b.e.e.e.b.e.b.e.e.j.e.b.e.j.j.e.k.e.k.e.k.e.k.0.k.k.e.k.e.j.b.e.e.e.e.b.b.b.b.bQt.d.d.g.q.n.u.A.N.4#o.3.L.6#c.2.T.D.p.x.g.g.p.u.g.f.q.f.q.d.f.g.y.A.A.w.f.f.dQtQt.d.c.c.c.r.#.l.a.#.a.e.b.e.e.e.e.j.b.e.e.r.r.r.bQt.rQt.r.q.f.f.p.h.v.z.D.J.C.u.iQt.c.c.b.#.a.a.b.e.e.e.e.e.e.e.e.j.e.e.e.e.e.e.e.e.e.e.e.j.j.e.b.a.a.a.b.a.a.a.e.e.e.k.e.j.e.j.e.j.e.j.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.j.e.j.e.j.e.j.j.e.e.e.e.e.b.e.b.l.b.e.e.e.b.a.eQt.d.i.d.i.f.f.g", +"Qt.fQt.dQt.cQt.d.#.a.#.a.a.a.a.b.a.a.a.a.b.a.b.a.e.l.e.e.b.e.k.b.e.b.j.b.e.b.j.b.e.l.b.e.e.b.r.e.e.r.r.c.f.d.c.#.b.b.d.d.h.h.h.v.F.N#i#j#d#h.2.1.Z.J.A.h.h.m.x.xQt.h.p.u.p.fQt.c.#.d.i.g.o.C.C.v.f.i.d.c.l.#.aQt.c.a.a.a.b.l.e.l.e.j.k.k.e.e.j.e.e.e.e.e.e.b.b.b.b.r.d.x.w.h.o.C.F.K.D.h.gQt.q.aQt.c.c.a.a.b.b.c.e.e.j.e.j.e.e.e.j.j.j.j.j.j.j.j.b.l.a.a.c.b.c.b.l.e.e.e.e.j.k.j.j.j.j.j.k.j.k.j.j.j.j.j.j.j.j.j.e.j.e.j.e.e.e.e.j.e.j.e.j.j.j.e.j.e.e.l.a.a.a.r.a.c.c.cQt.f.d.f.g.i.f.f.f.f.s.f", +"Qt.d.i.c.cQt.c.c.a.a.a.a.a.l.a.a.a.a.r.a.a.#.a.a.l.b.l.e.j.e.e.e.j.b.j.b.j.b.j.b.j.j.e.b.b.r.b.r.e.r.c.f.d.d.r.r.d.f.d.f.g.v.B.S#c#s#t#t#g#h.V.S.J.y.u.u.w.h.g.x.i.m.p.v.h.g.d.c.c.#.f.g.y.z.B.v.f.fQtQt.a.b.a.b.c.c.b.a.a.b.e.e.e.e.j.j.j.e.j.r.e.b.e.r.e.b.#.c.#.c.f.f.g.n.v.o.G.F.z.v.h.fQt.#.c.#.c.a.c.a.b.b.e.j.e.j.j.j.j.e.j.j.j.j.j.j.e.j.e.e.e.c.b.a.c.a.e.t.l.j.e.j.j.j.j.k.e.k.e.j.e.k.e.j.e.j.e.j.e.j.j.e.j.e.j.j.j.e.j.j.j.b.j.e.e.j.e.l.b.e.a.r.c.aQt.c.c.i.dQt.gQtQtQt.iQt.iQtQtQt", +".a.a.a.a.#.a.a.#.a.#.a.#.a.#.a.a.a.b.a.a.b.a.b.a.e.e.e.e.e.b.e.e.b.e.b.e.b.e.b.e.e.j.e.e.r.e.r.e.#.c.d.q.x.x.x.w.q.x.h.v.z.F.S.H.X#i#p#o.O.N.E.D.v.u.u.v.h.h.x.h.i.g.g.p.h.g.g.d.c.q.f.x.w.C.z.z.g.gQt.c.aQt.b.aQt.a.c.a.a.e.l.e.e.k.j.k.e.e.j.j.e.e.e.e.e.b.b.b.b.c.dQt.x.h.u.v.J.G.B.v.p.w.g.f.#.c.c.a.b.a.e.l.e.e.j.e.j.j.j.j.e.e.e.e.e.j.e.j.b.l.a.a.c.b.c.b.l.l.e.e.j.e.e.k.j.j.k.j.k.j.k.j.j.j.j.j.j.j.j.j.e.j.e.j.e.e.j.e.e.e.l.e.e.l.b.l.e.e.l.a.a.a.c.#.c.cQt.cQt.d.d.d.f.c.d.c.d.cQt.c", +".b.b.b.b.b.b.b.b.c.a.c.a.a.a.a.b.a.c.aQt.c.c.#.c.a.a.#.a.b.b.r.b.j.e.e.e.e.e.e.e.b.e.b.r.r.r.#.d.q.i.m.w.w.h.g.x.p.o.J.Q.M.F.B.C.C.D.F.I.G.D.C.u.z.v.u.p.h.h.g.g.f.m.g.h.g.g.fQt.#.dQt.f.g.o.C.G.h.g.f.q.#.c.b.c.c.r.a.r.a.l.e.e.j.e.e.j.j.e.e.j.e.b.e.j.b.b.r.bQt.c.f.f.h.g.h.h.D.z.o.v.o.v.u.hQtQt.c.a.a.a.e.e.e.e.l.e.e.e.b.e.j.j.e.j.e.e.j.e.e.e.b.a.b.a.c.a.e.t.e.j.e.e.e.j.j.j.k.e.j.j.j.j.j.e.j.e.j.e.j.e.j.e.j.e.j.j.e.j.t.e.e.j.e.l.e.e.l.b.a.a.bQt.c.c.c.a.f.d.f.d.i.c.r.b.#.b.#.b.r.r", +".e.e.l.e.b.l.b.e.l.b.b.b.b.b.a.r.a.r.a.c.b.a.r.a.a.b.a.b.a.b.r.r.b.e.b.b.r.r.b.r.b.r.c.f.f.x.x.h.m.h.p.v.A.o.A.z.E.F.F.F.z.y.v.u.u.v.v.C.z.v.p.p.A.u.h.u.h.g.h.h.f.f.i.g.g.m.g.fQt.iQt.g.g.v.G.z.o.p.iQtQt.cQt.c.c.a.c.a.b.b.l.e.b.j.j.k.e.e.j.e.b.j.e.e.e.r.b.b.c.a.cQt.f.x.m.h.p.v.v.v.v.o.v.v.f.iQt.c.a.b.e.e.b.l.b.e.a.e.l.e.b.l.e.l.e.e.l.e.l.b.a.b.a.a.c.c.l.e.e.j.e.e.e.e.j.j.j.k.j.j.k.j.j.j.j.j.j.j.j.j.e.j.e.j.e.e.e.e.e.l.e.l.a.a.a.a.a.a.a.r.c.c.c.c.c.c.c.a.c.a.cQt.e.b.e.b.e.r.e.e", +".e.b.e.b.e.e.e.e.b.#.e.a.b.a.e.b.aQt.b.c.a.c.a.r.#.c.a.b.r.c.r.c.c.c.c.a.c.a.c.a.d.g.f.h.h.n.p.o.v.z.K.E.Q.L.W.L.F.J.C.v.u.u.y.p.v.p.u.v.n.h.g.h.g.g.g.g.g.m.x.g.g.f.f.g.p.g.g.gQtQt.d.d.g.h.y.G.y.u.w.iQtQt.c.r.cQt.b.a.a.l.e.e.e.j.b.k.j.j.e.j.e.e.e.j.e.b.r.b.c.c.c.fQt.f.x.x.m.p.h.o.p.v.o.o.g.i.f.d.c.c.b.b.a.b.a.b.a.b.b.a.e.e.e.b.l.b.e.b.e.e.b.a.a.r.a.c.j.l.j.e.j.e.e.e.e.k.e.k.e.k.e.j.e.j.e.j.e.j.e.j.j.e.e.e.j.l.j.l.e.e.e.b.a.r.a.b.#.b.c.aQt.c.c.d.d.f.rQt.r.#.b.r.e.b.e.b.e.e.b.e", +".r.r.b.r.b.r.b.b.b.b.a.b.a.b.a.b.c.c.c.cQt.c.c.c.c.c.c.c.c.d.f.d.f.q.x.q.g.q.f.x.g.n.p.o.A.D.I.E.T.U#a.8.7.U.P.C.v.u.v.p.p.g.p.p.h.g.w.g.g.f.f.x.iQtQt.s.i.fQtQt.f.f.f.q.i.g.g.hQtQt.c.cQt.s.u.o.C.A.h.sQt.f.c.rQt.c.a.#.b.e.j.l.e.e.j.k.k.b.j.e.e.j.e.e.e.b.r.b.aQt.c.#.d.f.f.f.f.x.x.h.o.v.v.o.u.n.g.f.f.c.c.c.a.c.b.c.a.a.b.b.e.l.e.e.e.e.l.e.l.b.a.a.b.a.c.c.l.e.j.e.j.e.e.e.k.j.k.j.j.k.j.j.j.j.j.j.j.j.j.j.e.l.j.e.e.e.e.e.l.e.a.a.e.a.a.a.a.c.b.c.c.c.c.c.f.d.r.a.b.b.a.r.e.b.b.b.b.b.b.b", +".b.a.#.b.b.r.r.c.r.l.b.e.b.l.r.e.c.c.c.c.c.cQt.c.cQt.c.r.c.f.d.d.x.f.x.x.x.h.x.h.u.o.z.F.T.W.1#i.1.8#i.X.R.P.T.C.u.u.p.p.h.g.g.g.x.h.g.fQt.f.f.fQt.#.dQtQtQt.#Qt.q.f.f.f.i.g.g.w.i.f.i.c.f.g.n.A.y.y.v.g.s.d.c.c.c.c.c.a.a.e.l.e.e.e.j.e.k.e.e.j.j.b.j.e.b.b.b.b.c.#.cQt.d.d.g.q.d.i.x.w.p.p.v.v.o.v.h.g.q.c.d.d.b.c.a.c.b.a.b.a.e.b.e.a.e.a.e.b.e.e.a.b.a.r.a.c.j.l.e.j.e.e.e.e.k.e.j.j.j.j.j.e.j.j.e.j.e.j.e.j.e.e.e.l.e.t.e.l.b.a.l.b.a.a.b.a.b.c.#.c.c.c.c.c.r.r.c.rQt.b.r.e.a.#.b.#.a.b.a.b", +".e.b.e.l.b.l.b.e.a.cQt.c.c.c.cQtQtQt.iQtQt.dQt.d.x.x.f.gQtQt.q.#.h.p.n.p.o.o.I.E.Q.Y.W.W.Z.N.E.J.I.Y#a.1.L.N.C.g.g.g.g.f.i.f.s.f.i.#.iQt.c.q.c.c.c.c.a.cQt.#Qt.q.#.q.#.#.cQtQtQt.g.gQt.d.dQt.s.g.n.n.y.o.h.f.d.#.c.a.a.b.l.e.e.j.b.e.e.e.e.e.b.e.b.e.e.e.b.e.b.l.b.b.a.b.#.c.c.d.iQtQt.f.x.m.h.w.o.v.z.o.n.u.p.hQt.c.a.a.l.b.c.d.e.l.e.e.e.e.e.l.a.a.a.a.a.b.b.b.j.e.j.j.j.j.j.j.j.j.j.j.j.j.j.j.k.e.k.j.j.k.j.j.j.j.j.j.e.e.l.b.r.a.a.a.c.r.c.d.#.a.a.a.#.c.c.c.cQt.c.c.cQt.c.c.#.b.e.e.e.b.e.b", +".b.j.l.b.e.b.b.eQt.a.c.cQt.c.c.d.c.c.c.d.d.d.d.cQt.d.f.f.m.h.p.u.A.C.D.F.E.P.2#c.M.Q.F.B.z.o.z.D.T.O#d.U.R.F.p.f.g.iQtQtQtQtQtQt.cQt.dQt.#.c.c.c.c.#.c.c.#.c.#.d.a.#.c.#.c.iQtQt.iQtQt.c.f.d.f.m.y.o.y.n.p.m.d.d.#.#.a.a.b.e.e.e.b.e.b.e.r.e.b.e.e.e.e.e.e.e.b.e.a.b.b.b.b.c.d.c.c.#.d.f.i.x.g.h.v.o.v.o.o.y.o.u.f.f.c.a.a.c.c.c.e.e.a.e.b.l.b.e.r.a.l.a.b.c.e.a.e.j.j.e.j.e.j.e.j.e.j.e.j.e.j.e.j.k.j.j.j.j.j.j.j.j.j.j.j.e.a.l.a.#.a.a.c.c.c.r.a.#.r.c.c.dQt.fQt.d.#.f.#QtQt.d.a.b.e.b.b.b.e.b", +".e.b.e.e.b.a.r.b.e.a.r.a.c.cQt.c.#.c.c.d.x.x.s.s.x.i.u.v.C.B.E.K.1.2.X.Y.S.H.Q.Q.o.v.u.p.p.n.o.z.R#o#q#h.F.v.hQtQtQtQtQtQtQt.c.c.c.cQt.c.c.c.c.c.b.b.a.c.c.c.c.#.a.a.#.c.c.c.c.#.i.f.i.d.cQtQt.i.p.u.n.v.p.x.g.d.a.a.b.a.a.e.b.e.e.e.e.e.l.e.e.e.#.e.e.e.e.e.e.e.e.a.a.b.a.r.r.c.c.c.f.d.f.f.h.x.g.h.h.u.v.o.y.z.p.iQt.c.c.c.a.r.l.e.e.e.l.e.e.e.a.a.a.a.a.a.b.b.j.l.e.e.e.e.e.e.e.e.j.e.j.e.e.e.e.e.e.e.e.e.e.e.j.e.e.l.e.a.b.a.a.l.a.a.rQt.c.d.#.d.#Qt.dQt.fQt.iQt.iQt.#.f.#.q.b.r.e.b.e.r.e.r", +".b.b.r.b.r.r.b.b.#.b.a.bQt.d.d.cQt.d.f.x.h.p.v.C.u.A.C.J.H.P.M.N.T.T.I.z.y.u.v.p.f.f.x.m.w.h.v.z.2#p#i.2.B.h.x.dQtQtQt.c.c.c.c.c.a.c.a.c.b.c.a.a.e.a.b.b.a.#Qt.c.a.a.a.#.a.#.c.cQt.dQt.iQtQt.gQt.g.m.p.h.g.g.s.d.c.c.a.b.a.b.b.e.e.e.e.b.b.e.e.e.e.e.e.e.e.e.e.b.e.e.r.e.a.b.b.b.c.c.cQt.f.f.x.x.f.g.g.m.h.v.v.C.v.n.g.fQt.c.a.l.b.c.a.c.b.c.a.c.l.a.l.a.b.a.e.a.e.e.t.e.t.e.t.e.t.e.l.e.e.e.t.e.e.e.e.e.e.e.e.e.e.e.e.e.a.b.a.a.a.c.#.a.#.cQtQt.f.f.f.g.g.g.f.f.iQt.#.i.dQtQtQt.b.c.b.r.r.e.b.b", +".c.#.c.cQt.d.f.dQt.d.i.d.dQt.x.f.g.p.v.y.B.Q.M.X.2.2.Q.K.C.u.p.h.p.p.h.g.x.f.q.f.x.q.dQt.f.w.o.B#.#..S.D.hQtQt.cQtQt.#.c.a.b.e.b.b.r.b.a.r.e.b.r.e.e.e.a.#.r.#.c.a.a.b.a.b.c.c.c.#Qt.fQtQt.gQtQt.f.i.g.i.i.g.m.iQt.#.c.a.b.l.b.a.e.e.b.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.a.b.l.b.a.b.b.c.c.d.d.x.f.d.#.g.g.h.p.v.o.z.o.p.xQt.#.a.a.a.b.a.b.a.b.a.a.a.r.a.a.a.r.b.b.e.e.e.e.e.e.e.e.e.e.e.l.e.e.e.e.e.e.e.e.e.b.e.a.e.l.a.r.a.c.c.c.c.#.cQtQtQtQtQt.x.f.h.g.x.m.x.x.f.f.xQtQt.dQt.dQt.d.c.d.f.dQt.#", +".d.d.f.d.d.q.f.q.m.g.g.g.g.h.h.n.C.z.F.S.Y.N.L.L.G.D.v.p.h.i.fQt.g.f.f.x.d.dQt.#.f.g.q.i.f.p.C.E#..X.z.h.fQt.f.c.b.c.a.b.r.e.e.e.e.l.e.e.e.e.e.e.e.b.e.e.b.c.a.c.a.b.a.c.c.c.a.c.c.iQt.g.iQtQt.d.i.f.i.i.i.g.i.gQt.c.c.c.a.b.e.b.e.e.e.e.a.e.e.e.e.e.e.e.e.e.e.e.b.e.e.e.#.b.b.b.e.a.r.b.c.d.d.dQtQt.d.f.h.g.p.u.o.C.o.p.gQt.c.a.b.c.a.r.a.c.b.c.l.a.l.a.b.a.e.a.e.a.e.a.e.a.e.a.e.a.e.b.a.l.b.l.b.e.b.b.e.b.l.b.b.a.b.c.c.c.c.d.fQtQt.f.g.f.i.i.v.w.w.h.m.g.g.i.g.i.f.f.f.f.g.f.fQt.xQt.d.f.q.f", +".f.f.g.x.m.g.w.g.u.v.o.o.C.B.C.C.H.F.F.D.y.u.p.g.x.f.f.d.c.c.c.c.c.c.d.#.r.c.d.f.q.f.g.x.u.z.F.R.2.F.u.f.#.b.c.#.a.b.b.e.e.e.b.j.e.e.r.e.a.e.b.e.e.j.e.e.b.e.c.r.e.e.r.b.b.b.b.c.r.d.f.i.g.g.d.cQt.i.i.g.i.i.h.s.c.c.c.c.c.b.a.b.e.b.a.e.b.e.e.e.e.e.e.e.e.e.e.e.e.j.e.e.e.e.l.b.e.e.e.a.bQt.d.d.b.c.d.d.f.x.m.s.o.C.z.v.u.fQt.#.c.c.c.c.c.c.c.c.a.a.a.a.a.a.b.b.e.e.a.b.a.a.e.e.e.a.a.a.b.a.b.e.b.l.b.l.b.a.b.b.c.c.c.c.c.d.dQt.f.f.x.g.p.h.u.h.v.p.m.g.x.g.fQt.g.g.f.i.f.f.i.g.m.g.g.g.w.x.m.s", +".w.g.w.v.p.n.u.v.B.B.B.F.S.N.H.F.v.v.h.h.x.f.f.d.l.l.e.a.r.#.q.q.d.dQt.f.iQtQtQt.f.x.f.m.h.z.Q.L.E.u.x.c.e.a.e.c.b.e.b.e.e.j.j.e.b.l.e.e.j.e.e.e.j.e.e.j.a.b.c.a.b.e.a.e.a.b.a.b.c.#.f.m.i.fQt.f.c.d.s.i.i.i.i.g.#.c.c.b.a.b.e.b.a.e.e.e.e.e.e.e.e.e.e.b.e.e.e.e.e.e.b.e.b.e.e.b.j.b.e.b.b.c.d.d.r.c.f.d.d.g.x.g.u.C.z.C.o.h.fQt.b.c.a.c.b.c.a.c.l.a.l.a.b.a.b.a.e.e.l.a.e.a.e.e.a.l.b.a.a.a.l.a.a.e.b.b.a.e.b.l.c.c.c.d.d.dQt.f.f.h.g.n.u.A.v.o.g.g.g.f.iQtQt.i.i.h.i.m.i.m.g.m.u.p.v.p.v.u.n.u", +".C.A.v.h.w.u.z.A.F.M.S.H.z.u.g.f.iQtQt.i.c.c.a.c.e.r.l.b.a.b.b.b.b.a.#.b.c.c.f.q.i.d.h.h.o.I.E.J.x.gQt.cQt.b.#.e.b.j.e.k.j.k.j.k.e.e.b.l.b.e.e.e.b.e.e.#.a.a.#.a.a.a.#.a.a.e.r.a.aQtQtQt.f.x.f.fQt.i.f.s.f.f.g.m.i.c.b.e.b.a.a.r.b.e.e.e.e.e.e.e.e.e.e.e.k.e.e.e.e.e.e.e.e.e.e.e.b.e.l.r.a.b.b.a.c.a.c.c.cQt.d.iQt.p.v.o.o.v.h.i.d.d.c.c.c.c.c.b.a.l.e.e.b.e.e.e.e.e.e.a.a.b.a.c.a.a.c.a.r.a.r.c.c.c.c.c.c.c.c.cQt.c.fQt.f.i.n.u.C.z.C.v.u.h.g.s.m.f.d.qQt.f.x.g.u.p.p.h.h.p.p.u.w.v.u.v.v.y.C.A", +".C.v.v.v.o.o.z.A.W.Z.Q.B.u.g.m.fQt.iQt.#.c.a.c.a.b.a.b.e.b.a.b.a.l.r.a.bQt.d.d.d.c.g.g.n.v.Q.H.C.gQt.f.c.c.a.b.e.j.j.j.j.k.e.k.j.b.l.e.e.e.b.j.e.l.b.e.b.a.b.c.a.l.a.a.a.a.b.a.e.a.c.#.f.f.g.f.f.iQt.s.f.i.g.g.x.uQt.a.e.e.e.l.a.e.b.e.j.e.j.e.j.e.j.e.k.j.k.e.j.e.e.e.b.e.j.b.e.e.b.e.a.b.b.a.b.r.c.c.c.c.fQt.d.s.g.o.v.A.o.v.hQt.d.c.c.c.a.c.c.l.a.a.l.e.e.e.b.l.e.l.e.a.c.a.b.a.a.b.c.c.c.c.c.a.r.a.a.c.cQt.c.d.d.f.x.g.w.u.o.C.y.y.v.g.h.x.f.x.f.#.d.iQt.x.h.m.h.m.h.h.h.u.h.p.p.v.v.A.v.A.C", +".o.u.v.o.A.y.C.F.2.Y.F.p.g.f.fQtQtQt.cQt.a.c.r.b.b.e.b.b.a.b.e.b.b.a.#.b.c.c.f.qQt.h.m.h.B.N.J.uQtQt.c.c.#.b.b.l.b.k.b.k.e.k.e.b.e.e.b.l.e.l.e.b.e.e.e.a.a.c.a.a.#.a.a.b.#.b.b.a.#.aQt.f.f.f.f.fQtQt.f.q.g.i.i.m.n.hQt.a.b.b.e.e.e.j.e.e.b.e.j.e.e.e.j.k.k.k.k.b.j.e.j.e.e.e.e.j.e.e.e.b.a.b.b.b.a.cQt.c.cQt.dQtQt.g.h.v.v.A.p.g.d.d.c.c.r.c.c.a.a.a.b.a.r.a.b.b.a.a.a.c.b.c.c.c.c.c.a.c.a.c.c.c.a.a.#.c.c.#QtQt.n.p.n.v.u.v.u.v.p.u.h.g.f.f.f.d.s.f.g.f.f.f.w.h.g.i.g.i.w.h.p.h.v.u.u.u.o.v.o.C", +".v.v.u.o.v.v.F.R.B.B.y.p.g.fQt.c.#.#.c.a.a.b.e.e.e.e.e.e.e.e.b.e.e.r.a.aQt.d.d.f.f.h.p.o.S.Q.o.g.i.c.c.c.a.e.e.e.j.j.e.k.j.k.j.k.e.l.e.e.e.b.e.l.e.b.e.#.b.c.#.a.a.a.a.a.a.b.a.e.aQt.#.dQt.fQtQt.#Qt.i.f.f.f.x.x.o.p.i.#.c.a.r.e.e.b.e.e.j.e.j.e.j.e.j.e.k.e.k.e.e.b.e.j.e.j.e.e.b.e.#.e.e.b.l.b.c.a.c.c.c.dQt.fQt.g.i.p.v.v.u.h.q.f.dQt.c.c.c.c.a.a.a.b.a.b.b.e.c.#.r.c.c.c.c.d.a.#.#.c.i.fQtQtQtQtQt.g.g.g.w.h.B.D.z.v.o.p.u.p.i.iQtQtQtQt.#.i.f.f.f.s.g.h.g.g.h.x.h.h.g.h.u.p.u.u.v.o.v.v.o.v", +".p.w.o.y.z.B.F.E.p.p.h.g.f.i.d.c.c.a.a.a.r.e.e.b.e.e.b.e.e.e.e.e.r.a.#.c.c.d.d.f.g.w.p.B.M.F.h.x.c.#Qt.a.b.l.e.j.e.j.e.e.k.b.j.b.e.b.e.b.l.e.e.b.e.#.e.a.a.a.a.c.#.a.a.r.a.#.b.a.a.cQt.i.f.f.#.cQt.#Qt.#.g.f.s.g.p.u.p.i.c.c.b.e.r.b.b.b.b.r.b.b.e.e.e.j.k.e.e.j.j.e.e.b.e.e.b.e.e.e.e.b.l.b.b.b.a.b.c.cQt.d.#.dQtQt.x.m.u.o.v.n.f.qQt.d.f.c.c.r.c.c.c.c.c.c.c.c.c.c.c.c.d.i.dQt.c.dQt.i.f.f.g.w.h.h.u.u.o.o.z.D.z.C.o.u.p.h.f.fQtQtQtQt.gQt.c.c.f.f.x.g.p.h.h.g.x.f.x.g.w.h.u.v.B.C.z.C.A.A.o.A", +".n.v.v.A.F.H.B.v.g.h.f.f.f.d.c.b.#.a.e.e.e.b.e.j.e.e.j.e.e.b.e.b.e.a.b.#.c.f.x.f.h.w.o.K.R.A.g.q.q.c.c.a.a.e.e.j.e.j.j.e.e.k.j.j.e.l.e.l.e.b.e.l.e.b.b.c.a.#.#.c.a.#.a.a.a.a.b.#.c.qQt.qQtQt.c.a.c.c.c.i.dQt.f.g.p.p.u.hQt.#Qt.e.r.r.b.#.b.b.b.b.e.j.e.j.e.e.j.e.e.e.j.e.j.e.j.e.b.b.e.a.b.a.e.b.aQt.c.c.cQt.d.i.d.f.x.h.h.v.v.v.h.f.q.fQt.c.c.c.a.c.a.c.a.r.c.r.c.d.d.i.d.f.f.qQt.i.f.x.g.g.u.y.v.z.C.z.C.B.C.o.u.p.g.h.f.f.fQt.#Qt.qQtQt.c.#.cQt.f.m.h.h.w.s.m.x.h.h.w.p.v.v.A.B.F.C.B.C.A.v.u", +".p.u.A.z.F.J.u.g.g.i.f.i.d.c.b.b.l.e.e.e.e.j.e.e.k.e.b.j.e.j.e.j.b.a.#.cQt.d.g.g.h.u.B.H.F.u.h.d.#.c.#.e.b.e.j.j.b.k.e.k.e.e.j.b.e.b.e.e.b.l.e.b.b.l.a.#.a.c.c.q.a.rQt.cQt.a.#.a.c.#.iQt.i.c.a.a.c.cQtQt.d.i.f.f.m.p.h.m.h.fQt.c.r.#.r.a.rQt.b.b.b.j.e.e.e.j.e.j.b.j.e.e.e.e.e.e.e.e.e.r.a.b.b.a.c.b.c.c.c.cQt.d.d.d.g.x.w.u.v.z.x.f.f.q.f.d.dQt.c.#.c.c.c.d.c.dQt.fQtQt.x.h.x.h.x.s.g.n.v.C.z.D.B.B.D.A.v.p.h.g.iQt.fQtQt.dQt.dQt.cQt.c.#Qt.c.#.g.f.h.n.p.v.h.x.h.g.w.u.y.z.z.J.Q.I.J.D.A.A.u.n", +".y.A.I.H.J.p.g.wQtQtQt.#.c.a.b.b.e.b.j.e.k.e.k.k.j.j.j.j.e.j.b.e.l.r.aQt.c.g.g.x.h.v.F.S.C.p.x.dQt.#.a.l.l.b.e.e.e.k.e.e.j.j.j.j.e.l.b.l.e.e.e.l.r.b.#.c.a.cQt.#.#.c.qQt.cQt.cQt.c.iQt.dQt.c.a.#.c.c.c.cQt.dQt.g.x.m.h.h.p.s.f.i.a.r.b.#.b.r.b.r.e.b.e.j.e.j.e.e.j.e.e.j.b.e.j.b.b.e.b.l.b.a.b.r.a.c.cQt.c.d.fQt.#.d.q.h.g.u.o.B.g.h.x.g.q.i.dQtQtQt.d.d.d.d.d.d.d.fQt.g.f.h.f.x.h.h.n.C.I.F.B.z.v.u.u.p.h.i.x.#.iQt.qQt.d.f.d.d.c.c.c.cQt.fQt.g.f.m.h.n.u.u.w.m.w.h.h.v.J.F.H.H.N.M.E.E.F.B.o.n", +".J.K.H.G.w.i.fQt.cQt.a.c.b.a.b.e.e.e.e.e.e.j.e.b.k.e.k.j.e.e.e.j.#.a.bQt.d.g.x.w.z.S.z.m.i.f.gQt.q.a.#.b.e.e.e.e.b.e.b.e.e.b.e.e.e.e.e.b.b.a.r.a.#.q.c.q.c.#Qt.#Qt.iQtQt.iQt.dQt.iQt.q.#.c.c.c.c.a.#.cQt.d.#.fQt.f.qQt.d.f.g.u.y.gQtQt.dQt.b.r.e.e.e.j.e.e.e.b.j.e.e.j.e.e.e.b.e.a.a.a.b.e.b.b.b.c.a.c.c.cQt.d.dQtQt.g.g.p.n.v.D.o.p.i.f.#.d.f.x.c.#.f.#Qt.g.f.h.q.g.i.g.v.v.o.C.F.H.H.F.B.v.u.v.f.g.f.g.i.f.fQtQtQt.c.#Qt.c.#.c.#.d.#Qt.dQt.f.f.w.w.iQt.f.m.v.o.v.v.v.u.u.u.u.u.G.A.J.z.E.E.K.I", +".H.F.J.u.h.fQt.i.a.c.a.a.a.e.e.e.e.e.j.e.e.e.j.e.0.k.j.k.j.e.b.e.b.b.#.c.q.f.m.u.Q.T.v.m.f.#Qt.d.a.a.a.l.b.a.b.e.e.e.l.e.l.e.l.e.b.l.b.a.e.b.a.r.#.#.c.q.c.iQt.i.i.s.i.g.f.g.f.iQt.iQtQt.cQt.c.c.c.#.c.cQt.f.f.d.s.g.iQt.f.i.g.u.f.h.f.i.d.c.b.#.l.b.l.e.e.j.e.e.j.e.e.r.e.b.a.b.a.a.#.a.b.a.b.b.cQt.c.c.c.d.#.d.i.d.f.x.h.u.o.A.A.u.xQt.i.f.x.s.g.i.f.f.f.f.i.g.w.h.u.o.D.J.I.F.C.D.B.C.v.h.h.hQt.qQtQt.iQtQtQtQt.#Qt.c.c.#.cQt.c.#Qt.d.fQt.g.f.i.i.iQt.i.h.o.v.h.g.g.w.h.h.w.h.n.u.y.C.G.H.R.W", +".K.z.p.gQt.f.#.c.a.a.c.r.b.e.e.e.k.k.j.k.k.k.k.k.k.k.k.j.e.e.e.e.#.b.a.a.d.g.h.n.R.E.p.i.sQt.i.d.a.#.a.b.l.e.l.e.b.l.b.e.b.e.b.e.l.e.l.e.#.a.a.c.q.#.q.c.iQt.i.f.g.s.f.s.g.i.g.d.i.#QtQt.c.c.d.f.aQt.c.q.dQt.f.f.iQt.c.f.c.d.i.h.g.g.m.f.f.#.dQt.e.a.e.r.e.e.e.e.b.e.e.e.a.b.b.a.a.a.a.c.#.b.a.bQt.c.c.d.i.d.dQt.c.#.g.f.m.p.o.v.z.u.g.m.x.x.w.v.h.g.g.h.u.u.o.v.B.D.I.I.D.I.D.C.o.u.p.h.g.g.f.fQt.qQt.fQt.d.#.d.#.c.c.c.#.c.c.c.cQtQtQt.d.f.f.fQtQtQtQt.g.g.u.p.i.f.i.f.i.g.g.h.m.p.w.n.A.C.H.Q", +".u.h.gQt.fQt.c.a.c.c.a.a.e.e.e.k.k.j.k.j.j.j.j.j.j.k.j.k.j.b.j.e.c.a.bQtQtQt.h.p.S.H.u.g.s.d.#Qt.a.a.a.b.l.r.e.j.e.e.e.e.l.e.l.b.e.l.b.a.c.#.c.cQt.c.#.iQt.g.f.g.i.i.g.s.f.gQt.d.q.i.#.c.c.c.f.d.c.c.fQt.fQt.g.f.dQtQt.b.r.d.f.g.w.p.h.w.g.g.fQt.c.#.a.b.a.j.b.e.e.e.e.a.r.a.c.c.c.c.c.c.c.c.r.cQt.d.#.d.d.f.f.q.i.dQt.f.h.g.v.v.z.v.u.h.g.p.v.o.u.v.u.A.C.D.B.J.z.F.z.z.z.v.u.p.p.m.i.i.f.fQt.i.d.#.i.c.c.#.c.cQt.c.r.c.a.c.c.c.#.cQt.f.f.i.f.fQt.dQt.f.f.x.x.x.iQt.i.f.i.f.g.i.f.s.g.g.h.u.y.y", +".i.fQtQtQt.q.a.l.b.#.e.e.b.e.k.j.j.k.j.k.k.j.k.j.k.j.e.e.e.e.b.bQt.cQt.c.d.f.h.w.B.M.z.h.fQt.i.d.#.a.a.e.l.e.e.j.b.l.b.e.e.b.e.l.l.#.a.a.a.#.c.q.#QtQt.i.f.x.f.f.s.g.i.g.f.iQt.fQtQt.#.c.c.c.d.c.qQt.#.i.d.g.f.g.cQt.r.c.#.d.d.x.h.h.p.h.p.g.g.i.c.c.a.b.b.b.e.j.e.e.a.b.a.aQt.c.qQt.c.c.#.fQt.d.d.d.f.f.f.q.g.f.dQt.g.x.m.h.h.o.z.y.A.u.o.v.v.z.B.z.B.D.z.z.y.C.o.u.p.p.g.m.i.g.f.qQt.iQt.iQt.d.c.c.c.c.c.c.c.c.a.c.a.c.a.c.a.a.fQt.i.d.i.d.fQt.d.f.fQt.f.m.fQt.#QtQtQtQtQtQt.fQt.#Qt.s.g.g.h.i", +".dQt.c.c.a.a.a.e.a.b.b.e.e.k.e.k.j.j.j.j.j.j.k.j.k.e.j.b.e.b.r.r.r.c.c.#.f.f.w.v.T.P.z.h.f.dQt.c.a.a.a.l.e.e.e.e.e.e.l.b.e.l.e.b.l.a.a.r.#.c.q.d.#QtQt.iQt.f.g.f.g.i.s.g.i.g.dQt.iQtQt.#QtQt.f.dQt.#Qt.d.iQt.g.f.g.d.cQt.c.d.g.i.w.g.g.g.g.p.w.h.i.d.c.a.b.e.e.e.b.#.e.bQt.c.#.cQtQtQt.g.dQt.d.d.g.f.f.q.f.x.x.x.f.g.x.g.h.h.v.v.J.F.F.J.C.z.B.D.B.D.G.C.A.y.u.u.h.s.i.sQtQt.iQtQt.iQt.dQt.d.c.d.#.c.a.c.#.c.b.a.c.a.r.#.r.aQt.c.#Qt.c.f.fQtQt.f.q.d.f.g.f.f.fQt.c.#.cQtQtQt.f.i.f.gQtQtQt.xQtQt", +".c.c.c.a.a.e.l.b.e.e.e.b.e.j.k.j.k.k.j.k.k.j.k.j.k.e.e.j.b.b.b.c.cQt.c.fQt.x.n.z.W.Z.C.g.fQt.i.c.a.#.a.e.e.e.b.j.e.b.e.e.l.b.e.e.r.#.r.a.#.#QtQt.i.iQtQt.g.f.f.g.i.g.i.g.f.s.f.gQt.#QtQt.d.#.fQtQt.c.i.c.i.q.g.f.g.f.f.d.f.f.g.m.x.x.g.x.m.g.h.u.f.d.f.c.b.b.b.b.a.b.aQt.a.c.f.dQt.iQtQtQt.dQtQt.q.f.x.f.h.x.x.s.p.s.g.w.p.o.v.o.B.T.Q.F.F.D.y.A.u.u.v.u.v.u.u.p.m.i.i.i.f.f.d.dQt.#.cQt.d.d.d.d.b.b.b.b.b.b.a.b.b.b.a.b.a.b.b.bQt.c.iQt.d.qQt.f.dQt.f.f.x.hQt.c.q.cQt.dQt.f.f.f.f.f.fQtQt.c.a.c", +".a.b.b.b.l.b.e.l.e.e.e.e.j.e.j.k.j.j.j.k.e.k.e.k.e.j.e.e.b.b.b.r.f.c.dQt.d.w.o.K#h.Z.v.h.fQt.d.c.r.a.a.b.l.e.l.e.e.l.j.e.j.e.l.b.a.r.#.a.q.#.i.#.iQtQt.g.f.g.f.f.s.i.g.i.i.f.gQtQt.iQt.q.fQt.d.f.c.q.c.f.d.i.f.g.h.f.g.f.f.h.s.g.x.p.g.h.x.g.g.g.g.gQt.c.b.e.e.e.a.r.c.c.c.d.c.f.i.i.f.f.f.f.g.f.x.f.h.x.s.h.p.h.x.p.p.u.u.v.A.o.E.F.H.I.A.z.u.u.p.u.v.h.p.g.w.h.i.s.g.x.x.s.q.q.d.#.d.c.d.d.d.d.a.b.b.l.e.l.e.r.l.e.e.e.b.#.b.#.cQt.#.qQtQt.f.f.f.f.x.f.x.f.d.a.c.cQt.d.f.gQt.f.h.g.i.f.c.c.b.e", +".e.b.e.e.b.e.e.e.b.e.e.j.k.k.k.e.j.j.j.j.k.j.e.e.e.e.e.e.b.a.b.a.c.a.f.g.h.v.B#i#h.K.uQt.iQtQt.q.a.a.l.a.e.e.e.b.l.b.l.l.b.l.e.l.l.l.a.a.#.c.#Qt.q.iQtQt.q.s.q.s.i.s.i.g.i.s.f.f.q.c.c.c.i.cQt.cQt.iQt.#.c.f.g.x.w.w.h.n.p.v.m.h.o.v.u.u.y.s.p.x.u.v.u.m.f.d.f.#.d.c.d.f.d.g.f.i.s.f.i.q.f.f.i.g.s.h.h.p.p.u.v.y.z.C.o.C.o.o.z.A.u.v.p.u.h.h.h.w.i.s.x.s.g.m.i.i.iQt.qQt.#Qt.fQt.b.#.b.#.a.r.b.b.e.a.e.b.b.e.b.l.e.l.b.a.a.a.c.a.d.#.d.i.f.f.fQt.f.f.i.f.xQtQt.c.a.#.a.cQt.f.f.f.gQtQtQt.#.a.#.a", +".b.l.b.e.b.l.b.e.e.j.e.e.k.e.k.k.j.k.j.k.e.j.e.e.b.e.e.b.a.b.#.bQt.#.dQt.w.v.F#h.M.J.h.qQtQtQt.f.l.a.a.l.e.l.e.e.e.l.b.e.l.e.l.b.l.b.a.#.c.q.cQt.i.q.qQt.xQt.sQt.s.i.sQt.i.f.g.f.q.c.q.c.f.cQt.c.f.c.#QtQt.q.q.p.m.u.m.w.m.p.w.p.o.v.v.h.n.n.h.p.p.p.w.m.f.i.d.dQt.f.dQt.i.f.i.i.m.g.g.g.h.h.w.u.u.u.v.A.D.B.E.G.z.z.y.v.p.p.p.p.h.w.g.g.h.m.g.gQt.f.i.g.i.g.i.g.#.iQtQt.q.d.#.d.#.b.a.b.a.b.l.a.b.b.b.e.e.e.e.b.e.l.e.a.a.c.b.cQt.cQtQt.dQt.f.f.i.f.f.s.fQt.iQt.a.a.a.#.dQt.f.f.fQtQt.#.c.a.b.a", +".e.e.e.e.b.e.e.e.e.j.e.e.k.j.k.e.k.j.j.j.k.j.e.e.e.b.e.l.r.b.b.c.iQt.g.x.w.z.F.2.B.v.h.i.iQtQt.d.r.a.l.a.a.e.b.a.l.e.l.l.b.l.e.l.a.r.a.#.#.#.qQtQtQt.i.q.f.sQt.i.i.f.q.g.q.g.f.fQt.i.dQt.i.d.d.f.c.f.f.i.g.x.w.w.v.o.o.v.v.n.o.y.o.v.v.o.v.p.n.m.u.v.A.v.v.w.g.f.qQt.i.i.i.m.g.p.v.o.v.v.o.C.C.B.F.F.z.E.P.N.R.P.u.v.u.h.m.g.m.x.g.f.f.g.f.fQt.gQt.g.f.g.f.f.g.f.#.c.q.c.cQt.c.c.#.b.#.b.#.b.b.r.l.e.e.e.b.b.e.e.b.l.e.a.b.a.a.b.#.cQt.dQtQt.f.f.m.g.f.f.i.iQt.c.c.a.c.c.iQt.f.g.fQtQt.c.c.a.a.a", +".b.e.r.l.e.e.b.e.e.e.k.e.k.e.k.k.e.j.j.k.j.j.e.e.e.l.e.b.b.a.b.c.#.i.f.h.p.F.Q.P.C.p.g.iQtQt.cQt.r.c.a.l.a.a.e.e.b.a.b.a.e.a.b.a.#.aQt.#.#.d.#Qt.i.q.f.i.iQt.s.s.f.q.g.i.g.f.g.f.iQtQt.fQt.f.d.d.f.f.i.h.h.w.y.A.z.z.B.A.A.A.o.v.z.B.K.F.I.z.C.A.C.z.o.z.z.o.v.p.i.h.p.h.A.v.z.B.I.z.F.F.z.I.F.E.H.F.B.F.Q.Q.Q.I.g.g.s.i.f.g.f.fQt.qQt.#.#.i.#.d.#QtQtQt.s.gQtQt.c.q.cQt.c.c.#.c.b.a.b.a.b.a.b.a.e.e.b.l.e.b.l.b.l.e.e.#.a.a.r.a.c.c.c.iQt.q.i.f.i.g.f.sQtQtQt.#.#.c.#.cQt.d.fQt.fQtQt.c.c.a.a.b", +".e.e.e.e.b.e.e.e.k.k.j.k.k.k.j.j.j.k.j.j.k.j.e.e.b.e.b.a.e.aQt.a.dQtQt.h.h.Q.Z.H.u.h.h.iQt.#Qt.#.c.#.a.a.b.a.b.a.a.b.a.a.#.a.a.a.c.a.#.c.#.iQt.d.qQt.i.i.i.s.i.i.g.s.f.f.f.g.f.g.#.d.i.dQt.q.g.f.f.f.h.h.v.A.B.F.P.L.Z.L.T.E.E.K.T.P.Z.L.N.P.L.P.P.T.E.T.E.I.I.I.J.B.J.J.B.E.I.T.B.I.I.D.F.I.F.B.o.v.v.o.v.u.u.h.sQt.fQtQt.dQt.f.c.c.cQt.c.c.cQt.cQtQt.fQt.dQtQt.#.c.q.c.c.c.r.c.#.e.r.e.r.e.e.e.r.e.e.b.e.e.e.e.e.l.e.a.b.c.a.c.c.c.#.qQt.d.fQt.x.g.f.fQtQtQt.c.#.c.c.c.#.i.dQtQtQtQt.c.r.a.e.a", +".e.e.b.b.e.e.e.e.k.e.k.j.j.j.j.k.j.0.j.k.e.j.e.e.e.e.e.a.b.b.cQt.#.d.g.g.o.F.Z.I.h.h.g.iQtQtQtQt.c.#.c.c.a.a.b.b.a.a.a.b.c.aQt.a.#Qt.#.f.#.d.#.iQt.i.s.i.g.i.x.s.i.f.s.f.g.f.g.qQt.i.dQt.d.fQt.xQt.m.h.A.B.Q.Y.W.1#c#i#c.1.X.X.Y.R.X.R.L.R.N.V.1.W.Z.P.S.T.T.P.L.Q.H.E.E.J.K.J.J.A.v.C.A.v.v.v.v.g.i.m.i.m.i.g.f.#QtQt.f.cQt.a.c.a.#.a.a.a.#.a.a.c.c.c.cQt.cQt.c.cQt.c.c.#.b.r.b.#.b.e.a.e.a.r.e.l.e.a.e.b.e.b.l.b.e.e.a.a.#.c.b.#.c.cQt.dQt.f.f.i.f.q.fQtQtQt.cQt.c.#.c.c.cQtQtQtQtQt.c.c.a.a.a", +".e.e.l.e.e.e.e.e.j.k.j.k.k.j.k.e.j.j.k.j.k.j.e.e.e.r.e.b.#.b.a.c.c.g.f.w.u.I.Z.B.g.m.g.i.f.q.#.#.#.c.c.c.c.b.a.r.a.b.a.a.#.b.a.aQt.#.c.#Qt.i.f.f.f.g.f.g.g.g.m.g.g.s.f.g.f.g.f.iQt.f.g.d.i.q.f.g.m.u.z.F.M.L.2.U.N.2.N.N.Q.H.E.F.F.E.F.F.E.H.Q.M.I.B.B.z.C.z.B.F.F.F.B.o.A.o.u.v.h.p.w.g.h.h.h.x.g.f.f.g.f.g.f.i.d.dQt.d.d.c.rQt.c.c.b.b.b.cQt.b.a.r.a.a.a.a.a.aQt.r.#.a.r.c.r.r.e.b.l.b.e.e.e.l.r.e.e.e.e.b.e.e.l.e.l.b.a.r.a.c.c.c.iQt.f.f.fQt.f.f.f.gQtQt.iQt.#.c.c.c.#QtQt.cQtQt.i.c.c.l.b.l", +".e.b.e.e.e.e.e.e.e.k.j.j.j.k.e.e.j.k.j.j.k.e.e.e.e.e.b.a.e.b.cQtQt.f.x.n.o.J.P.z.x.g.g.iQt.q.#.#Qt.c.#.a.c.a.b.b.a.a.a.a.a.c.#.c.#.c.#.i.cQt.f.g.i.i.m.g.s.g.m.g.x.m.f.g.f.g.g.q.f.g.f.g.f.g.x.x.p.v.J.Q.N.X.X.X.S.H.K.C.J.B.z.z.o.y.z.C.J.D.A.C.v.u.o.u.v.p.p.A.C.o.v.v.h.g.h.f.p.h.x.h.x.f.i.f.f.g.q.q.f.q.d.d.fQtQt.c.d.r.c.b.a.cQt.bQt.c.cQt.a.b.a.b.r.b.r.aQt.cQt.cQt.c.r.a.r.l.r.e.b.l.b.e.b.e.#.b.e.a.e.r.e.l.e.#.a.c.b.a.c.#.dQt.dQt.f.f.f.s.f.qQtQtQtQt.d.f.#.c.c.c.c.#QtQtQt.#.c.a.a.b", +".e.t.j.j.j.j.0.j.k.j.j.k.j.j.k.j.k.j.k.j.j.k.j.e.e.e.b.e.e.b.#.b.f.g.f.f.m.B.H.I.A.g.xQtQt.cQtQt.a.r.r.a.a.a.a.aQt.cQt.r.c.c.c.cQtQtQt.d.i.f.f.x.g.w.g.g.m.i.g.i.i.s.s.x.m.h.m.m.i.q.i.s.i.m.u.w.C.D.H.P.R.P.K.D.A.o.A.z.o.v.v.v.n.u.o.o.B.o.o.p.m.h.n.h.v.h.w.h.o.n.u.f.x.x.fQt.dQt.fQt.d.i.q.d.d.d.c.f.c.d.c.d.#Qt.#Qt.c.c.c.b.r.a.b.a.b.a.b.b.aQt.c.c.c.a.c.c.#.a.#.a.#.a.a.#.a.a.a.#.l.e.l.l.r.e.b.e.e.e.e.e.l.b.e.e.e.a.#.a.#.q.#QtQt.xQtQt.#.c.#.cQt.iQtQt.q.c.cQt.c.#.c.cQt.#.#.c.r.c.l.a", +".l.j.e.j.j.k.k.k.j.j.j.j.e.k.e.k.j.j.k.e.k.e.j.k.e.e.e.j.b.c.b.rQt.d.d.g.w.B.Q.N.u.g.iQtQt.#QtQt.r.a.a.#.#.c.q.c.c.a.c.a.c.aQt.c.#.c.qQt.f.f.f.h.h.g.g.m.g.g.h.w.s.w.u.n.h.n.h.h.g.u.p.n.u.v.o.C.B.J.B.B.B.D.z.v.n.u.v.h.v.h.m.h.p.w.p.v.o.o.u.p.g.g.m.x.g.h.g.h.v.u.m.f.q.g.d.iQt.dQt.fQt.dQt.i.c.f.d.d.d.f.d.f.#Qt.#.c.c.c.#.c.b.a.b.#.b.#.b.#.c.cQt.cQt.c.a.c.b.a.a.#.l.a.b.a.b.a.b.a.l.e.#.e.b.l.r.l.r.e.b.e.l.e.l.l.e.a.b.a.#.#.#.iQtQt.xQt.q.#.cQtQtQtQtQt.dQt.c.#Qt.c.#.c.qQt.a.#.c.c.a.a", +".l.l.e.j.j.j.k.j.k.j.j.k.j.j.k.j.j.j.j.k.j.k.j.k.e.k.e.e.e.r.r.r.i.c.f.f.w.D.M.U.v.h.fQtQt.cQt.d.r.a.rQt.#.c.#.c.#.c.#.a.#.a.a.aQt.#.cQt.g.f.h.i.p.u.p.h.h.w.n.u.h.v.A.C.B.B.A.o.C.D.A.C.C.G.B.J.z.C.y.v.u.p.h.g.m.g.x.m.g.g.g.h.i.g.g.w.h.p.w.g.g.f.f.i.g.f.f.f.p.h.i.f.g.dQt.#.d.dQt.d.dQt.d.dQtQt.c.i.#Qt.cQt.#Qt.#.iQt.f.c.c.#.a.a.a.a.a.a.a.a.c.c.c.a.a.r.a.a.#.l.a.r.a.a.#.a.#.a.#.e.b.l.e.#.e.b.e.e.e.b.e.b.l.e.e.b.a.a.a.#.#.#QtQtQtQtQt.#.c.q.#QtQtQtQt.#QtQt.c.c.c.dQt.#Qt.#.c.r.c.l.a", +".l.b.l.e.j.j.j.j.j.k.e.k.e.k.e.j.k.j.j.j.e.j.j.j.b.e.j.e.b.r.bQt.c.c.i.x.o.E.L#h.o.p.g.i.iQtQtQtQt.#QtQtQt.iQt.i.c.c.c.c.c.cQt.c.#QtQt.i.f.g.g.g.u.h.v.h.v.v.v.v.A.D.B.E.E.F.I.I.B.B.D.B.D.I.G.E.u.v.u.w.w.i.g.f.g.f.g.f.f.g.fQt.f.g.f.i.x.m.x.g.f.f.gQt.f.iQt.i.q.x.i.i.#Qt.i.cQt.fQt.d.i.d.q.d.cQt.cQt.d.fQt.d.iQt.i.c.#.cQtQt.cQt.cQt.cQt.c.#.a.cQt.cQt.c.#.c.l.e.#.a.b.a.b.a.l.a.b.a.l.l.b.l.b.e.a.b.b.a.e.b.l.b.e.l.e.a.a.a.#.a.#.#Qt.iQtQt.#.#.c.#.fQtQt.i.#Qt.c.c.#.c.#.#Qt.#.#.c.#.c.a.a", +".a.a.e.e.e.e.e.j.j.j.b.j.k.j.k.j.e.k.j.k.j.k.j.e.k.e.e.e.e.rQt.cQt.i.g.s.A.N.1.2.v.u.g.sQtQt.fQtQt.iQtQtQt.f.d.f.d.i.d.i.d.dQt.f.c.#.i.i.m.h.p.u.u.y.v.A.o.z.B.A.F.I.I.F.I.B.o.v.A.u.y.v.A.v.A.v.h.h.w.g.f.gQt.iQt.#.iQt.iQt.q.dQtQt.iQt.g.f.f.s.f.f.f.iQtQt.c.qQt.f.x.f.sQtQt.c.i.cQt.c.c.c.c.c.#.c.#Qt.#.#.#.qQt.qQtQt.iQt.f.d.#.c.#.c.c.#.c.#.cQt.c.c.c.b.c.c.b.l.e.a.#.a.a.#.a.#.a.a.#.e.b.l.r.e.b.e.a.b.b.e.l.l.e.l.e.a.r.a.a.r.#.#.#QtQtQt.c.#.#.d.#QtQtQt.d.#.c.c.c.cQt.cQt.#.#.#.a.c.l.a", +".a.l.a.b.l.j.j.e.k.j.j.j.e.k.e.j.j.j.j.j.j.e.k.j.e.e.j.b.b.b.c.#.#.f.h.w.z.R.M.F.o.p.g.f.qQt.fQtQtQt.q.f.f.f.g.f.iQtQtQtQt.f.i.fQt.i.x.g.p.u.o.C.C.D.J.I.F.E.E.J.B.z.z.o.v.u.h.h.i.i.m.g.g.m.g.g.w.g.gQt.i.d.#.dQt.qQt.#.c.#Qt.c.iQt.d.#.#.f.i.x.g.g.fQt.d.q.#.c.iQt.g.i.s.i.g.f.c.c.c.c.c.cQt.c.cQtQt.c.#.f.cQt.#QtQt.iQtQtQt.#.#.#.#.#.#.#.#.#.c.c.cQt.c.cQt.c.e.l.b.a.r.b.a.b.a.l.#.l.#.l.e.l.b.b.a.b.b.e.l.b.l.b.l.e.b.a.a.a.l.a.c.#Qt.#.d.#.#Qt.#QtQtQtQtQt.cQtQt.c.#.cQt.#Qt.qQt.c.#.c.a.a", +".a.a.l.a.e.e.e.j.k.j.e.j.k.j.j.k.j.k.j.j.k.j.j.j.e.e.e.e.bQt.rQtQt.g.s.A.I.P.H.B.o.p.g.sQtQt.iQtQtQt.i.f.s.x.i.x.s.s.p.s.p.s.s.s.g.g.w.p.o.D.J.z.E.M.P.Q.H.Q.F.B.v.h.h.x.w.f.gQt.g.f.g.f.g.f.f.i.i.f.i.c.c.c.f.qQt.d.fQt.fQt.c.c.d.i.dQtQt.f.x.p.g.h.x.gQtQt.c.q.d.f.x.i.m.g.g.fQt.cQt.c.c.a.c.a.#.#.#.q.#.#.#.qQt.i.#QtQt.iQt.fQtQtQtQt.#.#.#.#Qt.c.c.c.cQt.c.c.b.a.l.#.l.a.#.a.#.a.a.#.a.e.b.l.b.l.b.e.#.e.r.e.l.e.e.l.e.a.a.b.a.a.a.a.c.c.q.c.#.c.#.i.cQt.iQtQtQtQt.#.d.i.cQt.i.#Qt.#.#.a.a.l", +".l.a.b.a.e.e.e.e.e.j.k.e.j.j.j.j.j.e.k.e.k.e.k.j.e.j.e.b.b.r.f.c.h.w.w.I.P.Q.F.B.u.g.fQtQtQtQtQtQtQt.f.g.g.x.w.g.n.n.p.w.p.h.w.h.m.w.h.o.B.z.E.I.N.L.N.E.F.J.z.v.w.m.x.m.xQtQt.q.q.f.fQt.f.iQtQt.dQt.i.cQt.d.f.i.i.d.#.d.#.d.dQt.f.dQt.c.dQt.f.s.g.w.g.f.dQt.qQt.f.f.i.i.h.h.w.h.c.c.cQt.cQt.r.a.d.q.d.#.d.q.d.#.#Qt.q.iQtQtQtQt.#.i.#Qt.iQt.iQt.cQt.c.q.c.c.c.c.l.e.e.a.a.#.l.e.a.l.#.e.#.l.l.a.b.b.b.b.e.b.e.r.l.b.e.l.e.a.a.a.b.a.a.#.a.#.c.c.c.#.#QtQtQtQtQtQt.cQt.cQt.#.#.cQtQt.#Qt.#.c.a.a", +".b.a.a.b.a.a.b.a.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.l.a.a.cQt.#.f.h.w.D.E.S.J.z.C.o.u.h.g.m.h.h.h.p.h.g.m.h.v.o.B.B.B.F.F.D.E.F.Q.S.N.S.H.E.H.E.F.F.B.z.A.v.p.w.g.g.i.dQt.fQt.d.d.cQt.c.d.d.d.d.f.dQt.dQt.dQt.fQt.a.#Qt.#Qt.#.#.#.cQt.c.iQt.fQt.iQt.f.s.x.m.f.q.d.f.g.f.g.g.w.h.h.q.g.d.c.cQtQt.c.#.c.c.#.c.c.#.c.q.c.#.c.i.c.q.cQtQt.iQt.#.#Qt.c.#.a.a.#.a.#.b.l.#.l.b.b.e.e.e.b.e.r.e.#.e.r.e.b.l.e.b.a.b.a.b.a.e.l.l.b.e.e.b.l.a.a.a.r.a.c.cQt.#Qt.qQtQtQtQtQtQtQt.iQtQtQt.fQt.sQtQt.#.c.l.a.e", +".a.r.a.a.b.a.a.b.e.e.e.e.e.e.e.e.r.e.e.e.e.e.e.b.b.eQt.aQtQt.fQt.x.p.I.E.F.z.A.D.G.o.u.h.g.f.h.g.h.g.g.u.u.y.D.F.F.Q.H.I.F.F.Q.M.L.L.E.H.B.F.z.D.A.o.o.u.w.g.m.x.i.i.d.i.d.i.d.i.c.aQt.c.f.d.f.d.dQt.f.d.i.dQt.d.#QtQt.#.#.c.#.c.c.cQt.c.dQt.d.f.g.i.g.g.g.x.g.f.f.g.f.m.h.u.v.hQtQtQtQt.d.d.i.#Qt.c.#.cQt.#.c.c.#.c.i.c.#.c.#.c.q.#.#.#.i.c.i.#.#.a.#.a.#.a.a.#.l.#.e.b.b.e.b.e.b.a.b.b.b.a.b.b.e.r.l.b.e.b.l.b.l.b.e.e.l.e.l.e.a.b.a.a.#.a.c.cQt.#QtQt.#QtQt.i.qQt.iQt.s.f.i.i.gQtQtQt.#.c.a.a", +".a.a.a.a.a.a.a.a.e.e.e.e.e.e.l.e.l.e.l.e.e.l.e.l.a.a.a.c.c.d.i.d.f.n.I.I.G.y.v.F.B.C.u.g.m.f.f.f.f.h.h.h.u.A.I.P.N.S.E.I.D.B.I.Q.S.Q.E.J.D.C.A.v.v.h.u.g.h.f.f.fQtQtQt.dQt.dQt.d.c.c.cQt.dQtQt.f.iQtQtQtQtQt.fQt.c.#.d.q.d.i.#.c.q.c.qQt.iQt.f.f.i.m.h.n.p.h.h.m.g.g.w.p.v.v.y.o.f.g.f.fQt.d.dQt.c.#.c.#.c.c.#.c.c.#.c.#.c.#.f.#.d.c.i.d.#Qt.#Qt.a.#.rQt.#.q.a.#.#.a.#.a.b.r.b.b.#.a.#.a.a.r.a.#.b.b.a.#.a.r.a.b.l.b.l.e.l.e.e.l.a.a.a.c.a.c.c.c.#Qt.#Qt.iQtQt.q.f.iQtQtQt.i.x.i.fQtQtQt.c.c.c.c", +".a.a.a.a.a.b.a.a.a.a.a.e.l.e.e.e.a.b.#.a.a.a.a.a.a.aQt.cQt.c.d.#.g.o.E.E.B.u.o.D.B.C.n.g.i.i.i.i.p.h.p.o.D.I.P.X.M.Q.I.I.D.J.I.I.K.F.F.A.z.v.v.u.g.w.g.h.i.f.q.dQtQt.f.#.fQt.fQtQt.d.i.d.i.d.g.d.f.g.f.f.gQtQt.gQt.iQt.iQtQt.f.iQtQtQt.dQt.f.f.g.h.p.u.v.v.v.h.h.h.w.p.p.u.A.y.y.w.g.f.f.i.#.c.c.c.#.cQt.#.c.#Qt.#.c.cQt.#.c.c.c.q.#.c.i.#QtQtQt.q.#.c.#.q.c.q.q.c.aQt.a.#.c.cQt.a.r.a.#.#.a.b.a.#.a.#.b.b.a.b.a.b.e.l.b.e.l.b.e.a.r.a.b.c.r.c.c.#Qt.qQtQtQtQtQtQt.q.f.q.f.i.s.f.i.iQtQt.#.c.#.c", +".a.a.a.a.l.a.l.a.l.#.l.l.e.l.a.a.l.a.a.a.a.#.a.#.c.c.c.c.c.c.i.d.g.A.E.F.C.p.v.v.D.z.v.w.g.m.i.g.g.p.n.D.E.R.X.2.K.I.G.D.D.I.F.F.F.z.J.C.u.h.n.h.f.m.x.g.gQt.cQtQtQtQt.dQt.dQt.d.#Qt.#QtQt.g.f.f.f.f.g.f.f.f.fQtQt.i.f.i.s.f.xQt.f.f.f.f.g.x.g.x.u.u.o.y.v.v.v.h.u.h.p.w.u.u.v.u.o.g.f.g.f.d.a.cQt.c.#.c.c.#.c.c.#.c.#.c.c.#.c.#.cQt.#Qt.c.i.#.cQtQt.qQt.iQt.iQt.#.#.rQt.aQt.a.cQt.c.c.a.c.#.c.#.a.#.a.a.#.c.a.c.e.b.l.e.l.e.l.e.a.a.a.c.a.c.a.cQt.#QtQt.#Qt.i.i.iQtQtQtQt.i.x.i.g.x.i.fQtQt.c.a", +".r.a.a.a.a.a.a.a.a.a.a.a.a.a.a.#.a.a.a.a.a.a.c.a.cQt.cQt.cQt.dQt.m.C.G.F.o.v.u.o.D.B.D.o.h.h.h.h.v.v.D.P.2.1.2.2.Q.T.D.A.B.C.F.J.D.G.C.v.u.h.g.x.s.x.s.g.dQtQt.cQt.d.i.d.q.dQt.fQt.i.d.i.f.f.f.s.f.xQt.i.i.f.iQt.s.i.s.f.s.i.f.i.f.i.g.g.g.g.m.g.p.n.n.y.v.u.u.p.h.h.h.h.h.p.p.h.A.u.g.f.f.#.c.c.#.c.#.c.#Qt.c.#.c.q.c.c.#Qt.#.c.#.i.c.i.#Qt.cQt.iQtQtQt.g.i.g.i.q.#Qt.c.c.c.#.cQt.aQtQtQt.cQt.c.#.c.#.a.c.cQt.c.l.l.l.e.e.l.e.e.a.a.b.#.r.a.r.c.#.i.#QtQtQtQtQtQtQt.f.q.f.f.i.i.i.iQtQt.#.c.a.a", +".a.a.r.a.r.a.r.a.a.a.a.a.a.a.r.a.a.#.r.#.#.#.r.a.c.c.c.c.c.d.i.q.i.o.F.B.A.u.n.o.C.G.z.v.o.v.o.o.J.K.S.2#h#c.X.N.E.F.D.z.o.o.y.A.y.C.o.h.h.g.m.f.g.h.f.f.g.d.cQt.d.q.dQt.dQt.fQtQtQtQtQt.i.i.f.f.f.f.i.g.i.f.f.f.i.f.g.i.g.i.m.i.f.g.f.f.i.x.g.h.h.h.p.v.u.p.u.h.m.x.x.m.g.g.m.g.v.u.u.iQt.d.c.b.c.q.c.c.#.c.#.c.c.c.#.c.c.#.c.c.q.d.#Qt.c.i.#QtQt.g.i.g.i.s.i.gQt.iQt.iQt.iQt.f.cQt.c.aQt.aQt.cQt.a.c.#Qt.c.c.c.b.e.e.l.b.e.l.b.a.a.a.c.a.c.c.a.#Qt.#Qt.iQt.q.fQt.q.qQt.i.i.g.gQt.#.c.a.a.l.l.j", +".r.l.a.l.a.a.a.a.r.a.r.a.l.a.a.a.r.r.c.r.#.r.#.a.c.c.c.cQt.dQt.g.g.o.E.F.o.o.u.o.D.F.I.B.o.B.I.K.G.K.E.M.S.M.F.B.D.C.v.u.w.u.v.u.A.u.u.h.g.m.f.f.h.g.h.g.q.dQt.r.q.d.fQtQt.dQt.dQtQt.i.fQt.f.g.f.q.f.f.f.fQt.iQt.x.i.i.f.i.f.f.i.f.g.f.i.f.g.x.g.p.p.p.u.p.u.p.h.x.x.f.x.m.g.f.g.o.u.v.gQt.#.cQt.#.c.c.#.c.#Qt.c.#.c.q.c.#.c.q.d.#.cQt.#.iQt.fQt.sQt.i.f.s.f.s.i.i.q.i.#.i.d.iQtQtQtQtQt.cQt.cQt.#.q.#.#.c.#.#.c.l.b.e.l.e.l.e.e.a.b.a.bQt.b.c.r.#Qt.#QtQtQtQtQt.#Qt.fQt.f.f.iQt.#.a.r.r.#.l.e.j", +".e.e.a.a.a.l.a.l.e.e.e.j.l.e.a.aQt.aQt.c.cQtQt.#.iQtQt.g.f.i.x.g.s.u.G.F.B.z.D.z.M.Q.E.M.Q.F.I.z.A.y.o.v.u.p.h.w.g.m.g.w.g.h.p.n.p.w.g.m.g.f.m.f.g.fQt.d.q.c.cQt.cQt.a.b.a.b.#.b.c.c.cQt.cQtQtQtQt.#.q.#.c.#.c.c.i.#.d.i.dQtQt.iQtQtQt.i.cQt.#.cQt.qQtQt.i.i.g.g.s.i.i.f.f.f.g.f.g.u.z.p.g.f.f.e.dQt.d.fQt.d.dQt.#.d.#Qt.g.f.f.f.q.#.qQtQt.f.x.f.f.i.h.h.u.h.h.h.s.g.i.m.g.g.h.w.i.f.f.f.g.g.i.q.#.#Qt.#.#.c.c.c.a.r.a.a.a.a.e.l.#.a.a.a.a.r.l.r.a.a.qQtQt.f.f.i.i.qQt.i.g.g.gQt.c.r.a.a.e.a.e.e", +".e.b.e.l.b.a.b.a.e.l.e.l.e.a.b.c.a.a.#.#.d.#.cQt.fQtQt.f.m.g.h.h.n.B.F.H.I.T.Q.Z#i.2.N.H.B.B.C.v.u.u.u.p.h.w.h.g.g.g.m.g.g.h.g.h.w.g.g.g.m.f.m.f.i.g.fQt.f.cQt.a.aQt.a.a.r.a.b.a.cQt.cQt.c.cQt.d.#.c.c.c.c.c.#.cQt.cQt.c.#.#.cQt.c.c.#.cQt.#.dQt.xQtQtQt.g.g.g.g.f.sQt.f.s.f.fQt.i.h.o.v.g.f.f.bQt.fQt.dQt.dQt.f.#.iQt.d.f.g.i.fQt.iQt.f.i.iQt.s.f.g.m.g.m.u.p.w.i.s.s.g.m.m.m.p.m.m.x.h.g.x.xQt.i.iQt.#.i.c.f.d.#.a.r.#.l.a.b.l.a.r.a.r.l.a.a.a.r.a.#QtQt.x.fQtQt.i.g.f.g.g.sQt.#.a.a.a.a.e.b.e", +".e.l.e.a.b.l.b.l.e.e.b.a.b.a.a.r.c.c.c.qQt.dQtQt.qQt.s.g.h.h.p.p.B.P.2.U.X.N.L.L.S.H.J.C.C.C.y.o.p.h.h.m.g.f.x.f.g.f.f.x.m.x.m.p.p.w.p.m.h.m.f.i.g.fQt.f.cQt.aQt.c.a.r.a.b.a.r.a.c.c.c.cQt.c.c.c.c.#.c.q.c.#Qt.#.cQt.#Qt.fQt.cQt.qQt.d.#.f.#.c.cQtQt.xQtQt.i.x.i.iQtQt.i.f.f.f.fQt.i.h.A.h.g.dQt.dQt.d.i.d.i.dQt.d.#Qt.i.f.f.f.gQtQt.i.#.f.g.f.g.g.g.m.p.u.p.u.p.p.g.h.p.p.h.p.u.y.n.v.u.u.w.s.f.x.i.gQtQtQt.dQt.#.c.#.c.a.a.a.a.a.a.a.a.a.a.#.a.a.a.#.c.#Qt.f.fQt.q.f.m.h.g.f.f.#Qt.c.l.b.l.b.e", +".e.e.b.a.b.a.a.b.l.e.a.a.a.c.c.c.c.qQtQt.d.f.g.f.fQt.f.f.h.v.o.z.L.2#h#c.L.T.H.I.z.C.y.u.u.h.p.h.g.m.h.g.x.x.f.g.fQt.g.f.f.h.x.m.v.u.w.p.w.h.m.x.g.x.dQtQt.c.a.b.#.b.a.b.#.b.a.b.c.c.c.c.c.c.c.c.c.q.c.c.#.c.c.#.c.cQt.#.c.#.c.c.c.c.c.#.c.c.#.cQtQtQt.i.f.f.f.gQt.iQt.gQt.fQt.gQt.i.g.z.y.w.f.dQt.fQt.dQt.dQt.fQt.i.dQt.f.g.f.f.i.f.d.g.x.x.p.m.u.v.v.z.v.o.y.A.y.n.u.y.y.C.z.z.I.z.z.C.A.v.p.g.m.g.g.s.fQt.i.d.#.q.#.#.c.#.b.a.a.#.a.aQt.a.c.a.a.a.#.c.c.fQt.f.iQt.i.h.g.h.iQt.#.#.c.a.c.a.e.b", +".a.a.a.l.a.e.a.a.#.a.a.r.#.c.cQtQt.dQt.f.f.f.f.f.s.i.h.u.v.o.B.B.1.W.Q.F.D.z.C.y.A.u.v.p.u.h.h.h.g.x.x.h.x.g.q.f.q.g.f.f.x.x.w.n.v.v.v.h.w.g.h.gQt.f.i.d.cQt.b.a.b.#.b.a.b.e.b.b.c.cQt.c.c.cQt.c.c.c.#.c.c.#.c.c.#.c.c.c.#.c.c.#.c.c.#.c.c.c.c.#Qt.dQt.iQt.f.i.fQtQtQt.i.f.f.f.f.s.f.h.z.z.z.g.x.i.fQt.gQt.fQt.f.f.f.g.i.f.g.h.g.x.w.h.h.m.h.w.p.F.F.E.E.H.I.E.Q.I.F.I.H.I.Q.E.Q.N.S.F.K.B.C.o.p.h.u.g.g.g.g.f.f.i.f.#Qt.c.a.c.a.c.c.c.a.c.a.c.a.#.a.a.c.c.#Qt.f.q.i.g.x.h.g.f.f.#.c.#.a.c.b.b.a", +".a.b.a.b.a.#.a.b.a.bQt.c.c.c.c.d.f.f.f.g.f.f.x.g.h.v.v.A.D.z.D.B.G.z.v.h.p.g.p.h.h.p.h.h.h.w.g.w.g.m.h.i.x.x.f.g.g.x.x.m.h.w.p.v.o.u.v.p.w.g.g.hQt.i.dQtQt.c.b.#.b.a.b.#.b.a.b.a.c.c.c.c.c.c.c.c.#.c.c.#.c.c.#.c.c.c.#.c.c.c.c.c.#.c.c.c.c.#.c.cQt.#.c.dQtQtQt.fQtQtQt.fQtQtQt.fQt.g.g.y.F.B.v.h.x.h.x.x.x.x.h.f.h.f.h.h.h.w.h.p.w.u.o.A.o.B.z.I.P.R.N.P.R.N.M.L.M.P.T.R.N.N.L.2.1.X.L.E.E.B.C.z.u.p.h.w.g.g.i.gQtQt.i.#.#Qt.a.r.#.b.c.b.a.r.a.c.l.a.l.a.#.d.i.d.s.x.m.u.w.h.h.gQtQt.c.c.c.a.e.b", +".a.a.#.a.b.a.a.a.a.c.c.dQt.cQt.fQt.f.x.x.g.w.h.w.o.C.z.C.z.o.z.v.h.p.g.m.m.p.g.g.w.p.h.g.h.x.x.g.p.p.h.m.h.h.x.x.m.g.w.p.h.v.u.o.u.n.h.h.h.g.s.gQt.i.d.i.c.c.a.b.#.b.a.b.b.l.r.e.c.a.c.a.c.a.c.a.c.a.c.a.c.a.c.a.a.a.l.a.l.a.l.a.a.a.a.a.a.a.a.a.#.c.c.#.d.dQtQtQt.q.i.iQt.f.g.f.i.g.p.A.F.z.v.o.h.s.w.x.p.h.w.p.w.p.n.n.u.o.o.A.C.z.I.F.J.F.E.E.Q.H.H.H.E.Q.E.H.I.F.F.H.P.P.P.N.N.N.M.S.P.E.B.B.o.v.u.v.p.m.x.m.f.iQt.d.q.c.c.c.b.a.b.r.a.b.b.r.l.e.a.c.c.d.dQt.i.i.h.h.p.w.h.gQt.i.#Qt.c.c.c.b", +".b.a.b.a.a.a.r.a.r.aQt.dQt.i.dQt.g.h.g.m.h.h.w.p.J.F.I.C.v.u.u.u.h.h.m.f.i.f.h.p.h.h.h.w.h.g.w.g.v.u.w.h.u.h.m.h.n.u.v.u.v.u.u.o.u.u.v.p.w.h.m.h.iQt.d.i.c.c.r.a.b.a.b.#.b.b.a.b.c.c.c.c.c.c.c.c.c.c.#.c.q.#.c.q.a.a.a.a.a.a.a.a.#.a.a.#.a.a.#.a.c.c.c.c.#Qt.fQtQtQtQt.fQt.fQt.fQt.i.v.y.F.C.A.v.n.n.n.p.h.n.p.n.v.o.v.A.z.z.I.B.F.H.H.Q.I.F.B.F.B.J.C.C.C.C.A.y.A.y.y.C.D.B.B.F.Q.P.T.R.S.S.H.B.C.z.v.u.w.h.g.m.q.g.iQt.#.c.c.c.a.b.b.a.b.b.a.b.l.e.#.a.cQt.d.dQt.m.h.w.u.h.h.gQtQtQt.c.c.c.r.c", +".d.d.d.d.c.c.c.c.iQt.d.q.f.s.s.p.h.h.u.o.o.B.I.I.o.v.p.p.h.h.h.u.g.f.f.f.g.g.f.f.f.g.f.f.g.w.p.h.h.w.u.v.v.z.C.C.A.z.C.A.u.u.u.p.w.p.w.h.x.h.f.fQtQt.fQt.dQt.c.c.b.l.b.a.a.a.b.a.c.a.r.a.c.b.c.a.c.#.c.#.c.c.#.c.c.a.b.a.b.a.a.r.a.c.a.c.c.c.#.d.#.c.#.c.c.c.#.dQtQtQtQtQt.iQtQt.d.q.g.p.y.z.D.v.y.v.y.B.G.T.S.T.E.H.H.P.Q.P.P.P.T.H.F.G.B.D.o.o.p.n.p.w.p.w.h.u.h.h.n.w.h.v.n.u.z.z.F.E.H.E.E.Q.z.F.D.A.C.y.y.v.m.g.fQt.qQtQt.c.f.d.c.cQt.a.b.bQt.b.b.b.a.a.c.b.cQt.h.p.v.v.h.h.q.d.dQt.c.dQt.q", +"QtQtQt.fQtQt.c.c.c.f.f.h.w.n.s.p.A.z.B.D.z.D.B.D.u.v.h.w.p.w.h.w.i.f.s.x.g.x.x.h.i.g.g.w.u.p.o.v.A.v.A.z.C.z.z.B.A.z.C.v.v.n.u.u.p.w.h.w.i.x.i.f.f.#.dQt.c.c.a.c.l.e.e.a.b.a.a.b.c.c.c.c.c.c.c.c.#.c.#.cQt.cQt.c.c.a.a.b.a.c.b.a.a.a.a.c.#.c.c.c.c.c.c.c.c.c.c.cQtQtQtQtQtQtQtQt.d.f.f.u.u.C.B.v.u.u.o.D.F.I.P.P.F.F.F.E.H.F.K.I.z.D.D.C.C.v.v.v.m.h.g.g.w.g.h.g.s.w.h.h.u.w.h.n.v.A.C.B.D.J.B.z.z.C.C.y.v.u.v.u.p.h.i.i.gQt.dQt.c.c.c.c.b.b.#.b.c.c.a.bQt.c.#.c.qQt.g.h.v.u.w.g.f.fQt.c.c.#.d.f", +".d.x.d.d.f.q.f.q.f.g.g.g.v.v.z.F.E.K.I.D.A.v.v.v.m.h.h.u.h.g.g.g.h.g.x.f.g.g.g.h.h.w.u.h.v.v.o.o.B.F.z.B.D.z.D.C.v.v.u.v.p.v.s.h.w.h.g.x.x.g.i.gQtQt.i.cQt.c.r.b.e.l.e.a.a.b.a.a.b.a.b.a.b.a.b.a.c.c.c.c.c.#.c.c.a.b.c.a.b.a.b.c.a.#.a.a.c.c.#.c.#.c.#.c.#.c.c.r.c.c.c.c.c.c.c.c.d.cQt.g.p.A.z.C.h.h.u.o.o.B.G.I.D.B.B.B.D.D.C.z.v.o.u.u.w.h.h.h.g.g.m.g.i.g.f.m.g.g.x.w.x.w.h.w.u.p.v.u.u.v.u.u.u.p.w.h.u.h.u.w.p.u.g.w.i.i.f.f.q.c.#Qt.c.a.b.a.f.c.c.c.d.cQt.d.c.i.f.g.w.u.p.p.gQtQt.c.iQt.i.f", +".d.d.g.q.f.h.x.h.p.o.A.C.E.Z.X.2.S.I.I.o.v.v.o.v.h.h.v.u.v.u.u.h.h.g.h.w.h.n.p.p.v.u.u.v.z.D.B.z.Q.E.H.E.z.B.C.z.v.p.w.h.h.m.x.h.g.g.h.x.g.f.f.fQtQtQt.c.c.b.l.b.l.e.e.a.a.b.c.b.c.a.b.a.b.a.r.a.a.a.a.a.a.a.a.l.a.b.a.b.e.b.a.l.a.a.a.a.a.c.a.c.c.#.c.c.c.r.c.c.c.c.c.#.c.#.c.#.f.dQt.f.g.v.z.o.h.h.h.u.v.v.v.v.z.C.C.C.o.v.o.v.p.p.u.h.h.i.x.i.h.g.x.x.x.h.g.x.x.x.h.g.x.g.x.g.w.h.h.g.g.i.s.i.h.g.x.g.h.x.s.f.p.h.p.p.g.h.g.gQtQt.c.c.cQt.cQtQtQt.f.dQt.i.d.iQtQt.g.g.h.h.v.h.x.f.fQt.i.f.f.x", +".x.h.x.s.s.p.p.p.D.K.S.V.8#p#i.1.T.B.I.D.o.o.v.o.o.y.o.v.o.v.v.A.h.w.u.h.v.v.v.v.o.v.A.o.C.B.B.F.Q.S.Q.E.F.B.D.B.o.v.h.n.m.s.h.x.x.h.g.f.f.f.gQt.i.#.cQt.a.a.e.e.b.l.e.#.a.a.b.a.b.a.c.b.c.a.b.a.a.a.l.b.l.a.b.a.b.l.e.e.l.e.a.b.l.l.a.#.a.a.#.c.a.#.a.a.a.a.a.l.a.#.a.a.b.a.a.a.d.c.d.q.f.v.C.z.h.v.h.n.h.n.v.p.v.o.v.w.u.u.h.h.w.g.g.i.m.f.f.f.f.g.fQt.fQt.fQt.g.f.f.f.g.f.g.f.g.i.g.f.i.#.d.#.d.i.dQt.dQt.fQt.m.g.w.h.u.p.p.p.i.iQtQt.#.#Qt.#.d.i.#Qt.dQtQtQt.iQt.f.g.g.u.v.v.h.m.x.f.g.h.g.h", +".w.u.v.v.v.o.A.A.J.R.W#c.8#h.L.T.D.D.D.C.z.u.u.u.o.o.o.o.o.o.o.o.h.p.w.p.h.h.p.u.h.v.u.v.o.o.A.C.F.I.D.F.F.I.I.I.v.o.w.p.w.h.m.h.h.g.f.f.i.fQtQt.c.q.c.a.a.r.e.e.e.e.l.b.a.b.c.a.b.a.e.e.e.e.b.e.e.e.e.e.e.e.e.j.e.j.e.e.e.e.e.e.l.b.l.l.a.a.a.l.a.a.a.a.a.l.a.a.a.b.a.b.a.a.b.a.d.c.c.cQt.h.A.C.u.p.u.h.h.h.h.w.u.h.h.p.h.h.w.g.g.i.m.f.f.fQt.gQtQtQtQtQtQtQtQt.fQt.gQtQtQtQtQt.f.fQt.c.c.c.b.#.c.c.c.q.c.d.fQt.f.g.g.h.h.h.u.h.i.i.sQt.f.fQt.fQt.f.dQt.i.f.g.f.f.g.f.g.g.u.o.C.p.v.h.m.g.h.o.p", +".D.B.D.B.D.B.J.B.F.Q.E.F.E.B.C.C.o.u.y.v.p.w.h.p.p.p.h.p.h.p.h.p.m.h.g.h.h.w.p.h.m.g.g.w.u.u.v.u.v.u.o.A.C.z.B.B.v.o.A.o.p.w.p.w.g.g.fQt.f.gQt.i.c.#.aQt.e.e.e.a.e.l.e.a.e.a.b.a.e.e.b.l.b.l.e.l.e.e.e.e.e.e.e.e.l.e.l.j.l.e.t.e.l.l.l.l.a.l.a.a.e.l.e.l.e.e.l.e.e.e.e.e.e.e.e.e.f.cQt.b.c.m.v.B.v.o.p.p.h.h.g.g.h.w.h.m.h.m.g.f.i.f.f.f.f.i.qQt.d.d.d.f.d.d.f.d.#.d.#.dQt.dQt.d.#.c.cQt.b.b.c.b.a.#.r.c.#.c.#Qt.f.f.f.i.i.h.g.h.h.h.g.p.m.g.f.f.i.g.f.f.f.i.i.f.x.g.g.m.h.o.D.I.D.o.u.u.o.v.A.D", +".P.P.E.J.z.C.C.C.v.A.v.u.p.w.p.n.u.u.h.h.g.h.h.w.i.s.i.s.g.g.i.s.g.g.g.m.g.h.h.w.f.f.m.g.w.h.w.p.p.h.n.n.o.A.z.B.A.z.z.B.A.o.v.n.h.m.i.f.g.f.iQt.#Qt.a.a.e.a.b.b.l.b.e.a.e.b.c.a.b.e.l.e.e.e.e.b.j.k.j.j.j.j.j.j.e.j.e.e.j.e.e.e.j.l.e.l.#.a.a.a.l.e.l.e.a.l.b.l.e.e.e.e.e.b.e.e.c.c.bQt.c.x.z.z.z.A.o.v.h.g.w.g.h.g.h.g.i.i.fQt.m.i.i.f.fQtQt.d.i.dQt.dQt.dQt.dQt.cQt.q.c.#.q.c.c.a.b.a.c.r.#.b.l.a.#.a.#.cQt.d.g.q.h.f.m.x.g.h.h.p.p.g.h.g.h.g.f.i.f.s.f.s.x.s.h.m.h.g.w.o.I.G.I.D.A.D.A.D.I.K", +".K.G.v.u.p.m.g.g.i.i.g.m.g.h.p.h.s.h.i.i.f.g.x.f.f.dQt.dQt.d.d.d.cQt.dQt.d.iQt.d.q.f.d.f.x.h.h.s.s.m.m.p.u.v.v.o.u.o.o.B.I.B.C.A.v.p.w.h.g.qQt.i.c.c.b.#.e.b.e.e.e.e.j.e.j.e.j.k.e.l.e.e.e.e.j.e.j.e.e.j.e.j.e.e.j.l.e.t.e.l.e.l.b.l.e.j.e.j.e.j.e.e.e.l.e.j.e.e.e.e.j.e.e.l.e.e.j.e.a.c.f.f.w.v.E.z.v.h.g.f.f.x.m.x.g.m.x.f.g.iQtQt.iQtQtQtQtQt.d.c.c.c.c.c.c.c.c.c.c.c.c.c.c.c.b.r.b.b.b.l.b.b.b.e.e.b.r.d.d.dQt.d.d.d.dQt.dQt.#.gQt.i.g.w.u.v.h.w.h.h.h.u.u.p.p.v.v.v.C.B.Q.R.I.K.I.I.I.C.D.B", +".E.D.z.p.g.g.f.m.i.g.i.g.g.g.h.h.h.g.i.i.f.f.g.x.dQt.d.i.dQt.c.c.c.cQt.c.c.cQtQt.c.cQt.fQt.f.h.x.i.s.g.m.w.h.v.u.w.p.o.B.z.A.o.v.v.v.p.u.g.s.f.q.c.c.#.b.b.e.j.e.e.j.e.k.e.k.e.j.e.e.e.l.j.j.e.j.e.e.j.e.j.e.j.e.l.j.e.e.j.e.j.e.l.e.e.l.e.l.e.e.e.l.e.e.j.e.j.e.j.l.e.l.j.e.t.e.e.e.a.cQt.f.g.o.Q.J.v.p.g.i.f.x.f.f.f.f.f.i.f.f.gQtQtQtQtQt.iQt.c.c.c.c.c.c.c.c.c.a.c.c.c.r.c.a.a.e.a.l.r.b.a.e.l.e.l.b.a.c.d.d.fQt.d.#.cQt.c.dQtQtQt.f.g.p.p.u.u.v.u.u.y.v.A.y.o.C.A.z.D.E.K.R.I.B.G.B.D.A.o.o", +".G.B.o.p.g.f.f.g.i.i.f.f.i.g.i.f.q.iQt.f.g.f.f.qQt.i.d.c.c.b.b.b.a.c.c.a.c.a.c.c.a.a.c.c.d.d.f.f.g.f.g.g.w.n.h.n.m.g.u.o.o.v.p.w.u.v.u.h.g.g.s.iQt.c.c.a.r.e.e.b.j.j.k.j.j.b.j.k.l.j.e.j.e.j.e.j.e.l.e.j.e.e.l.e.j.e.l.e.l.e.l.e.e.l.e.e.l.e.j.l.j.e.j.l.e.j.e.t.e.j.j.e.e.e.e.e.j.e.aQt.d.f.g.u.E.D.v.u.h.h.x.f.i.f.i.f.f.f.f.iQtQtQt.iQtQtQtQt.c.a.c.a.c.a.c.a.b.c.b.a.b.a.a.b.b.b.b.b.a.e.b.#.e.e.b.a.a.c.fQt.c.d.c.c.c.c.fQt.cQtQt.g.g.h.p.u.y.A.y.z.z.B.z.J.z.B.B.F.F.T.P.K.B.D.z.o.v.o.v.B", +".F.z.v.w.i.f.f.f.f.f.g.i.fQt.fQtQtQtQtQt.dQt.dQt.c.c.c.c.c.b.a.bQt.a.a.r.a.b.c.r.a.r.#.c.c.dQt.d.qQtQt.g.g.w.w.h.g.m.g.w.p.w.x.m.u.p.p.w.g.m.f.gQtQtQt.b.a.e.j.e.j.j.j.e.k.e.k.j.e.l.e.e.j.e.j.e.j.e.j.e.j.e.j.e.l.j.e.l.e.e.e.t.b.e.e.j.b.l.e.e.j.e.e.j.e.j.e.j.e.j.e.j.j.j.l.j.e.j.e.c.#Qt.g.h.F.B.z.u.h.g.f.x.fQt.fQt.f.s.f.fQtQtQtQtQtQtQt.c.c.c.c.r.c.c.r.c.a.a.a.b.a.a.r.a.b.l.a.b.a.b.l.b.e.l.a.a.c.c.c.c.c.c.c.c.c.c.c.dQt.g.f.i.w.h.h.p.v.y.v.C.C.C.C.B.C.D.F.K.T.T.S.K.B.z.o.v.o.B.C.B", +".D.o.p.g.f.f.fQtQt.#QtQtQtQtQtQtQtQtQt.#Qt.d.d.f.#.c.c.a.c.b.a.e.c.bQt.a.b.a.b.c.a.a.c.a.aQt.c.d.i.c.i.f.m.g.x.f.s.f.m.w.m.g.g.i.g.g.w.g.m.g.g.sQt.q.c.c.a.b.e.b.j.j.k.j.j.k.j.k.e.j.e.j.e.j.e.j.e.j.e.j.e.l.e.e.l.e.l.b.e.l.e.e.l.j.l.e.e.j.e.l.j.e.l.e.j.e.j.e.j.e.j.e.e.j.e.e.j.e.b.c.#.dQt.s.C.A.z.u.h.x.x.fQtQtQtQtQtQt.f.f.iQtQtQtQtQt.c.#.c.r.a.a.b.a.a.b.c.b.c.a.r.a.b.a.a.#.b.a.a.a.#.a.a.a.a.#.a.a.a.c.c.c.c.c.b.c.c.cQt.f.f.f.i.g.m.h.u.v.v.y.v.y.z.C.C.z.G.E.P.S.I.E.F.D.z.C.B.B.B.D", +".o.u.h.g.i.iQtQtQt.dQt.c.cQt.c.q.c.#Qt.c.cQt.c.c.c.#.c.#.c.l.r.b.a.a.b.a.a.a.a.a.b.a.b.a.b.a.a.a.c.#.c.d.f.g.g.h.x.g.x.w.h.s.f.i.g.g.g.f.f.g.f.gQtQt.c.#.r.a.a.e.e.j.j.j.j.j.e.j.e.l.e.l.e.j.e.j.l.e.e.j.e.j.l.j.e.l.e.e.l.b.e.l.e.e.e.j.e.l.e.j.e.e.j.e.j.e.j.e.e.j.e.j.e.e.j.e.e.e.l.aQt.#Qt.f.p.y.A.u.h.i.fQtQtQtQtQtQtQtQtQtQtQtQt.iQtQt.c.#.b.a.r.a.b.a.r.a.e.e.e.a.b.a.a.b.a.b.a.a.b.a.b.a.a.a.a.a.a.a.a.a.c.c.a.c.c.a.c.a.d.dQtQt.f.f.fQt.g.h.g.h.p.u.p.v.o.C.D.T.T.E.F.D.J.I.D.B.C.D.B.C", +".p.g.fQtQtQtQt.f.cQt.c.c.q.c.a.a.c.c.c.c.c.a.c.r.c.a.c.b.a.b.e.e.a.a.a.b.e.e.b.a.#.a.a.b.l.e.e.e.e.a.bQt.d.g.f.f.x.x.m.g.h.h.f.iQt.iQt.iQt.dQtQtQt.iQtQt.#.b.c.b.e.e.j.k.j.k.j.k.e.j.e.j.e.l.e.e.e.j.l.e.e.e.e.l.e.b.l.e.l.e.l.e.b.l.l.e.l.e.e.j.e.l.e.l.j.e.j.e.j.e.e.e.t.e.l.e.j.e.e.a.a.c.qQt.x.v.u.u.h.f.dQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt.c.#.a.b.e.e.b.e.e.e.b.l.e.a.e.a.e.a.l.l.l.l.a.a.a.a.a.#.a.a.a.#.r.a.#.b.a.b.a.b.a.b.c.c.cQt.c.#Qt.#Qt.f.f.m.g.m.g.h.v.C.B.K.E.G.B.z.D.J.F.C.C.C.C.v", +".g.g.gQt.#QtQt.fQtQt.c.#.c.a.a.l.b.b.c.a.a.a.a.a.a.a.#.c.a.b.e.e.e.a.b.l.e.e.l.a.b.a.e.e.b.l.j.b.e.b.#.c.d.f.x.g.f.h.s.n.w.g.g.d.i.#Qt.#.cQtQtQt.iQtQt.#.c.c.a.a.e.e.j.j.e.k.e.j.e.l.e.l.e.j.e.t.e.l.e.e.l.l.e.l.e.l.e.e.l.e.e.l.l.e.e.l.e.l.e.l.j.e.j.e.e.j.e.l.e.e.t.e.e.e.e.e.e.e.e.#.a.a.#.#.i.g.u.g.fQtQt.a.#Qt.#Qt.#Qt.#QtQt.iQtQtQtQt.#.c.a.a.a.a.a.a.a.a.e.e.e.b.a.b.a.a.e.a.a.a.a.l.#.l.a.r.a.r.a.r.a.a.c.a.c.b.c.a.r.a.a.b.a.a.a.c.c.#.cQtQtQt.f.x.i.h.u.A.D.E.J.C.v.v.C.B.D.C.z.v.y.v", +".iQtQt.iQtQt.q.d.c.c.c.c.c.c.c.a.a.c.#.r.a.b.a.b.a.b.b.a.e.a.a.a.b.a.e.e.b.l.b.a.e.l.e.l.a.b.a.a.e.b.e.a.a.cQt.s.g.s.m.g.g.f.g.g.dQt.c.cQt.a.c.c.a.cQt.c.c.i.cQt.b.l.e.e.e.l.e.e.j.j.j.e.j.e.j.e.e.j.j.j.j.j.b.e.b.l.e.b.l.e.b.l.b.a.b.l.b.l.e.e.l.l.l.l.j.e.e.e.j.e.e.e.t.e.t.e.e.j.e.e.l.a.#.aQt.i.p.p.h.x.d.#.a.r.c.c.r.c.d.dQtQt.c.iQt.cQt.c.c.b.a.b.a.b.a.a.e.l.e.l.e.l.e.e.l.l.l.e.a.c.c.c.e.e.l.b.l.e.l.e.e.e.e.e.e.b.b.b.a.a.b.a.c.c.c.cQtQt.d.f.g.g.x.g.u.o.u.o.v.p.w.p.w.u.z.C.o.v.p.h", +".s.f.qQtQtQt.#.c.c.c.cQt.c.c.a.c.c.b.c.a.b.a.r.a.b.a.l.b.a.a.b.a.l.b.a.l.e.e.e.a.j.l.b.e.e.a.b.a.b.e.e.a.#.#QtQt.g.g.m.h.f.g.d.f.cQt.c.#.c.c.cQt.a.a.a.c.#.c.c.d.a.a.a.a.a.e.a.e.e.l.e.l.e.l.e.l.e.b.e.b.b.e.e.b.l.b.l.l.e.l.e.l.e.l.e.e.l.e.e.l.l.l.l.e.l.j.e.e.e.e.j.l.e.e.e.e.j.j.l.e.e.a.r.a.q.i.g.n.g.x.d.r.c.a.a.c.a.c.cQt.cQt.#.d.#.i.c.#.c.b.a.a.b.a.a.r.l.e.b.l.e.e.l.e.l.l.l.a.a.c.a.c.e.l.e.l.e.e.e.l.b.e.e.b.e.b.l.b.e.a.a.b.c.c.c.c.c.dQt.f.f.x.x.w.u.u.v.v.h.h.h.h.m.u.o.o.o.o.p.h", +".i.i.iQtQtQt.c.#.#.c.c.c.a.r.a.r.#.c.b.a.c.b.a.a.a.b.a.a.e.a.a.a.e.e.e.e.e.l.e.e.j.j.j.l.e.a.a.a.e.e.l.b.a.c.gQt.s.i.m.fQt.d.fQt.f.c.c.#.c.#.c.b.a.a.c.a.c.c.c.c.a.r.a.c.a.c.a.c.a.a.a.a.a.a.a.a.e.l.e.e.l.l.b.l.e.a.e.b.l.e.b.l.b.e.l.e.e.b.l.e.b.l.l.t.e.e.e.e.l.e.l.e.j.j.e.j.e.j.e.j.l.r.a.#Qt.f.m.h.h.f.d.rQt.b.c.c.c.c.r.c.c.#.c.#.d.#.c.#.a.a.a.a.a.a.a.a.l.l.l.l.b.l.l.b.l.l.#.a.a.a.c.c.e.b.l.e.e.l.j.e.e.l.e.e.e.a.b.a.a.b.a.a.c.a.c.c.c.qQt.f.f.x.m.g.u.v.u.h.u.m.g.g.i.m.p.v.u.v.h.g", +".gQtQtQt.iQt.i.c.c.cQt.cQt.aQt.a.b.a.a.a.b.a.e.b.e.a.l.b.a.a.r.a.l.b.e.l.e.e.j.e.j.j.j.e.j.e.a.e.e.e.b.a.a.#QtQt.g.s.f.i.d.i.c.c.aQt.aQt.a.b.a.b.b.l.r.a.a.b.a.c.c.c.c.c.r.c.c.c.a.c.c.cQt.#.cQt.a.a.a.a.a.c.a.c.l.b.l.l.r.l.b.l.b.l.e.b.l.l.e.l.l.l.b.l.e.l.e.e.e.l.e.e.e.l.j.e.j.j.l.e.e.a.a.a.i.f.h.w.g.f.d.r.a.c.c.b.c.c.c.c.#.cQt.c.#QtQt.d.a.a.a.a.a.b.a.a.e.a.l.a.l.a.l.r.l.a.r.a.a.a.b.a.e.l.e.l.e.e.e.e.l.e.e.l.b.a.c.b.a.b.a.b.c.c.r.c.#.dQt.f.g.x.g.s.u.u.h.w.h.i.x.i.s.f.i.g.m.h.g.g", +"QtQt.gQt.#.d.d.cQt.c.c.c.c.c.c.a.a.a.b.a.a.a.a.e.l.e.e.l.e.e.l.e.e.l.j.j.j.j.j.j.j.j.j.j.j.e.e.l.j.e.e.a.a.cQt.s.i.g.fQt.i.cQt.f.a.r.#.c.a.r.a.b.e.b.e.e.b.a.b.e.c.a.c.a.c.a.c.a.c.#.c.#.c.c.#.c.#Qt.c.#.aQt.c.q.a.a.#.e.l.e.b.l.e.l.e.l.e.e.l.b.l.l.l.l.e.l.e.e.e.j.e.t.e.e.e.l.j.j.e.e.l.a.#.a.c.i.g.u.g.f.dQt.c.a.c.c.c.c.c.c.d.#.cQtQtQt.iQt.a.#.a.e.a.l.a.l.a.a.a.a.a.a.a.a.a.r.a.a.a.a.a.a.e.e.l.b.e.t.e.j.l.l.j.l.e.a.a.a.l.a.b.a.c.c.c.c.cQt.d.f.f.g.g.w.u.u.h.g.g.g.m.gQtQt.xQt.i.i.m.f", +"QtQt.#.#.c.c.a.b.a.a.a.a.#.a.a.b.b.l.b.e.e.e.j.e.e.e.e.e.l.b.e.l.j.j.e.e.e.j.e.j.j.j.j.e.j.l.e.e.e.e.e.e.a.qQtQt.g.i.qQt.c.f.cQt.b.#.a.r.a.b.b.e.j.b.e.e.b.e.e.b.b.a.b.b.a.b.a.b.q.c.#.q.#.#Qt.#.f.#.c.#.c.c.#.c.l.r.a.l.r.l.a.l.e.l.b.e.e.l.e.l.l.l.l.l.l.e.b.e.e.l.e.e.j.l.j.e.j.e.t.e.e.b.c.a.cQt.m.h.g.g.#.a.c.r.c.c.a.c.c.d.qQt.c.#.iQtQtQt.r.a.a.a.r.a.a.a.l.a.l.a.r.#.a.a.q.#.a.a.a.e.a.b.l.b.e.l.e.e.l.e.l.e.l.b.l.a.l.a.a.b.a.c.b.c.c.c.c.#.i.f.f.h.h.h.v.p.v.g.m.x.i.x.s.qQtQt.x.f.i.g", +"QtQt.c.c.cQt.b.b.a.b.a.b.a.a.b.a.e.l.e.l.e.l.e.l.j.j.j.j.e.j.j.b.j.j.t.j.j.j.j.j.k.k.j.j.j.j.j.e.j.e.e.a.a.cQt.g.qQt.i.c.q.cQt.c.#.b.a.#.e.b.l.e.j.j.j.e.j.e.e.e.a.a.b.a.a.b.a.a.a.r.a.a.a.#.r.#QtQt.gQt.gQt.i.f.#.a.l.e.l.e.b.e.l.e.a.l.b.l.e.e.l.l.l.b.e.l.e.e.l.j.e.t.e.e.e.e.j.j.e.e.l.#.a.#.c.d.i.m.w.i.cQt.c.#.c.c.c.d.dQt.cQt.c.#.dQtQt.i.c.r.a.r.#.r.a.r.a.a.#.r.a.r.a.r.a.c.r.a.l.l.b.l.e.l.e.e.l.e.e.b.t.l.t.l.l.a.a.a.b.a.b.a.c.c.c.c.dQt.d.f.g.h.g.w.p.h.g.g.g.i.g.i.g.f.x.iQt.s.h.h", +".qQtQt.c.c.b.e.a.e.b.#.a.a.b.a.a.e.e.e.e.j.e.j.e.j.j.j.b.j.e.j.l.j.b.j.e.j.j.j.j.k.k.j.j.j.j.j.j.j.e.e.a.a.#QtQtQt.qQt.q.d.c.#.c.#.a.#.b.e.r.e.e.e.j.j.j.k.e.e.e.e.b.l.e.b.l.e.e.a.a.r.a.r.#.a.#Qt.iQtQtQt.qQtQt.#.a.#.a.b.b.l.#.e.l.b.e.l.e.b.l.l.b.l.l.l.e.e.e.e.l.e.e.j.l.j.l.e.e.j.l.e.b.a.a.b.i.f.m.g.gQt.a.c.c.c.c.c.dQt.fQt.c.#.cQtQtQtQt.#.a.r.a.a.r.#.a.l.r.r.a.a.a.r.a.c.#.c.a.#.a.e.e.l.e.e.l.b.l.e.l.l.l.l.l.l.l.a.a.l.a.a.r.a.r.c.c.c.cQt.f.h.g.p.p.p.h.m.g.s.g.f.f.g.iQt.i.q.x.p.h", +".h.h.f.#.a.a.a.a.a.a.b.a.b.l.j.e.l.e.l.e.j.e.j.e.j.j.j.j.j.j.j.j.e.l.e.l.e.j.e.t.j.j.j.j.0.j.e.j.k.l.a.#Qt.iQtQt.i.i.gQt.i.i.c.c.a.r.a.e.l.l.e.e.e.e.j.j.j.j.j.j.j.j.e.j.l.e.e.l.b.l.e.#.a.r.a.c.r.r.#.q.f.g.g.i.g.dQt.c.c.a.a.b.l.r.l.a.b.a.e.l.a.a.a.a.e.l.a.l.b.l.l.l.l.e.l.l.j.e.j.l.b.l.e.#.j.aQt.x.u.h.f.q.a.#.e.b.l.a.d.d.r.a.#.d.qQtQtQt.r.r.a.r.a.r.a.r.r.a.r.#.r.r.#.r.a.r.a.a.r.l.r.a.a.#.r.l.l.l.l.l.l.l.a.l.a.l.a.a.#.a.a.a.a.a.c.c.#.rQtQt.g.h.p.h.p.g.g.g.x.g.g.f.i.fQt.f.f.m.g.m", +".h.g.f.#.a.#.a.a.r.a.c.a.a.b.l.e.j.b.e.l.j.e.j.e.j.j.e.j.e.j.e.j.l.e.l.j.e.l.e.e.j.j.j.0.j.j.j.j.j.e.a.#QtQtQt.iQtQt.f.iQt.dQt.c.b.a.e.l.b.l.e.l.e.e.e.j.e.j.e.j.e.j.e.j.e.e.e.e.e.e.l.b.a.c.#.c.a.#.#.#QtQt.f.m.f.gQt.f.cQt.a.#.a.a.a.a.a.a.a.a.a.l.a.l.a.a.e.a.l.l.b.e.l.l.e.l.j.e.j.e.l.l.b.e.j.#.i.x.h.m.fQt.c.c.e.a.aQt.#.d.a.q.c.#QtQtQt.f.#.a.r.r.a.r.a.r.a.r.a.r.r.a.r.r.r.a.#.r.a.a.a.l.r.l.a.l.a.a.l.a.e.a.l.b.l.a.l.l.a.l.a.a.#.a.c.#.r.r.#.i.s.p.u.p.g.w.g.g.s.g.f.iQtQtQt.s.f.i.f.g", +".h.mQtQt.i.c.#Qt.a.c.b.a.b.l.e.e.l.l.e.e.j.e.j.e.j.j.j.j.j.j.j.j.e.e.e.l.b.j.e.t.j.j.j.e.j.j.j.j.k.a.c.qQtQt.sQt.f.i.g.#.d.i.c.c.l.l.b.a.e.e.l.e.j.e.j.j.j.j.j.j.j.e.l.j.e.l.e.l.e.l.e.a.a.b.c.a.a.aQt.#.iQt.f.f.gQt.dQt.c.c.c.cQt.#Qt.cQt.a.a.#.a.#.a.a.#.l.a.l.l.l.l.l.l.l.b.l.j.e.t.e.e.b.a.c.b.cQt.x.g.w.gQt.c.q.a.#.a.c.cQt.#.#.#QtQtQtQtQt.#.r.a.r.a.r.a.r.a.r.q.a.#.r.c.r.a.a.r.a.r.a.r.a.r.a.r.a.r.l.r.a.l.a.l.a.l.a.l.a.a.a.a.a.a.a.c.a.#.a.iQt.g.g.h.g.p.g.g.g.f.s.f.f.i.f.i.f.i.g.f.g", +".p.p.mQtQt.#.c.#.r.a.c.#.a.e.b.l.e.e.e.l.j.e.j.e.j.j.e.j.e.j.e.j.l.l.b.e.e.l.e.e.j.e.j.j.j.j.e.j.e.a.#Qt.i.i.q.gQt.s.fQt.i.d.cQt.e.r.l.e.l.b.e.e.e.j.e.j.e.j.e.j.l.j.j.j.e.e.e.e.l.b.l.b.#.c.a.#.l.a.a.a.cQt.g.f.dQtQtQtQt.cQt.cQtQtQt.#Qt.cQt.c.#.a.a.a.a.a.a.a.#.a.a.#.a.a.a.a.e.j.b.e.l.a.a.a.l.q.i.g.m.g.g.i.dQt.#.c.q.cQt.dQtQtQt.iQtQt.iQt.#.#.a.r.a.r.a.r.#.#.a.r.r.a.r.#.a.r.a.#.r.l.a.l.#.l.r.b.l.l.l.l.a.a.a.l.a.l.b.l.l.#.l.a.a.l.c.c.#.#QtQt.f.m.g.x.g.w.i.m.i.f.iQtQt.qQtQtQt.f.i.f", +".g.i.i.iQtQt.#.c.#.cQt.a.a.e.l.e.e.t.e.e.e.j.e.l.j.j.j.j.j.j.j.j.e.e.l.l.e.e.j.e.e.j.e.e.e.j.e.e.l.#.#Qt.x.i.s.f.s.i.g.#.dQt.a.b.a.l.b.a.e.l.l.e.j.j.b.j.j.j.j.j.j.j.j.j.l.e.l.e.e.e.e.a.a.b.c.a.e.b.a.c.c.dQtQtQt.c.c.cQt.dQt.fQt.fQt.d.#Qt.cQtQt.#Qt.#.a.c.a.c.a.a.#.a.a.l.a.b.l.l.e.l.a.a.cQt.a.#Qt.s.g.w.p.m.fQt.i.c.c.#Qt.gQt.iQtQtQtQtQtQt.#.r.#.a.r.a.r.a.#.q.r.c.r.q.r.r.a.r.a.r.a.a.r.a.r.r.a.r.r.l.l.l.#.l.a.a.e.a.l.l.a.l.a.a.l.a.c.a.#.dQt.i.i.f.f.f.s.i.g.f.iQt.fQt.iQt.i.f.iQt.f.s", +".s.i.s.h.sQtQt.#.c.a.r.a.a.e.e.l.e.e.l.e.l.e.j.e.j.j.e.j.e.j.e.j.l.e.e.e.e.l.e.j.l.e.e.j.e.e.j.e.l.a.#.q.g.p.g.i.s.f.iQt.q.dQt.b.#.a.e.l.b.e.e.l.j.j.j.j.e.j.e.j.j.j.j.j.e.e.e.e.l.e.l.b.a.c.b.c.l.l.e.#.a.c.i.d.#.c.cQt.c.i.cQtQtQtQt.iQtQt.i.#.a.#.a.#.a.#.c.q.a.a.a.c.aQt.a.r.e.l.e.a.b.#.c.c.cQt.i.g.g.w.p.h.m.gQtQtQt.cQt.fQtQtQtQtQt.#.c.#.r.r.a.r.a.r.a.r.r.#.r.r.a.r.a.#.r.#.a.a.r.a.r.a.l.r.l.a.l.#.a.l.a.a.b.a.a.l.a.e.l.b.l.a.b.l.#.c.c.cQtQtQt.fQt.f.g.i.i.s.q.iQt.xQtQt.#Qt.q.gQtQt", +".q.i.p.g.g.fQt.#Qt.cQt.a.r.l.e.e.j.e.b.e.j.j.e.e.j.j.j.j.j.j.j.j.e.j.l.j.l.j.e.l.b.l.e.a.a.e.l.a.a.a.q.q.g.h.s.iQtQtQt.c.c.c.c.b.l.b.l.r.l.l.e.e.j.e.j.e.j.j.j.j.j.j.e.j.e.t.b.e.l.b.e.a.a.#.c.a.e.b.b.a.b.c.d.d.a.#.c.cQt.dQt.f.#.q.#.#.c.#.c.#.c.c.#Qt.c.#.c.#.a.c.a.#.#.a.a.c.b.l.#.a.c.c.cQt.#.iQt.f.s.p.p.v.p.g.mQtQt.iQt.f.fQtQtQt.f.#.#.#.a.r.a.r.a.r.a.r.#.#.a.q.r.c.#.#.#.r.r.#.a.r.#.r.#.a.r.a.r.a.l.r.a.l.a.a.l.e.l.e.l.l.a.l.a.a.c.a.#.c.q.dQt.d.i.f.s.i.iQtQtQt.fQt.#.q.#QtQtQtQt.g", +".d.i.h.w.g.iQt.#.r.a.c.a.a.e.b.l.e.l.e.l.e.e.t.e.j.j.e.j.e.j.e.j.l.e.e.e.e.l.b.e.a.e.e.a.a.e.e.l.a.#.i.q.s.g.i.i.gQt.i.cQt.c.aQt.e.a.e.l.e.e.e.e.j.j.j.e.e.e.j.e.j.j.j.j.e.e.l.e.e.l.e.l.b.c.bQt.e.e.e.a.b.c.f.q.#.c.a.c.i.cQt.d.r.#.q.c.r.#.r.aQt.#.c.c.c.#.c.c.#.a.c.#.#.c.a.a.l.e.a.b.aQt.cQtQt.f.xQt.i.w.h.u.u.w.g.g.iQtQt.q.f.fQtQt.#.c.a.r.a.r.a.r.a.r.#.a.q.r.a.r.a.r.q.#.r.a.a.a.r.a.a.r.a.r.l.#.l.r.l.l.a.a.a.l.a.l.b.l.a.e.e.a.a.l.c.c.c.cQt.c.cQt.dQt.i.i.s.f.xQtQt.i.rQt.c.qQt.gQtQt", +".#.i.f.g.h.i.fQt.i.#.#.c.r.a.l.l.j.j.j.j.j.j.e.j.e.e.j.e.j.e.j.e.j.j.j.l.j.e.a.a.a.a.a.c.c.c.c.c.r.#.rQt.q.i.g.f.r.a.a.a.a.b.b.a.l.b.l.#.e.l.e.e.e.e.e.j.j.j.k.j.j.j.j.e.e.e.e.b.l.e.l.b.a.a.a.c.a.aQt.a.c.c.c.d.a.a.aQt.#.c.q.a.#.c.#.#.c.#.#.#.a.a.a.l.a.a.a.a.a.a.l.a.a.a.a.#.l.a.a.#.a.a.c.#Qt.qQt.i.g.g.p.w.u.p.u.h.g.mQt.c.q.#.q.#.c.#.#.c.#.c.#.c.#.c.#.#.a.r.#.a.r.r.a.r.r.r.r.r.r.a.r.a.r.r.r.r.a.a.l.a.b.a.l.l.e.l.l.e.a.l.a.e.l.a.a.lQt.a.c.#.cQt.#.d.s.i.i.iQtQt.gQtQt.qQt.fQtQtQtQt", +"QtQt.i.x.g.g.g.fQtQt.#.#.#.l.e.l.b.j.e.j.e.j.j.j.e.j.e.j.e.j.e.j.j.j.e.e.e.e.e.e.l.a.l.c.r.c.#.c.d.#.#.#QtQtQtQt.a.#.b.a.a.b.a.b.l.l.l.e.e.e.e.e.j.k.j.k.j.j.j.e.k.j.j.e.e.e.e.e.e.b.e.l.b.a.r.a.b.c.b.c.c.c.d.i.c.q.c.r.c.r.c.c.#Qt.#.c.#.#.c.#.a.#.a.#.l.r.b.a.l.a.#.a.a.l.a.a.l.b.l.a.a.a.#.#Qt.iQt.s.g.m.p.h.h.h.p.h.gQtQt.f.#Qt.cQt.#.q.c.#.c.#.a.#.a.#.a.#.c.r.#.r.#.a.#.r.r.#.a.r.#.a.r.#.a.#.#.a.l.a.a.a.a.l.a.e.a.l.b.l.a.a.e.l.e.l.a.a.a.a.a.c.cQtQtQt.i.i.s.f.sQtQtQtQtQtQt.iQtQtQt.f", +"Qt.f.i.g.g.g.g.iQtQt.q.#.a.a.a.l.e.e.l.e.e.e.e.l.j.e.j.e.j.e.j.j.e.j.l.j.l.e.b.e.a.a.c.c.c.c.cQt.r.#.#.qQtQt.#.d.a.a.a.b.a.e.r.l.#.l.e.l.e.e.e.e.j.j.j.j.k.j.k.j.j.e.e.e.e.b.a.a.a.a.l.a.a.c.cQt.a.#.#.cQt.#QtQt.#.c.c.c.q.c.#Qt.#.#.c.#Qt.#.c.q.a.a.a.a.a.a.a.a.a.a.a.a.#.a.a.a.#.r.a.a.cQt.#QtQtQt.qQt.f.g.g.m.g.s.g.m.iQtQt.i.#Qt.#.q.c.#.#.c.r.a.a.a.a.a.a.a.r.r.c.r.#.r.a.#.r.r.r.#.r.a.a.r.r.a.r.r.a.a.l.a.l.e.l.l.e.l.l.e.a.a.l.a.l.e.a.l.a.a.#.c.r.cQt.c.i.m.i.iQtQt.gQtQt.i.fQtQt.i.g.q", +".q.i.f.g.m.x.g.g.xQtQt.#.#.a.a.l.e.l.e.e.j.l.j.e.e.j.e.l.j.e.j.j.j.j.j.e.e.e.l.e.c.r.c.#.c.#QtQt.r.#.#.#.c.#.c.c.l.a.l.e.e.a.e.b.l.l.e.b.l.e.e.e.e.k.j.j.e.j.j.j.e.e.e.l.e.a.b.c.a.a.a.c.c.#.cQt.#.#QtQtQt.iQtQt.f.iQtQtQtQtQtQtQtQtQtQtQt.d.#Qt.a.a.r.a.a.r.a.r.#.c.a.a.a.c.a.c.r.a.#.#.a.#Qt.#.#QtQt.gQt.i.i.g.s.g.p.p.gQtQt.#.#.#.d.#.#.c.#.c.a.a.l.a.l.a.l.a.q.a.r.a.r.#.r.#.r.r.r.a.r.a.r.a.a.#.r.#.a.a.a.a.e.a.l.b.l.a.e.a.l.a.a.l.b.l.l.l.a.a.a.c.c.c.#Qt.i.i.g.i.gQt.q.iQtQtQtQtQtQt.f.f", +".i.i.i.i.g.g.g.hQtQtQtQt.c.#.a.a.l.a.l.a.e.e.e.l.e.e.e.j.e.j.e.e.j.e.e.l.e.e.e.l.c.c.#.c.#QtQtQt.a.#.#.#.c.c.c.#.l.l.e.e.e.e.e.e.#.l.e.l.e.e.e.e.k.j.j.j.k.j.j.k.l.t.l.b.l.a.a.#.c.c.#Qt.#.#.dQtQtQtQt.iQt.f.fQtQtQtQtQt.iQt.iQtQt.iQt.iQt.#Qt.#.#.#.c.#.q.c.#.#.c.#.c.c.#Qt.c.#.#.r.a.#.i.#.iQt.i.qQt.qQt.s.f.i.s.i.m.v.h.gQt.#.c.#.q.#.d.#.#.c.a.#.a.a.a.a.a.a.a.r.#.r.a.r.a.r.r.r.q.r.r.#.r.a.#.r.a.r.a.a.l.a.e.l.a.l.a.e.l.l.a.l.l.a.l.e.a.e.a.l.c.#.c.i.d.i.i.i.i.iQtQt.fQt.i.xQt.qQt.f.i.i", +".h.g.i.g.s.h.u.pQt.q.iQt.#.c.a.a.a.b.a.b.a.l.b.e.e.j.l.e.l.e.e.e.j.j.e.j.e.l.e.b.r.#.#QtQt.#QtQt.#.#.#.c.a.a.a.b.l.b.l.e.t.e.e.e.e.l.l.e.e.e.e.e.e.k.j.j.j.j.j.j.e.a.e.l.a.l.c.c.c.#.cQtQt.i.fQtQt.iQtQt.f.i.iQt.iQtQtQtQt.iQtQtQt.qQt.qQt.xQt.i.#.q.#.#.#.#.q.#.#.c.c.q.c.#.c.c.r.#.q.#.#QtQtQt.qQtQt.i.iQt.i.iQtQt.g.v.o.g.f.q.c.#.d.#.q.#Qt.#.a.a.a.a.l.l.l.l.r.r.#.a.#.#.#.r.#.r.r.a.r.a.a.r.r.#.r.a.a.a.a.a.e.a.l.a.a.l.a.e.l.e.a.l.a.l.e.l.a.a.c.c.#.c.#Qt.i.g.s.i.g.q.iQt.iQtQtQt.s.i.m.i", +".h.g.i.g.h.h.p.p.i.fQtQtQt.c.a.a.a.e.a.e.a.e.e.l.e.e.e.j.e.j.l.j.e.j.e.l.e.a.a.a.#Qt.qQtQtQtQtQt.#.c.#.c.l.a.e.e.l.j.j.j.j.j.e.e.l.b.e.l.e.e.e.e.j.j.j.j.k.j.j.k.l.l.l.a.a.a.#.r.#.c.#QtQtQtQt.fQt.q.i.i.s.g.g.gQtQtQtQtQtQtQt.s.q.x.q.q.s.q.i.qQtQt.i.#Qt.#Qt.#.d.qQt.cQt.#Qt.#Qt.#.#.#.i.#QtQt.i.iQt.qQt.i.qQt.g.i.m.p.v.p.h.i.c.#.#.iQt.#.#.c.a.a.a.a.b.a.b.a.c.r.#.r.r.r.a.r.r.r.r.#.a.r.a.a.r.a.#.r.a.#.a.a.l.l.a.a.l.a.e.l.b.l.e.a.l.a.e.l.a.a.a.#Qt.cQtQt.i.i.i.iQtQt.f.q.i.i.i.i.i.f.g.g", +".g.h.i.x.i.g.p.p.s.iQtQt.c.q.a.a.r.a.a.a.b.a.b.e.l.j.j.e.j.l.e.e.j.j.e.e.e.l.b.b.#.#Qt.#QtQtQtQt.cQt.a.a.a.e.j.e.j.j.e.j.e.k.j.e.l.l.l.j.e.e.e.e.e.k.j.k.e.j.j.j.l.l.a.l.r.c.a.c.cQt.c.cQtQtQt.f.qQtQt.i.i.g.g.gQtQtQt.qQt.sQtQtQtQtQtQtQtQtQtQt.i.#QtQtQt.#Qt.#Qt.#.d.#QtQt.d.#.#.#.q.#Qt.iQtQt.q.i.q.iQt.x.f.xQt.f.g.w.p.u.g.i.#Qt.#QtQt.#Qt.#.a.#.b.a.#.b.a.a.r.a.r.a.r.c.r.#.r.r.#.a.r.#.a.r.#.r.#.r.a.a.a.l.b.a.l.a.#.a.a.l.l.e.l.a.l.a.l.e.a.#.#.c.c.c.#Qt.i.i.sQtQtQt.iQt.qQt.q.i.i.i.g.g", +"QtQtQtQtQtQt.d.fQtQt.i.iQtQtQtQt.#.c.l.a.l.a.b.e.e.e.e.e.e.e.e.e.t.j.l.l.a.c.cQt.q.q.f.qQt.iQtQt.a.b.a.e.e.e.l.j.j.j.j.j.k.e.e.e.l.l.b.l.l.j.e.e.e.e.b.e.e.e.e.e.e.e.e.l.b.e.a.a.a.b.a.c.c.c.c.c.#.#.gQt.fQt.fQtQtQtQt.iQtQtQtQtQt.iQtQt.iQtQt.i.d.#.q.d.#QtQtQt.q.q.q.q.q.q.q.q.iQtQtQtQtQtQt.iQt.#.dQtQtQt.i.g.i.xQt.s.g.v.p.h.u.gQt.x.#.a.a.#.a.a.a.a.b.a.a.r.a.r.#.a.a.#.r.a.r.#.r.r.a.r.r.a.r.r.a.r.a.r.a.a.r.a.#.a.l.l.l.e.e.l.e.e.e.e.e.l.a.a.a.r.#.#.d.#.f.q.fQt.q.f.fQt.i.qQtQtQtQtQt.c", +"Qt.#QtQtQt.gQt.d.#.iQtQtQtQtQtQt.c.#.a.a.a.a.a.e.e.e.e.e.e.e.e.e.e.l.e.l.a.c.#.d.q.q.i.qQtQtQtQt.b.c.a.b.l.e.j.e.j.k.j.k.j.e.e.e.l.l.l.l.e.e.e.e.b.e.e.e.e.b.e.b.j.j.e.e.l.e.a.r.a.c.b.c.c.c.c.c.c.cQtQtQtQtQt.fQtQtQtQtQtQtQt.i.fQt.fQtQt.iQtQt.#.d.#Qt.qQt.#.i.q.x.q.qQt.dQt.dQtQtQt.#Qt.qQtQt.#.iQt.q.iQt.iQt.iQt.g.i.w.A.z.u.p.g.s.qQt.q.a.c.a.a.b.a.a.a.a.a.a.a.a.r.a.r.a.#.a.r.a.a.r.a.r.a.r.c.rQt.r.a.a.l.a.l.r.l.l.l.l.l.e.e.e.l.b.e.l.b.a.r.a.a.c.#.c.#Qt.sQtQt.i.f.f.iQt.#.i.qQtQt.c.#", +".#Qt.#QtQt.c.dQt.r.#.#Qt.qQtQtQt.#.c.#.c.a.a.b.a.e.e.e.e.e.e.l.e.l.#.l.a.c.cQtQt.i.q.iQtQt.q.fQt.a.b.a.e.e.e.j.e.j.j.k.e.e.e.e.b.l.b.l.l.e.l.e.e.e.e.e.e.e.e.e.e.j.e.j.j.e.e.e.e.e.e.a.b.c.a.r.c.#.#QtQtQtQtQtQt.#.c.#.c.c.#.c.#.#.q.#.qQt.#Qt.q.#.#.#.r.aQt.#Qt.#QtQtQt.q.iQtQt.q.d.q.d.#.d.d.q.r.r.r.q.#QtQtQt.s.i.i.m.h.A.z.y.g.p.p.qQtQt.#.a.#.a.a.#.a.a.a.a.a.r.a.a.r.a.r.a.r.#.a.r.a.r.a.r.a.r.r.r.a.r.a.r.a.r.a.a.l.l.l.l.t.l.b.l.l.l.l.l.a.#.r.a.r.c.#.d.q.iQt.qQt.iQt.f.x.qQtQt.#.#.c.#", +".c.#.#Qt.c.#.c.c.#.c.iQtQt.iQtQtQtQt.#.c.#.c.c.a.c.a.c.a.c.a.b.a.a.r.c.#.cQtQt.i.q.qQt.iQtQt.fQt.c.c.a.b.e.e.e.e.j.k.j.e.e.e.b.l.l.l.l.l.b.e.e.e.e.e.e.e.j.e.e.e.j.j.j.e.j.e.b.e.a.e.b.a.b.c.c.c.d.c.#.f.#.c.c.#.c.c.c.c.#.c.c.c.a.c.c.c.a.c.#.c.r.a.r.a.a.#.#.#.#Qt.#.#.#.#.#.#.r.d.#.r.r.#.r.#.r.q.r.#.#.d.i.d.i.i.m.h.m.u.A.C.g.p.u.i.i.q.i.c.a.a.a.a.a.a.#.a.l.a.a.r.#.a.a.r.#.a.r.a.r.a.r.a.q.r.c.r.#.a.a.a.l.r.b.l.l.l.l.l.e.l.a.l.a.a.l.l.r.l.r.#.c.#.c.#.iQt.i.s.i.f.s.f.i.xQt.#Qt.cQt.c", +".#.#Qt.cQt.c.c.c.#.c.#.c.#QtQtQtQtQtQtQt.q.c.#.a.c.c.c.c.c.c.c.c.#.c.#.cQtQtQtQt.i.q.s.qQt.q.fQt.b.a.b.e.l.e.j.e.j.j.e.e.e.e.a.b.l.l.l.l.e.l.e.e.j.k.e.k.e.k.j.j.j.j.e.j.j.e.j.e.e.e.l.b.a.a.c.a.c.#QtQt.#.d.#.c.a.a.a.a.a.a.a.a.#.a.#.a.a.#.a.a.b.l.a.#.a.a.#.a.#.#.#.c.#.#.#.#.q.r.r.r.r.r.#.r.r.r.r.q.r.#.#.q.i.i.i.m.g.u.A.C.h.h.h.u.iQtQtQt.#.c.c.c.c.c.c.#.a.r.#.a.r.a.r.a.r.#.a.r.a.r.a.r.a.r.a.r.a.r.a.l.r.a.r.l.l.l.e.l.a.a.a.a.a.l.a.a.l.l.a.r.c.#QtQt.f.x.i.f.i.g.f.i.i.i.i.i.#.c.#.#", +".a.r.a.#.q.c.#.c.a.a.c.c.c.c.c.d.i.s.qQtQtQt.c.c.#.c.c.#.c.c.#.cQt.#QtQtQt.iQtQtQt.qQt.i.f.i.fQt.b.a.c.e.b.j.e.l.e.e.l.e.a.a.c.a.l.l.b.l.e.e.e.e.j.j.j.j.k.j.j.j.j.j.j.j.j.j.e.j.t.e.e.e.a.b.a.b.#.dQtQt.c.r.a.r.a.a.a.l.l.a.a.a.l.l.l.b.l.l.l.l.l.b.l.e.a.a.a.r.#.a.c.#.c.aQt.c.r.r.r.r.#.r.#.r.r.#.r.a.#.q.#.#.sQt.s.f.s.p.z.G.h.h.h.h.m.iQt.q.c.q.#.#.q.#.#.#.a.r.a.r.l.a.a.r.a.r.r.a.r.a.r.a.r.#.#.c.r.a.r.a.l.l.l.l.l.l.l.l.l.a.r.#.a.a.a.a.l.l.l.a.r.cQtQt.q.i.f.s.i.i.f.m.g.m.iQtQt.#.#.a", +".r.a.r.c.#.c.a.c.a.l.a.#.a.#.c.#QtQt.iQtQtQtQtQt.#Qt.#Qt.#QtQt.#QtQtQtQtQtQtQtQt.q.i.q.fQt.qQtQt.a.b.a.e.l.e.e.e.l.l.e.l.a.a.a.#.l.l.l.l.e.l.e.e.k.k.j.k.j.j.k.j.k.0.j.j.e.j.j.e.e.e.t.e.a.b.a.cQt.#Qt.#.#.a.a.b.l.e.l.e.e.l.b.l.e.l.l.l.e.l.e.e.j.e.e.e.e.e.b.b.a.a.a.a.a.#.a.a.#.a.a.a.a.a.a.#.a.a.#.c.c.c.c.c.q.#.i.i.i.m.o.n.o.p.h.p.h.i.i.fQtQtQtQt.dQt.c.c.a.r.a.a.r.#.r.a.#.#.a.r.a.r.a.r.a.r.r.r.a.#.a.l.l.l.l.l.l.l.l.l.a.a.l.a.l.r.l.l.l.l.a.r.c.#.#.i.f.i.s.i.f.g.i.m.p.m.i.iQt.c.#.a", +".r.a.r.a.a.c.#.a.a.a.l.c.c.a.c.c.f.i.f.iQtQt.#QtQtQtQtQtQtQtQtQt.iQtQtQtQtQtQtQt.q.q.q.iQtQtQtQt.c.b.c.a.e.j.e.l.b.l.l.a.a.a.a.c.l.l.l.l.e.j.e.e.j.j.k.j.j.k.k.j.0.k.j.j.j.j.j.j.j.e.e.e.a.a.b.a.c.fQt.c.#.r.l.l.e.l.b.e.e.l.e.e.l.e.e.e.e.e.l.b.j.j.j.j.e.r.e.e.a.a.a.b.a.a.a.a.a.b.a.#.a.a.a.a.r.e.b.b.cQt.cQt.d.#.#.q.f.i.u.n.o.n.h.h.h.m.gQt.cQtQtQtQt.d.#.#.#.a.r.#.a.a.r.a.r.r.a.r.a.r.a.r.a.r.c.r.a.r.r.a.l.l.l.l.e.l.l.a.l.r.a.r.a.l.a.l.l.l.r.a.a.c.cQt.i.i.f.i.s.g.i.g.u.h.gQt.#.#.r.a"}; diff --git a/tests/auto/gui/image/qimagewriter/images/ship63.pbm b/tests/auto/gui/image/qimagewriter/images/ship63.pbm Binary files differnew file mode 100644 index 0000000000..4da971a2d7 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/ship63.pbm diff --git a/tests/auto/gui/image/qimagewriter/images/teapot.ppm b/tests/auto/gui/image/qimagewriter/images/teapot.ppm new file mode 100644 index 0000000000..b8ab85f3a5 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/teapot.ppm @@ -0,0 +1,31 @@ +P6 +256 256 +255 +\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À[7 eOLjQLmSMoTMnSMlRMhPL_9 \À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀnSMtVMzYN~[N~[N\N\O€\O€]O€]O€]O€]O€\O€\O}[NyYNtVM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀG-wXN}[N€]O„^O†_O†`O‡`Oˆ`Oˆ`OˆaO‰aO‰aO‰aO‰aO‰aO‰aOˆaOˆ`O†_Oƒ^O\N\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀaMLyYN…_O‰aP‹bPcPŽcPŽdPŽdPdPdPdPdPdPdPdPeP‘eP’eP’eP‘ePdPcP…_OpUM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀwXN…_OdP“fP•gQ–hQ˜hQ˜iQ™iQ™iQšiQšiQšjQ›jQ›jQœjQœjQœjQœjQœjQ›jQœjQ™iQ“fP‡`O\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJiQL‹bP—hQkQ¡mR¤nR¥oR¥oR¥oR¥oR¥oR¥oR¦oR¦oR¦pR¨pS©qSªqS«rS¬rS«rS©qS¤oRœjQ€]O\KK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀfOLrUMcPŸlR©qS¯tS²uTµwT·xT¸xT¹yTºyT»zT»zU¼zU¼zU¼zU»zUºyT¸xT¶wT¯tS¡mR‰aOhPL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\Àa0 cNLqUM€\O”fQ¦pS²wVºzV¿|VÂ}VÄVÆVÇ€VÉ‚WÌ…[Õeæ w÷³‹êª…Ĉg§qT“fQ{ZNYIK9\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀO1{G#‘JkRMqUMtVN–iS¨v\·€d¹bµzZ±vU°uT®sSªqS¤nRœjQ’eP„^OrUMHh>!T4\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀG-V5wE"~I#†M%U+¥e7²l:°g2®b*a(`(©^(¥])¡^-›]1ŠS,qC$`9 R3G-\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À@)J/i>!pA"tD"wF$yH&xH&tE$wE#yG%}M+ƒT4S5mE*Z7!K/B*;'\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À‰aO¦oR½{UÇ€VÏ…X<(F-a: e<!h>!j@#k@$h>"d<!c=$hD-fF2[<)K0@);'5$Ë‚VÇ€V¿|U_LKYIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À…_O·xTÉ‚Wó«€ûµ‹Ö’k¼|X×>µf-¨^(¡Z'šW&–T&œN>)F-J/b; g>#nD(jB&c<!b=%jH2_A/I0!<(8&5$”J¥Y’S%8&;'?)E,<:HA=HE?IJAISFJYIKXIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À£nRÁ}UܘqÊŠe±vU²e,™V&¥V†C
€@|>y<u:r9o7l6 +j5 +h4 +g3 +5$D,K/b; h>"wM1tK.e="a<#cA,U8&E-<(9&.!a0 b1 c1 + ++3#@)46G<:HMCIXHK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀU*´vT¿~X¸{YÃk+›W&‰N$|>u:p8k5 +f3 +a0 _/ ]. [- I¡\*ª_(‘LkRMmSMmSMnSMnSMD,R3W5mA"|O0|P1j?"c<!a=%Y7"N1F,;'NCJNCJNDJODJODJODJh>!a: X/K% +g3 +a0 Z- \/T*Q(ŠHµm8kRMmSMnTMoTMpTMpUM15G15G05G04G04GpUMpTM5^9 d<!yF#O+€N,rC#qB"pB#k?"a: Z7 6ODJPDJPEJQEJQEJREJREJREJRFJSFJSFJSFJSFJe<!X/ +^/ V+Q(L&I$r9 TlRMnSM46G47G47G46G46G46G46G46G36G36G25G25G15G04G/4F.3F + +X&pUMuWMwXNxXN<:H<:H<:H<:H<;H<;H<;H<;H=;H=;H=;H=;H>;H>;H?<H@<HA=HC>HG@ILBIREJ[JKcNLjQL§pR±uTºzUÃ~VÈWË‚XÖŽcäsÒŽe¼{V²vT¨pSžkR•gQŒbP†_O‚^O]O€\O€\O€\O€\O€]O]O]O]O]O]O]O]O]O]O]O€\O€\O~\N}[N|ZNxXN•T%H$ +›W&rVMvWNyYNzYN|ZN}[N}[N><H?<H?<H?<H?<H?<H@<H@<H@<HA=HA=HB=HC>HE?IG@IIAIKBIODJSFJWHK—hQŸlR§pR°b(¾i*Én+Ù|7Û|6Ïr,Íq+Êp-Ãl+»g)±b(®sS§pS lRšiQ•gQePcPŠaPˆaO‡`O‡`O†_O†_O…_O…_O…_O…_O…_O…_O…_O„_O„^O„^Oƒ^Oƒ^O‚]O]O€\O~[N{ZN•T% + + +@%<-$G?@…pfdNLuWM\NdNL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀTFJvWN‰aP./01„E}[N]O…_Oˆ`O‰aP‹bPŒbPcPcPŽcPdPdPdPeP‘eP’eP’eP“fP“fQ”fQ•gQ•gQ–gQ–hQ—hQ˜hQ™iQšiQ›jQœjQkQkRžlRŸlRžY&¤\'¨^'µ^½bÀcÃeÇi ÄgÀc½b¼a¹`µ^´]¯X¢[' Z'žY&¢mR¡mR¡mR lRŸlRŸlRžkRkQœkQœjQ›jQšjQšiQ™iQ™iQ˜iQ˜hQ—hQ—hQ—hQ–gQ–gQ•gQ•gQ•gQ”fQ”fQ“fQ“fP’eP‘ePdPcP‰aP—O + B\À\À\À\À\À\À\À\À\À\À%7!!C*F#P){dYœze»p€\OgPL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ`LKvWNŠaPm6 + +$5 ¬`(¶e)£nRœjQƒ^OJAI\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀXIK^KKdNLhPLuWM‚]OŒbP”fQeP
m6 +†`OŽcP“fQ—hQ˜hQ™iQšiQšjQ›jQ›jQ›jQœjQœjQœjQœkQkQkQkRžkRžkRžkRžlRŸlRŸlRŸlR lR lR lR¡mR¡mR¡mR¡mRºg)³c(²c(±b(V¿cÂeÅi!Åi!Àd¼bº`¹`·_·_¶^¢Q§]'ª_(`(¹f)£nR£nR£nR£nR£nR£nR£nR¢nR¢nR¢nR¢nR¢nR¢nR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢mR¢nR¢mR¢mR£nR¢mR¢mR¡mR mRkR—hQˆGa0 ŠbP mRœjQ“fQ‰aP}[NrUMmSM…L$\À\À\À\À\À\À\À\À B B
#C, 8&H.Z7 §pR›jQ{ZN\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀQEJ[JK`LKdNLhQLqUM{ZN…_OŽcP–gQ—hQ +‹bP‘eP–hQšiQ›jQœjQkQkQkRžkRžkRžlRžlRŸlRŸlRŸlRŸlRŸlR lR lR lR mR¡mR¡mR¡mR¡mR¡mR¢mR¢mR¢mR¢nR£nRÀj*ºg)·e)¶d)Âd°XÅgÅhÂe¿c½b½b¾bªU`(®a(¯a(³c(¾i*¤oR¤oR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤nR¤oR¤oR¥oR¥oR¥oR¥oR¥oR¥oR¦oR¦oR¥oR¥oR¤nR¡mR›jQŽQ%Z- œjQ£nRŸlR—hQŽdP…_OuWMpTMnSMkRLa: \À\À\À\À\À\À\À B B&D2
@*S6#G@IPDJ˜hQmSM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀVGJ]KKbMLeOLiQLlRMvWN\OˆaO‘eP—hQœjQ•gQ +!C+E'0F.4F7%8%U/lG.SFJZIK]KKZIKB=H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀREJZJK`LKdNLgPLjQLlRMnSMpTMqUMtWMxXN{ZN~[N]O„^O†`O‰aO‹bPdP•gQ™iQœkQ lR¤nR§pSªrSsS¯tT²uT´vT¶wT·xT¹yT¹yTºyTºyT¹yT¶xT´vT¬rS¢nR—hQ¿|U¿|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ|UÀ}UÀ}UÁ}UÁ}UÁ}UÁ}UÂ}UÂ~UÃ~UÃ~VÃ~VÄVÅ€WÆX®a(ŸlRªrS´vT¸yT¼zU¾|UÁ~VÃXÆ‚[Ɇ_΋dÓ‘jÔ“mÔ“nБlÊŒhĆd½_¶{[°vWªsU¦pS¢nRžkRšiQ˜hQ•gQ“fQ‘ePdPŒbP‰aO†_Oƒ^O€\O|ZNxXNsVMpTMnTMmSMjQL€C B)D&/F-3F47G6%>"Y7 kA$YIK]KK^KKSFJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀVGJ\KKbMLeOLhPLkRLmSMnTMpTMrUMuWNyYN|ZN\N‚]O„_O‡`OŠaPŒbPŽcPeP“fP—hQ›jQžlR¢nR¥oS©qT¬sT¯uU²vU´wV¶xV¸yV¹yUºzU»zU¼{U½{U¾{U¾|U¿|U¿|U¿|U¿|U¾{U½{U¼{U¼zU»zTºyT¹yT¸xTµwT³vT´vT´vT´vT´wT´wTµwT·xT¹yTºzT¼zU½{U¾{U¿|UÀ|UÂ}UÄVÅ€WÇ‚YÉ„\͈_ÑŒdÙ”láuç£|쩂ſtî‡ëª…æ¦ÞŸ{Õ—sËŽl†d¹^³yZuW¨qU¤oSŸlRžkRœjQšiQ˜hQ–gQ”fQ‘ePdPcPŠaP‡`O„^O]O}[NyYNuWMpTMoTMmSMkRLgPL&D#.E,3F46G;'<(D"iB(VGJ]KK`LK[JKB>H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJYIK^LKcNLfOLiQLkRMmSMoTMqUMsVMvXNzYN}[N€\O‚^O…_Oˆ`OŠaPŒcPdP‘eP“fQ•gQ—hQ™iQkR mS¤oT¨rU¬tW°wY´zZ¸}\»]¾€^À^Á‚^‚^Â\Á€ZÁYÁXÁ~WÁ~WÂ~VÂ~VÂ~VÃ~VÃ~UÃ~UÄ~UÄ~UÄUÄUÅVÅVÅVÅVÆVÆ€VÆ€VÇ€WÇWÈ‚XɃZË…[͇^ЊaÓdØ’iÜ—nâtè£zî©ó¯‡ø´û¸‘üº“û¹“÷¶ñ±Œé©…à¡~Ö˜vËmÇf»€`´z[®vX©rU¥pT£oS¢nS lRžkRœkRšjQ˜iQ–hQ”fQ’ePdPcP‹bPˆ`O…_O‚]O~[NzYNvWNpTMoTMnSMkRMhQLo7,2F36G99HC+@ ]8 nA"\JK`ML_LKSFJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ[JK`LKdNLgPLjQLlRMnSMpTMqUMtVMwXNzZN}[N€]Oƒ^O†_OˆaO‹bPcPdP‘eP“fQ•gQ—hQ™iQ›jRžlR mS£oU§rW¬vZ²{]¹€a¿…fÅŠjËnГqÓ•sÕ–sÕ–rÕ–qÕ”oÓ’mÑjÏgÍŠcˈaɆ^È„\Ç‚[ÆYÅ€XÅ€WÅWÅWÅVÅVÅWÅ€WÆ€WÇXÈ‚YɃ[Ê…\͇_ÏŠaÒeÕ‘hÙ•mÝ™qávä¡zç¤}ê§€ë©ƒëª„é¨ƒå¥€ß |Ù›wÓ•rÌmƉh¿„c¸~^²yZ®vX¬tWªsV¨qU¦pT¤oS¢nS mRžlRœkR›jQ™iQ—hQ•gQ“fPePŽcP‹bPˆaO…_O‚^O\N{ZNwXNsVMoTMnSMlRMiQL~I#26G99G?<HA*E$ i@$ZIKaMLbML[JK;:H\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀWHJ]KKbMLeOLhPLjRLlSMnTMpTMrUMuWMxXN{ZN~\N]O„^O†`O‰aO‹bPŽcPdP’eP”fQ–gQ˜hQšiQœkRžlS mT£oU¦rWªuZ¯y]´~aºƒfŠlË’sÔšzÜ¡€ã§†è«‰ë®‹í¯Œí®‹ë¬ˆè¨„ã£~ßžyÚ™tÖ•oÒjÎŒfˈbÈ…_ƃ\ÅZÄ€YÃXÂWÂ~WÂ~WÂ~WÃXÀXÄ€YÅZƃ\Ç…^Ɇ`ˈbÌŠdÍ‹fÎgÎŽiÎŽjÎŽjÍŽjËŒiljgÆd¿ƒaº^¸}]¶|\´{[²yZ°xY®vX¬tWªsV¨qU¦pT¤oS¢nS mRžlRkR›jQ™iQ—hQ•gQ“fP‘ePŽdPŒbP‰aO†_Oƒ^O€\O|ZNxXNtVMpTMnSMmSMjQLgPL99G?<HG-E&b;!YIK`MLdOM`LKNCJ\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀŸlRºyTÄ~UÊ‚XʃYÄXº{WtUšW'¢[(—hQ lRcP€\OhQL\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀNCJYIK^LKcNLfOLiQLkRLmSMoTMqUMrVMvWNyYN|ZN\N‚]O„_O‡`O‰aPŒbPŽcPdP’fP”gQ–hQ˜iQšjRœkRžlS¡nT¤pU§sW«vZ°z]µb»„gŠlÉ‘sИyØžÞ¤…ã©Šèì±ï³‘ﳑëŠç©…⣀ݞzؘtÒ“nÎiɉdÆ…`Â]Á€[¿~Y¾}X½|W½|V¼{V¼{V¼{V¼{V¼{V¼|W¼|W½}X½}Y½~Z½~Z¼~Z»}[º}[º}[º~\º~\º~]º~]¹~]¸~]·}]¶|\´z[²yZ°wY®vX¬tWªsV¨rU¦pT¤oS¢nS mRŸlRkR›jQšiQ˜hQ–gQ“fQ‘ePdPŒcPŠaP‡`O„^O]O}[NyYNuWNpTMnTMmSMkRLhPL|H$D>IQ2P+XHK_LLfQOcNLXIK\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À©qSºyTÃ~VΈ`遲ޜv¾€]ªqS–LŽG|>g3 +S)?*%.—hQ—hQ‘eP‡`OuWM\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\ÀSFJ[JK`LKdNLgPLjQLlRMnSMoTMqUMsVMwXNzYN}[N€\O‚^O…_O‡`OŠaPŒbPŽdP‘eP“fP•gQ—hQ˜iQšjRœkRŸlS¡nT¤pV§sX«vZ°z^¶b¼…gËmÊ’sјzØŸ€Þ¤…ã©Šèê¯ë°ê¯Žè¬‹å¨‡à¤‚Ûž|Ö™wÑ“qÌŽlljgÃ…bÀ‚_½\»}Zº{X¹zW¸yV·yU·xU·xU·xT·xT·xU·xU·xU·yV·yV·yW¸zW¸{X¹{Y¹|Zº}[º}[º}\º~\¹~]¹~]¸}]·|\µ{\´z[²yZ°wY®vX¬tWªsV¨rU¦pT¤oS¢nS¡mRŸlRkRœjQšiQ˜hQ–gQ”fQ’ePdPcPŠbP‡`O…_O‚]O~[NzZNvWNrUMoTMmSMlRMiQLeOLJAIJ(h>!]KKfQOgQN_LKD>I\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À\À™iQ°tS¸yT¼{UÂYÎŒeïˆô´Õ—u¶|\ Z'™LˆD
|> + +
&3#.$-% .% .& /&!,#,#@70A71XNHXNHWNHWNHZRLYQLYQLXQLWQLWPLUOLSNLQMKOLJMJJ0//.-.,,-&(+"(!' +%' %$#" ! !$
diff --git a/tests/auto/gui/image/qimagewriter/images/teapot.tiff b/tests/auto/gui/image/qimagewriter/images/teapot.tiff Binary files differnew file mode 100644 index 0000000000..20845c6e32 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/teapot.tiff diff --git a/tests/auto/gui/image/qimagewriter/images/trolltech.gif b/tests/auto/gui/image/qimagewriter/images/trolltech.gif Binary files differnew file mode 100644 index 0000000000..f674369efc --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/images/trolltech.gif diff --git a/tests/auto/gui/image/qimagewriter/qimagewriter.pro b/tests/auto/gui/image/qimagewriter/qimagewriter.pro new file mode 100644 index 0000000000..0fc40d0f0a --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/qimagewriter.pro @@ -0,0 +1,25 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qimagewriter.cpp +MOC_DIR=tmp +!contains(QT_CONFIG, no-tiff):DEFINES += QTEST_HAVE_TIFF +win32-msvc:QMAKE_CXXFLAGS -= -Zm200 +win32-msvc:QMAKE_CXXFLAGS += -Zm800 + +wince*: { + addFiles.files = images\\*.* + addFiles.path = images + DEPLOYMENT += addFiles + DEFINES += SRCDIR=\\\".\\\" +} else:symbian { + addFiles.files = images\\*.* + addFiles.path = images + DEPLOYMENT += addFiles + qt_not_deployed { + imagePlugins.files = qjpeg.dll qtiff.dll + imagePlugins.path = imageformats + DEPLOYMENT += imagePlugins + } +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} diff --git a/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp b/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp new file mode 100644 index 0000000000..b119763723 --- /dev/null +++ b/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp @@ -0,0 +1,628 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <QDebug> +#include <QFile> +#include <QImage> +#include <QImageReader> +#include <QImageWriter> +#include <QLabel> +#include <QPainter> +#include <QSet> + +#if defined(Q_OS_SYMBIAN) +# define SRCDIR "" +#endif +typedef QMap<QString, QString> QStringMap; +typedef QList<int> QIntList; +Q_DECLARE_METATYPE(QImage) +Q_DECLARE_METATYPE(QStringMap) +Q_DECLARE_METATYPE(QIntList) +Q_DECLARE_METATYPE(QImageWriter::ImageWriterError) +Q_DECLARE_METATYPE(QIODevice *) +Q_DECLARE_METATYPE(QImage::Format) + +//TESTED_FILES= + +class tst_QImageWriter : public QObject +{ + Q_OBJECT + +public: + tst_QImageWriter(); + virtual ~tst_QImageWriter(); + +public slots: + void init(); + void cleanup(); + +private slots: + void getSetCheck(); + void writeImage_data(); + void writeImage(); + void writeImage2_data(); + void writeImage2(); + void supportedFormats(); + + void readWriteNonDestructive_data(); + void readWriteNonDestructive(); + +#if defined QTEST_HAVE_TIFF + void largeTiff(); +#endif + + void writeToInvalidDevice(); + + void supportsOption_data(); + void supportsOption(); + + void saveWithNoFormat_data(); + void saveWithNoFormat(); + + void resolution_data(); + void resolution(); + + void saveToTemporaryFile(); +}; +#ifdef Q_OS_SYMBIAN +static const QLatin1String prefix(SRCDIR "images/"); +#else +static const QLatin1String prefix(SRCDIR "/images/"); +#endif +static void initializePadding(QImage *image) +{ + int effectiveBytesPerLine = (image->width() * image->depth() + 7) / 8; + int paddingBytes = image->bytesPerLine() - effectiveBytesPerLine; + if (paddingBytes == 0) + return; + for (int y = 0; y < image->height(); ++y) { + qMemSet(image->scanLine(y) + effectiveBytesPerLine, 0, paddingBytes); + } +} + +// Testing get/set functions +void tst_QImageWriter::getSetCheck() +{ + QImageWriter obj1; + // QIODevice * QImageWriter::device() + // void QImageWriter::setDevice(QIODevice *) + QFile *var1 = new QFile; + obj1.setDevice(var1); + + QCOMPARE((QIODevice *) var1, obj1.device()); + // The class should possibly handle a 0-pointer as a device, since + // there is a default contructor, so it's "handling" a 0 device by default. + // For example: QMovie::setDevice(0) works just fine + obj1.setDevice((QIODevice *)0); + QCOMPARE((QIODevice *) 0, obj1.device()); + delete var1; + + // int QImageWriter::quality() + // void QImageWriter::setQuality(int) + obj1.setQuality(0); + QCOMPARE(0, obj1.quality()); + obj1.setQuality(INT_MIN); + QCOMPARE(INT_MIN, obj1.quality()); + obj1.setQuality(INT_MAX); + QCOMPARE(INT_MAX, obj1.quality()); + + // int QImageWriter::compression() + // void QImageWriter::setCompression(int) + obj1.setCompression(0); + QCOMPARE(0, obj1.compression()); + obj1.setCompression(INT_MIN); + QCOMPARE(INT_MIN, obj1.compression()); + obj1.setCompression(INT_MAX); + QCOMPARE(INT_MAX, obj1.compression()); + + // float QImageWriter::gamma() + // void QImageWriter::setGamma(float) + obj1.setGamma(0.0f); + QCOMPARE(0.0f, obj1.gamma()); + obj1.setGamma(1.1f); + QCOMPARE(1.1f, obj1.gamma()); +} + +tst_QImageWriter::tst_QImageWriter() +{ +} + +tst_QImageWriter::~tst_QImageWriter() +{ + QDir dir(prefix); + QStringList filesToDelete = dir.entryList(QStringList() << "gen-*" , QDir::NoDotAndDotDot | QDir::Files); + foreach( QString file, filesToDelete) { + QFile::remove(dir.absoluteFilePath(file)); + } + +} + +void tst_QImageWriter::init() +{ +} + +void tst_QImageWriter::cleanup() +{ +} + +void tst_QImageWriter::writeImage_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<bool>("lossy"); + QTest::addColumn<QByteArray>("format"); + + QTest::newRow("BMP: colorful") << QString("colorful.bmp") << false << QByteArray("bmp"); + QTest::newRow("BMP: font") << QString("font.bmp") << false << QByteArray("bmp"); + QTest::newRow("XPM: marble") << QString("marble.xpm") << false << QByteArray("xpm"); + QTest::newRow("PNG: kollada") << QString("kollada.png") << false << QByteArray("png"); + QTest::newRow("PPM: teapot") << QString("teapot.ppm") << false << QByteArray("ppm"); + QTest::newRow("PBM: ship63") << QString("ship63.pbm") << true << QByteArray("pbm"); + QTest::newRow("XBM: gnus") << QString("gnus.xbm") << false << QByteArray("xbm"); + QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << true << QByteArray("jpeg"); +#if defined QTEST_HAVE_TIFF + QTest::newRow("TIFF: teapot") << QString("teapot.tiff") << false << QByteArray("tiff"); +#endif +} + +void tst_QImageWriter::writeImage() +{ + QFETCH(QString, fileName); + QFETCH(bool, lossy); + QFETCH(QByteArray, format); + + QImage image; + { + QImageReader reader(prefix + fileName); + image = reader.read(); + QVERIFY2(!image.isNull(), qPrintable(reader.errorString())); + } + { + QImageWriter writer(prefix + "gen-" + fileName, format); + QVERIFY(writer.write(image)); + } + + { + // Shouldn't be able to write to read-only file + QFile sourceFile(prefix + "gen-" + fileName); + QFile::Permissions permissions = sourceFile.permissions(); + QVERIFY(sourceFile.setPermissions(QFile::ReadOwner | QFile::ReadUser | QFile::ReadGroup | QFile::ReadOther)); + + QImageWriter writer(prefix + "gen-" + fileName, format); + QVERIFY(!writer.write(image)); + + QVERIFY(sourceFile.setPermissions(permissions)); + } + + QImage image2; + { + QImageReader reader(prefix + "gen-" + fileName); + image2 = reader.read(); + QVERIFY(!image2.isNull()); + } + if (!lossy) { + QCOMPARE(image, image2); + } else { + QCOMPARE(image.format(), image2.format()); + QCOMPARE(image.depth(), image2.depth()); + } +} + +void tst_QImageWriter::writeImage2_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("format"); + QTest::addColumn<QImage>("image"); + + const QStringList formats = QStringList() << "bmp" << "xpm" << "png" + << "ppm"; //<< "jpeg"; + QImage image0(70, 70, QImage::Format_ARGB32); + image0.fill(QColor(Qt::red).rgb()); + + QImage::Format imgFormat = QImage::Format_Mono; + while (imgFormat != QImage::NImageFormats) { + QImage image = image0.convertToFormat(imgFormat); + initializePadding(&image); + foreach (const QString format, formats) { + const QString fileName = QString("solidcolor_%1.%2").arg(imgFormat) + .arg(format); + QTest::newRow(fileName.toLatin1()) << fileName + << format.toLatin1() + << image; + } + imgFormat = QImage::Format(int(imgFormat) + 1); + } +} + +#if defined QTEST_HAVE_TIFF +void tst_QImageWriter::largeTiff() +{ +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QImage img(4096, 2048, QImage::Format_ARGB32); + + QPainter p(&img); + img.fill(0x0); + p.fillRect(0, 0, 4096, 2048, QBrush(Qt::CrossPattern)); + p.end(); + + QByteArray array; + QBuffer writeBuffer(&array); + writeBuffer.open(QIODevice::WriteOnly); + + QImageWriter writer(&writeBuffer, "tiff"); + QVERIFY(writer.write(img)); + + writeBuffer.close(); + + QBuffer readBuffer(&array); + readBuffer.open(QIODevice::ReadOnly); + + QImageReader reader(&readBuffer, "tiff"); + + QImage img2 = reader.read(); + QVERIFY(!img2.isNull()); + + QCOMPARE(img, img2); +#else + QWARN("not tested on Symbian/WinCE"); +#endif +} +#endif + +/* + Workaround for the equality operator for indexed formats + (which fails if the colortables are different). + + Images must have the same format and size. +*/ +static bool equalImageContents(const QImage &image1, const QImage &image2) +{ + switch (image1.format()) { + case QImage::Format_Mono: + case QImage::Format_Indexed8: + for (int y = 0; y < image1.height(); ++y) + for (int x = 0; x < image1.width(); ++x) + if (image1.pixel(x, y) != image2.pixel(x, y)) + return false; + return true; + default: + return (image1 == image2); + } +} + +void tst_QImageWriter::writeImage2() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + QFETCH(QImage, image); + + //we reduce the scope of writer so that it closes the associated file + // and QFile::remove can actually work + { + QImageWriter writer(fileName, format); + QVERIFY(writer.write(image)); + } + + QImage written; + + //we reduce the scope of reader so that it closes the associated file + // and QFile::remove can actually work + { + QImageReader reader(fileName, format); + QVERIFY(reader.read(&written)); + } + + written = written.convertToFormat(image.format()); + if (!equalImageContents(written, image)) { + qDebug() << "image" << image.format() << image.width() + << image.height() << image.depth() + << hex << image.pixel(0, 0); + qDebug() << "written" << written.format() << written.width() + << written.height() << written.depth() + << hex << written.pixel(0, 0); + } + QVERIFY(equalImageContents(written, image)); + + QVERIFY(QFile::remove(fileName)); +} + +void tst_QImageWriter::supportedFormats() +{ + QList<QByteArray> formats = QImageWriter::supportedImageFormats(); + QList<QByteArray> sortedFormats = formats; + qSort(sortedFormats); + + // check that the list is sorted + QCOMPARE(formats, sortedFormats); + + QSet<QByteArray> formatSet; + foreach (QByteArray format, formats) + formatSet << format; + + // check that the list does not contain duplicates + QCOMPARE(formatSet.size(), formats.size()); +} + +void tst_QImageWriter::readWriteNonDestructive_data() +{ + QTest::addColumn<QImage::Format>("format"); + QTest::addColumn<QImage::Format>("expectedFormat"); + QTest::addColumn<bool>("grayscale"); + QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono << false; + QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << false; + QTest::newRow("tiff rgb32") << QImage::Format_ARGB32 << QImage::Format_ARGB32 << false; + QTest::newRow("tiff grayscale") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << true; +} + +void tst_QImageWriter::readWriteNonDestructive() +{ + QFETCH(QImage::Format, format); + QFETCH(QImage::Format, expectedFormat); + QFETCH(bool, grayscale); + QImage image = QImage(prefix + "colorful.bmp").convertToFormat(format); + + if (grayscale) { + QVector<QRgb> colors; + for (int i = 0; i < 256; ++i) + colors << qRgb(i, i, i); + image.setColorTable(colors); + } + + QVERIFY(image.save(prefix + "gen-readWriteNonDestructive.tiff")); + + QImage image2 = QImage(prefix + "gen-readWriteNonDestructive.tiff"); + QImage::Format readFormat = image2.format(); + QCOMPARE(readFormat, expectedFormat); + QCOMPARE(image, image2); +} + +void tst_QImageWriter::writeToInvalidDevice() +{ + QLatin1String fileName("/these/directories/do/not/exist/001.png"); + { + QImageWriter writer(fileName); + QVERIFY(!writer.canWrite()); + QCOMPARE(writer.error(), QImageWriter::DeviceError); + } + { + QImageWriter writer(fileName); + writer.setFormat("png"); + QVERIFY(!writer.canWrite()); + QCOMPARE(writer.error(), QImageWriter::DeviceError); + } + { + QImageWriter writer(fileName); + QImage im(10, 10, QImage::Format_ARGB32); + QVERIFY(!writer.write(im)); + QCOMPARE(writer.error(), QImageWriter::DeviceError); + } + { + QImageWriter writer(fileName); + writer.setFormat("png"); + QImage im(10, 10, QImage::Format_ARGB32); + QVERIFY(!writer.write(im)); + QCOMPARE(writer.error(), QImageWriter::DeviceError); + } +} + +void tst_QImageWriter::supportsOption_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QIntList>("options"); + + QTest::newRow("png") << QString("gen-black.png") + << (QIntList() << QImageIOHandler::Gamma + << QImageIOHandler::Description + << QImageIOHandler::Quality + << QImageIOHandler::Size); +#if defined QTEST_HAVE_TIFF + QTest::newRow("tiff") << QString("gen-black.tiff") + << (QIntList() << QImageIOHandler::Size + << QImageIOHandler::CompressionRatio); +#endif +} + +void tst_QImageWriter::supportsOption() +{ + QFETCH(QString, fileName); + QFETCH(QIntList, options); + + QSet<QImageIOHandler::ImageOption> allOptions; + allOptions << QImageIOHandler::Size + << QImageIOHandler::ClipRect + << QImageIOHandler::Description + << QImageIOHandler::ScaledClipRect + << QImageIOHandler::ScaledSize + << QImageIOHandler::CompressionRatio + << QImageIOHandler::Gamma + << QImageIOHandler::Quality + << QImageIOHandler::Name + << QImageIOHandler::SubType + << QImageIOHandler::IncrementalReading + << QImageIOHandler::Endianness + << QImageIOHandler::Animation + << QImageIOHandler::BackgroundColor; + + QImageWriter writer(prefix + fileName); + for (int i = 0; i < options.size(); ++i) { + QVERIFY(writer.supportsOption(QImageIOHandler::ImageOption(options.at(i)))); + allOptions.remove(QImageIOHandler::ImageOption(options.at(i))); + } + + foreach (QImageIOHandler::ImageOption option, allOptions) + QVERIFY(!writer.supportsOption(option)); +} + +void tst_QImageWriter::saveWithNoFormat_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QByteArray>("format"); + QTest::addColumn<QImageWriter::ImageWriterError>("error"); + + QTest::newRow("garble") << prefix + QString("gen-out.garble") << QByteArray("jpeg") << QImageWriter::UnsupportedFormatError; + QTest::newRow("bmp") << prefix + QString("gen-out.bmp") << QByteArray("bmp") << QImageWriter::ImageWriterError(0); + QTest::newRow("xbm") << prefix + QString("gen-out.xbm") << QByteArray("xbm") << QImageWriter::ImageWriterError(0); + QTest::newRow("xpm") << prefix + QString("gen-out.xpm") << QByteArray("xpm") << QImageWriter::ImageWriterError(0); + QTest::newRow("png") << prefix + QString("gen-out.png") << QByteArray("png") << QImageWriter::ImageWriterError(0); + QTest::newRow("ppm") << prefix + QString("gen-out.ppm") << QByteArray("ppm") << QImageWriter::ImageWriterError(0); + QTest::newRow("pbm") << prefix + QString("gen-out.pbm") << QByteArray("pbm") << QImageWriter::ImageWriterError(0); +#if defined QTEST_HAVE_TIFF + QTest::newRow("tiff") << prefix + QString("gen-out.tiff") << QByteArray("tiff") << QImageWriter::ImageWriterError(0); +#endif +} + +void tst_QImageWriter::saveWithNoFormat() +{ + QFETCH(QString, fileName); + QFETCH(QByteArray, format); + QFETCH(QImageWriter::ImageWriterError, error); + + QImage niceImage(64, 64, QImage::Format_ARGB32); + qMemSet(niceImage.bits(), 0, niceImage.byteCount()); + + QImageWriter writer(fileName /* , 0 - no format! */); + if (error != 0) { + QVERIFY(!writer.write(niceImage)); + QCOMPARE(writer.error(), error); + return; + } + + QVERIFY2(writer.write(niceImage), qPrintable(writer.errorString())); + + QImageReader reader(fileName); + QCOMPARE(reader.format(), format); + + QVERIFY(reader.canRead()); + + QImage outImage = reader.read(); + QVERIFY2(!outImage.isNull(), qPrintable(reader.errorString())); +} + +void tst_QImageWriter::resolution_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<int>("expectedDotsPerMeterX"); + QTest::addColumn<int>("expectedDotsPerMeterY"); +#if defined QTEST_HAVE_TIFF + QTest::newRow("TIFF: 100 dpi") << ("image_100dpi.tif") << qRound(100 * (100 / 2.54)) << qRound(100 * (100 / 2.54)); + QTest::newRow("TIFF: 50 dpi") << ("image_50dpi.tif") << qRound(50 * (100 / 2.54)) << qRound(50 * (100 / 2.54)); + QTest::newRow("TIFF: 300 dot per meter") << ("image_300dpm.tif") << 300 << 300; +#endif +} + +void tst_QImageWriter::resolution() +{ + QFETCH(QString, filename); + QFETCH(int, expectedDotsPerMeterX); + QFETCH(int, expectedDotsPerMeterY); + + QImage image(prefix + QLatin1String("colorful.bmp")); + image.setDotsPerMeterX(expectedDotsPerMeterX); + image.setDotsPerMeterY(expectedDotsPerMeterY); + const QString generatedFilepath = prefix + "gen-" + filename; + { + QImageWriter writer(generatedFilepath); + QVERIFY(writer.write(image)); + } + QImageReader reader(generatedFilepath); + const QImage generatedImage = reader.read(); + + QCOMPARE(expectedDotsPerMeterX, generatedImage.dotsPerMeterX()); + QCOMPARE(expectedDotsPerMeterY, generatedImage.dotsPerMeterY()); +} + +void tst_QImageWriter::saveToTemporaryFile() +{ + QImage image(prefix + "kollada.png"); + QVERIFY(!image.isNull()); + + { + // 1) Via QImageWriter's API, with a standard temp file name + QTemporaryFile file; + QVERIFY(file.open()); + QImageWriter writer(&file, "PNG"); + if (writer.canWrite()) + QVERIFY(writer.write(image)); + else + qWarning() << file.errorString(); +#if defined(Q_OS_WINCE) + file.reset(); +#endif + QCOMPARE(QImage(writer.fileName()), image); + } + { + // 2) Via QImage's API, with a standard temp file name + QTemporaryFile file; + QVERIFY(file.open()); + QVERIFY(image.save(&file, "PNG")); + file.reset(); + QImage tmp; + QVERIFY(tmp.load(&file, "PNG")); + QCOMPARE(tmp, image); + } + { + // 3) Via QImageWriter's API, with a named temp file + QTemporaryFile file("tempXXXXXX"); + QVERIFY(file.open()); + QImageWriter writer(&file, "PNG"); + QVERIFY(writer.write(image)); +#if defined(Q_OS_WINCE) + file.reset(); +#endif + QCOMPARE(QImage(writer.fileName()), image); + } + { + // 4) Via QImage's API, with a named temp file + QTemporaryFile file("tempXXXXXX"); + QVERIFY(file.open()); + QVERIFY(image.save(&file, "PNG")); + file.reset(); + QImage tmp; + QVERIFY(tmp.load(&file, "PNG")); + QCOMPARE(tmp, image); + } +} + +QTEST_MAIN(tst_QImageWriter) +#include "tst_qimagewriter.moc" diff --git a/tests/auto/gui/image/qmovie/.gitignore b/tests/auto/gui/image/qmovie/.gitignore new file mode 100644 index 0000000000..396e8cbc7d --- /dev/null +++ b/tests/auto/gui/image/qmovie/.gitignore @@ -0,0 +1 @@ +tst_qmovie diff --git a/tests/auto/gui/image/qmovie/animations/comicsecard.gif b/tests/auto/gui/image/qmovie/animations/comicsecard.gif Binary files differnew file mode 100644 index 0000000000..f064de065b --- /dev/null +++ b/tests/auto/gui/image/qmovie/animations/comicsecard.gif diff --git a/tests/auto/gui/image/qmovie/animations/corrupt.gif b/tests/auto/gui/image/qmovie/animations/corrupt.gif Binary files differnew file mode 100644 index 0000000000..c1545eb0ed --- /dev/null +++ b/tests/auto/gui/image/qmovie/animations/corrupt.gif diff --git a/tests/auto/gui/image/qmovie/animations/dutch.mng b/tests/auto/gui/image/qmovie/animations/dutch.mng Binary files differnew file mode 100644 index 0000000000..4917fdee7a --- /dev/null +++ b/tests/auto/gui/image/qmovie/animations/dutch.mng diff --git a/tests/auto/gui/image/qmovie/animations/trolltech.gif b/tests/auto/gui/image/qmovie/animations/trolltech.gif Binary files differnew file mode 100644 index 0000000000..df7eb92703 --- /dev/null +++ b/tests/auto/gui/image/qmovie/animations/trolltech.gif diff --git a/tests/auto/gui/image/qmovie/qmovie.pro b/tests/auto/gui/image/qmovie/qmovie.pro new file mode 100644 index 0000000000..3e085ceeaf --- /dev/null +++ b/tests/auto/gui/image/qmovie/qmovie.pro @@ -0,0 +1,28 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qmovie.cpp +MOC_DIR=tmp + +!contains(QT_CONFIG, no-gif):DEFINES += QTEST_HAVE_GIF +!contains(QT_CONFIG, no-jpeg):DEFINES += QTEST_HAVE_JPEG +!contains(QT_CONFIG, no-mng):DEFINES += QTEST_HAVE_MNG + +wince*: { + addFiles.files = animations\\* + addFiles.path = animations + DEPLOYMENT += addFiles +} + +RESOURCES += resources.qrc + +symbian: { + addFiles.files = animations\\* + addFiles.path = animations + DEPLOYMENT += addFiles + + qt_not_deployed { + imagePlugins.files = qjpeg.dll qgif.dll qmng.dll + imagePlugins.path = imageformats + DEPLOYMENT += imagePlugins + } +} diff --git a/tests/auto/gui/image/qmovie/resources.qrc b/tests/auto/gui/image/qmovie/resources.qrc new file mode 100644 index 0000000000..ce459a0e7e --- /dev/null +++ b/tests/auto/gui/image/qmovie/resources.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>animations/corrupt.gif</file> +</qresource> +</RCC> diff --git a/tests/auto/gui/image/qmovie/tst_qmovie.cpp b/tests/auto/gui/image/qmovie/tst_qmovie.cpp new file mode 100644 index 0000000000..15c7f856b1 --- /dev/null +++ b/tests/auto/gui/image/qmovie/tst_qmovie.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <QIODevice> +#include <QLabel> +#include <QMovie> + +//TESTED_FILES= + +class tst_QMovie : public QObject +{ + Q_OBJECT + +public: + tst_QMovie(); + virtual ~tst_QMovie(); + +public slots: + void init(); + void cleanup(); + +protected slots: + void exitLoopSlot(); + +private slots: + void getSetCheck(); + void construction(); + void playMovie_data(); + void playMovie(); + void jumpToFrame_data(); + void jumpToFrame(); + void changeMovieFile(); + void infiniteLoop(); +}; + +// Testing get/set functions +void tst_QMovie::getSetCheck() +{ + QMovie obj1; + // QIODevice * QMovie::device() + // void QMovie::setDevice(QIODevice *) + QFile *var1 = new QFile; + obj1.setDevice(var1); + QCOMPARE(obj1.device(), (QIODevice *)var1); + obj1.setDevice((QIODevice *)0); + QCOMPARE(obj1.device(), (QIODevice *)0); + delete var1; + + // CacheMode QMovie::cacheMode() + // void QMovie::setCacheMode(CacheMode) + obj1.setCacheMode(QMovie::CacheMode(QMovie::CacheNone)); + QCOMPARE(QMovie::CacheMode(QMovie::CacheNone), obj1.cacheMode()); + obj1.setCacheMode(QMovie::CacheMode(QMovie::CacheAll)); + QCOMPARE(QMovie::CacheMode(QMovie::CacheAll), obj1.cacheMode()); + + // int QMovie::speed() + // void QMovie::setSpeed(int) + obj1.setSpeed(0); + QCOMPARE(0, obj1.speed()); + obj1.setSpeed(INT_MIN); + QCOMPARE(INT_MIN, obj1.speed()); + obj1.setSpeed(INT_MAX); + QCOMPARE(INT_MAX, obj1.speed()); +} + +tst_QMovie::tst_QMovie() +{ +} + +tst_QMovie::~tst_QMovie() +{ + +} + +void tst_QMovie::init() +{ +} + +void tst_QMovie::cleanup() +{ +} + +void tst_QMovie::exitLoopSlot() +{ + QTestEventLoop::instance().exitLoop(); +} + +void tst_QMovie::construction() +{ + QMovie movie; + QCOMPARE(movie.device(), (QIODevice *)0); + QCOMPARE(movie.fileName(), QString()); + QCOMPARE(movie.state(), QMovie::NotRunning); +} + +void tst_QMovie::playMovie_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<int>("frameCount"); +#if defined(QTEST_HAVE_MNG) && !defined(Q_OS_WINCE) + // Qt/WinCE runs out of memory for this one... + QTest::newRow("home") << QString("animations/dutch.mng") << 10; +#endif +#ifdef QTEST_HAVE_GIF + QTest::newRow("comicsecard") << QString("animations/comicsecard.gif") << 5; + QTest::newRow("trolltech") << QString("animations/trolltech.gif") << 34; +#endif +} + +void tst_QMovie::playMovie() +{ + QFETCH(QString, fileName); + QFETCH(int, frameCount); + + QMovie movie(fileName); + + QCOMPARE(movie.state(), QMovie::NotRunning); + movie.setSpeed(1000); + movie.start(); + QCOMPARE(movie.state(), QMovie::Running); + movie.setPaused(true); + QCOMPARE(movie.state(), QMovie::Paused); + movie.start(); + QCOMPARE(movie.state(), QMovie::Running); + movie.stop(); + QCOMPARE(movie.state(), QMovie::NotRunning); + movie.jumpToFrame(0); + QCOMPARE(movie.state(), QMovie::NotRunning); + movie.start(); + QCOMPARE(movie.state(), QMovie::Running); + + connect(&movie, SIGNAL(finished()), this, SLOT(exitLoopSlot())); + + QLabel label; + label.setMovie(&movie); + label.show(); + + QTestEventLoop::instance().enterLoop(20); + QVERIFY2(!QTestEventLoop::instance().timeout(), + "Timed out while waiting for finished() signal"); + + QCOMPARE(movie.state(), QMovie::NotRunning); + QCOMPARE(movie.frameCount(), frameCount); +} + +void tst_QMovie::jumpToFrame_data() +{ + playMovie_data(); +} + +void tst_QMovie::jumpToFrame() +{ + QFETCH(QString, fileName); + QMovie movie(fileName); + movie.start(); + movie.stop(); + QVERIFY(movie.jumpToFrame(-1) == false); + QVERIFY(movie.currentFrameNumber() == 0); +} + +void tst_QMovie::changeMovieFile() +{ + QMovie movie("animations/comicsecard.gif"); + movie.start(); + movie.stop(); + movie.setFileName("animations/trolltech.gif"); + QVERIFY(movie.currentFrameNumber() == -1); +} + +void tst_QMovie::infiniteLoop() +{ + QLabel label; + label.show(); + QMovie *movie = new QMovie(QLatin1String(":animations/corrupt.gif"), QByteArray(), &label); + label.setMovie(movie); + movie->start(); + + QTestEventLoop::instance().enterLoop(1); + QTestEventLoop::instance().timeout(); +} + +QTEST_MAIN(tst_QMovie) +#include "tst_qmovie.moc" diff --git a/tests/auto/gui/image/qpicture/.gitignore b/tests/auto/gui/image/qpicture/.gitignore new file mode 100644 index 0000000000..0f391ffb80 --- /dev/null +++ b/tests/auto/gui/image/qpicture/.gitignore @@ -0,0 +1 @@ +tst_qpicture diff --git a/tests/auto/gui/image/qpicture/qpicture.pro b/tests/auto/gui/image/qpicture/qpicture.pro new file mode 100644 index 0000000000..eb96b73487 --- /dev/null +++ b/tests/auto/gui/image/qpicture/qpicture.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qpicture.cpp + + + diff --git a/tests/auto/gui/image/qpicture/tst_qpicture.cpp b/tests/auto/gui/image/qpicture/tst_qpicture.cpp new file mode 100644 index 0000000000..8661a2b2d0 --- /dev/null +++ b/tests/auto/gui/image/qpicture/tst_qpicture.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qpicture.h> +#include <qpainter.h> +#include <qimage.h> +#include <qdesktopwidget.h> +#include <qapplication.h> +#include <limits.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPicture : public QObject +{ + Q_OBJECT + +public: + tst_QPicture(); + +private slots: + void getSetCheck(); + void devType(); + void paintingActive(); + void boundingRect(); + void swap(); + void operator_lt_lt(); + + void save_restore(); + + void boundaryValues_data(); + void boundaryValues(); +}; + +// Testing get/set functions +void tst_QPicture::getSetCheck() +{ + QPictureIO obj1; + // const QPicture & QPictureIO::picture() + // void QPictureIO::setPicture(const QPicture &) + // const char * QPictureIO::format() + // void QPictureIO::setFormat(const char *) + const char var2[] = "PNG"; + obj1.setFormat(var2); + QCOMPARE(var2, obj1.format()); + obj1.setFormat((char *)0); + // The format is stored internally in a QString, so return is always a valid char * + QVERIFY(QString(obj1.format()).isEmpty()); + + // const char * QPictureIO::parameters() + // void QPictureIO::setParameters(const char *) + const char var3[] = "Bogus data"; + obj1.setParameters(var3); + QCOMPARE(var3, obj1.parameters()); + obj1.setParameters((char *)0); + // The format is stored internally in a QString, so return is always a valid char * + QVERIFY(QString(obj1.parameters()).isEmpty()); +} + +tst_QPicture::tst_QPicture() +{ +} + +void tst_QPicture::devType() +{ + QPicture p; + QCOMPARE( p.devType(), (int)QInternal::Picture ); +} + +void tst_QPicture::paintingActive() +{ + // actually implemented in QPainter but QPicture is a good + // example of an external paint device + QPicture p; + QVERIFY( !p.paintingActive() ); + QPainter pt( &p ); + QVERIFY( p.paintingActive() ); + pt.end(); + QVERIFY( !p.paintingActive() ); +} + +void tst_QPicture::boundingRect() +{ + QPicture p1; + // default value + QVERIFY( !p1.boundingRect().isValid() ); + + QRect r1( 20, 30, 5, 15 ); + p1.setBoundingRect( r1 ); + QCOMPARE( p1.boundingRect(), r1 ); + p1.setBoundingRect(QRect()); + + QPainter pt( &p1 ); + pt.drawLine( 10, 20, 110, 80 ); + pt.end(); + + // assignment and copy constructor + QRect r2( 10, 20, 100, 60 ); + QCOMPARE( p1.boundingRect(), r2 ); + QPicture p2( p1 ); + QCOMPARE( p1.boundingRect(), r2 ); + QPicture p3; + p3 = p1; + QCOMPARE( p1.boundingRect(), r2 ); + + { + QPicture p4; + QPainter p(&p4); + p.drawLine(0, 0, 5, 0); + p.drawLine(0, 0, 0, 5); + p.end(); + + QRect r3(0, 0, 5, 5); + QCOMPARE(p4.boundingRect(), r3); + } +} + +void tst_QPicture::swap() +{ + QPicture p1, p2; + QPainter(&p1).drawLine(0, 0, 5, 5); + QPainter(&p2).drawLine(0, 3, 3, 0); + QCOMPARE(p1.boundingRect(), QRect(0,0,5,5)); + QCOMPARE(p2.boundingRect(), QRect(0,0,3,3)); + p1.swap(p2); + QCOMPARE(p1.boundingRect(), QRect(0,0,3,3)); + QCOMPARE(p2.boundingRect(), QRect(0,0,5,5)); +} + +// operator<< and operator>> +void tst_QPicture::operator_lt_lt() +{ + // streaming of null pictures + { + QPicture pic1, pic2; + QByteArray ba( 100, 0 ); + QDataStream str1( &ba, QIODevice::WriteOnly ); + str1 << pic1; + QDataStream str2( &ba, QIODevice::ReadOnly ); + str2 >> pic2; + QVERIFY( pic2.isNull() ); + } + + // picture with a simple line, checking bitwise equality + { + QPicture pic1, pic2; + QPainter p( &pic1 ); + p.drawLine( 10, 20, 30, 40 ); + p.end(); + QByteArray ba( 10 * pic1.size(), 0 ); + QDataStream str1( &ba, QIODevice::WriteOnly ); + str1 << pic1; + QDataStream str2( &ba, QIODevice::ReadOnly ); + str2 >> pic2; + QCOMPARE( pic1.size(), pic2.size() ); + QVERIFY( memcmp( pic1.data(), pic2.data(), pic1.size() ) == 0 ); + } +} + +static QPointF scalePoint(const QPointF &point, QPaintDevice *sourceDevice, QPaintDevice *destDevice) +{ + return QPointF(point.x() * qreal(destDevice->logicalDpiX()) / qreal(sourceDevice->logicalDpiX()), + point.y() * qreal(destDevice->logicalDpiY()) / qreal(sourceDevice->logicalDpiY())); +} + +static QRectF scaleRect(const QRectF &rect, QPaintDevice *sourceDevice, QPaintDevice *destDevice) +{ + return QRectF(rect.left() * qreal(destDevice->logicalDpiX()) / qreal(sourceDevice->logicalDpiX()), + rect.top() * qreal(destDevice->logicalDpiY()) / qreal(sourceDevice->logicalDpiY()), + rect.width() * qreal(destDevice->logicalDpiX()) / qreal(sourceDevice->logicalDpiX()), + rect.height() * qreal(destDevice->logicalDpiY()) / qreal(sourceDevice->logicalDpiY())); +} + +static void paintStuff(QPainter *p) +{ + QPaintDevice *screenDevice = QApplication::desktop(); + p->drawRect(scaleRect(QRectF(100, 100, 100, 100), screenDevice, p->device())); + p->save(); + p->translate(scalePoint(QPointF(10, 10), screenDevice, p->device())); + p->restore(); + p->drawRect(scaleRect(QRectF(100, 100, 100, 100), screenDevice, p->device())); +} + +/* See task: 41469 + Problem is that the state is not properly restored if the basestate of + the painter is different when the picture data was created compared to + the base state of the painter when it is played back. + */ +void tst_QPicture::save_restore() +{ + QPicture pic; + QPainter p; + p.begin(&pic); + paintStuff(&p); + p.end(); + + QPixmap pix1(300, 300); + pix1.fill(Qt::white); + p.begin(&pix1); + p.drawPicture(50, 50, pic); + p.end(); + + QPixmap pix2(300, 300); + pix2.fill(Qt::white); + p.begin(&pix2); + p.translate(50, 50); + paintStuff(&p); + p.end(); + + QVERIFY( pix1.toImage() == pix2.toImage() ); +} + +void tst_QPicture::boundaryValues_data() +{ + QTest::addColumn<int>("x"); + QTest::addColumn<int>("y"); + QTest::newRow("max x") << INT_MAX << 50; + QTest::newRow("max y") << 50 << INT_MAX; + QTest::newRow("max x and y") << INT_MAX << INT_MAX; + + QTest::newRow("min x") << INT_MIN << 50; + QTest::newRow("min y") << 50 << INT_MIN; + QTest::newRow("min x and y") << INT_MIN << INT_MIN; + + QTest::newRow("min x, max y") << INT_MIN << INT_MAX; + QTest::newRow("max x, min y") << INT_MAX << INT_MIN; + +} + +void tst_QPicture::boundaryValues() +{ + QPicture picture; + + QPainter painter; + painter.begin(&picture); + + QFETCH(int, x); + QFETCH(int, y); + painter.drawPoint(QPoint(x, y)); + + painter.end(); + + +} + + +QTEST_MAIN(tst_QPicture) +#include "tst_qpicture.moc" diff --git a/tests/auto/gui/image/qpixmap/.gitignore b/tests/auto/gui/image/qpixmap/.gitignore new file mode 100644 index 0000000000..8d4996f365 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/.gitignore @@ -0,0 +1 @@ +tst_qpixmap diff --git a/tests/auto/gui/image/qpixmap/convertFromImage/task31722_0/img1.png b/tests/auto/gui/image/qpixmap/convertFromImage/task31722_0/img1.png Binary files differnew file mode 100644 index 0000000000..7991e9fb17 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromImage/task31722_0/img1.png diff --git a/tests/auto/gui/image/qpixmap/convertFromImage/task31722_0/img2.png b/tests/auto/gui/image/qpixmap/convertFromImage/task31722_0/img2.png Binary files differnew file mode 100644 index 0000000000..dca6d97dc3 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromImage/task31722_0/img2.png diff --git a/tests/auto/gui/image/qpixmap/convertFromImage/task31722_1/img1.png b/tests/auto/gui/image/qpixmap/convertFromImage/task31722_1/img1.png Binary files differnew file mode 100644 index 0000000000..31e6e1aaa0 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromImage/task31722_1/img1.png diff --git a/tests/auto/gui/image/qpixmap/convertFromImage/task31722_1/img2.png b/tests/auto/gui/image/qpixmap/convertFromImage/task31722_1/img2.png Binary files differnew file mode 100644 index 0000000000..0d48026898 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromImage/task31722_1/img2.png diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp.ico b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp.ico Binary files differnew file mode 100644 index 0000000000..dbb55cd4db --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp.ico diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_16x16.png b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_16x16.png Binary files differnew file mode 100644 index 0000000000..f23f39818c --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_16x16.png diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_256x256.png b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_256x256.png Binary files differnew file mode 100644 index 0000000000..293f1c5942 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_256x256.png diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_32x32.png b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_32x32.png Binary files differnew file mode 100644 index 0000000000..bfdb1fe035 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_32x32.png diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_48x48.png b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_48x48.png Binary files differnew file mode 100644 index 0000000000..7dd2d13351 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_32bpp_48x48.png diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp.ico b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp.ico Binary files differnew file mode 100644 index 0000000000..4341a3355e --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp.ico diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_16x16.png b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_16x16.png Binary files differnew file mode 100644 index 0000000000..e9a995e19e --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_16x16.png diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_32x32.png b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_32x32.png Binary files differnew file mode 100644 index 0000000000..41ef57f94d --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_32x32.png diff --git a/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_48x48.png b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_48x48.png Binary files differnew file mode 100644 index 0000000000..35d60d138b --- /dev/null +++ b/tests/auto/gui/image/qpixmap/convertFromToHICON/icon_8bpp_48x48.png diff --git a/tests/auto/gui/image/qpixmap/images/designer.png b/tests/auto/gui/image/qpixmap/images/designer.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/designer.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_-10_dy_-10_50_50_100_100.png b/tests/auto/gui/image/qpixmap/images/dx_-10_dy_-10_50_50_100_100.png Binary files differnew file mode 100644 index 0000000000..a4a19249c7 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_-10_dy_-10_50_50_100_100.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_-10_dy_-10_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_-10_dy_-10_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..1506af5a7e --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_-10_dy_-10_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_-10_dy_0_50_50_100_100.png b/tests/auto/gui/image/qpixmap/images/dx_-10_dy_0_50_50_100_100.png Binary files differnew file mode 100644 index 0000000000..8500ab1f5c --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_-10_dy_0_50_50_100_100.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_-10_dy_0_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_-10_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..2145c6124c --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_-10_dy_0_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_-128_dy_-128_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_-128_dy_-128_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_-128_dy_-128_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_-128_dy_0_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_-128_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_-128_dy_0_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_-10_50_50_100_100.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_-10_50_50_100_100.png Binary files differnew file mode 100644 index 0000000000..728ee79153 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_-10_50_50_100_100.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_-10_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_-10_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..e9d5850db7 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_-10_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_-128_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_-128_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_-128_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_50_50_100_100.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_50_50_100_100.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_50_50_100_100.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_null.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_null.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_null.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_0_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_10_50_50_100_100.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_10_50_50_100_100.png Binary files differnew file mode 100644 index 0000000000..7c09b17830 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_10_50_50_100_100.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_10_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_10_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..70a63405e6 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_10_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_128_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_128_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_128_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_0_dy_1_null.png b/tests/auto/gui/image/qpixmap/images/dx_0_dy_1_null.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_0_dy_1_null.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_10_dy_0_50_50_100_100.png b/tests/auto/gui/image/qpixmap/images/dx_10_dy_0_50_50_100_100.png Binary files differnew file mode 100644 index 0000000000..85abadaf98 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_10_dy_0_50_50_100_100.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_10_dy_0_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_10_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..3e03450c01 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_10_dy_0_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_10_dy_10_50_50_100_100.png b/tests/auto/gui/image/qpixmap/images/dx_10_dy_10_50_50_100_100.png Binary files differnew file mode 100644 index 0000000000..315fbe087a --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_10_dy_10_50_50_100_100.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_10_dy_10_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_10_dy_10_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..d91dc71217 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_10_dy_10_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_128_dy_0_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_128_dy_0_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_128_dy_0_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_128_dy_128_64_64_128_128.png b/tests/auto/gui/image/qpixmap/images/dx_128_dy_128_64_64_128_128.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_128_dy_128_64_64_128_128.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_128_dy_128_x_y_w_h.png b/tests/auto/gui/image/qpixmap/images/dx_128_dy_128_x_y_w_h.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_128_dy_128_x_y_w_h.png diff --git a/tests/auto/gui/image/qpixmap/images/dx_1_dy_0_null.png b/tests/auto/gui/image/qpixmap/images/dx_1_dy_0_null.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/images/dx_1_dy_0_null.png diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_argb32.png b/tests/auto/gui/image/qpixmap/loadFromData/designer_argb32.png Binary files differnew file mode 100644 index 0000000000..55d8247cfc --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_argb32.png diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha.gif b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha.gif Binary files differnew file mode 100644 index 0000000000..26a6da33df --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha.gif diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha.png b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha.png Binary files differnew file mode 100644 index 0000000000..28cd2f06d1 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha.png diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha_animated.gif b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha_animated.gif Binary files differnew file mode 100644 index 0000000000..86a3a2e17d --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_no_alpha_animated.gif diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha.gif b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha.gif Binary files differnew file mode 100644 index 0000000000..49ec77b39b --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha.gif diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha.png b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha.png Binary files differnew file mode 100644 index 0000000000..09735a9752 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha.png diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha_animated.gif b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha_animated.gif Binary files differnew file mode 100644 index 0000000000..f813c057d2 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_indexed8_with_alpha_animated.gif diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_rgb32.jpg b/tests/auto/gui/image/qpixmap/loadFromData/designer_rgb32.jpg Binary files differnew file mode 100644 index 0000000000..70f39c2154 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_rgb32.jpg diff --git a/tests/auto/gui/image/qpixmap/loadFromData/designer_rgb32.png b/tests/auto/gui/image/qpixmap/loadFromData/designer_rgb32.png Binary files differnew file mode 100644 index 0000000000..bca471d576 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/loadFromData/designer_rgb32.png diff --git a/tests/auto/gui/image/qpixmap/qpixmap.pro b/tests/auto/gui/image/qpixmap/qpixmap.pro new file mode 100644 index 0000000000..bcd65897d2 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/qpixmap.pro @@ -0,0 +1,35 @@ +load(qttest_p4) + +QT += core-private gui-private widgets widgets-private + +SOURCES += tst_qpixmap.cpp +wince*|symbian: { + + task31722_0.files = convertFromImage/task31722_0/*.png + task31722_0.path = convertFromImage/task31722_0 + + task31722_1.files = convertFromImage/task31722_1/*.png + task31722_1.path = convertFromImage/task31722_1 + + icons.files = convertFromToHICON/* + icons.path = convertFromToHICON + + loadFromData.files = loadFromData/* + loadFromData.path = loadFromData + + DEPLOYMENT += task31722_0 task31722_1 icons loadFromData +} + +wince*: { + DEFINES += SRCDIR=\\\".\\\" + DEPLOYMENT_PLUGIN += qico +} else:symbian { + LIBS += -lfbscli.dll -lbitgdi.dll -lgdi.dll +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" + win32:LIBS += -lgdi32 -luser32 +} + +RESOURCES += qpixmap.qrc + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/gui/image/qpixmap/qpixmap.qrc b/tests/auto/gui/image/qpixmap/qpixmap.qrc new file mode 100644 index 0000000000..99fde61a29 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/qpixmap.qrc @@ -0,0 +1,29 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>images/designer.png</file> + <file>images/dx_0_dy_0_50_50_100_100.png</file> + <file>images/dx_0_dy_0_null.png</file> + <file>images/dx_0_dy_0_x_y_w_h.png</file> + <file>images/dx_0_dy_-10_50_50_100_100.png</file> + <file>images/dx_0_dy_10_50_50_100_100.png</file> + <file>images/dx_0_dy_-10_x_y_w_h.png</file> + <file>images/dx_0_dy_10_x_y_w_h.png</file> + <file>images/dx_0_dy_-128_x_y_w_h.png</file> + <file>images/dx_0_dy_128_x_y_w_h.png</file> + <file>images/dx_0_dy_1_null.png</file> + <file>images/dx_-10_dy_0_50_50_100_100.png</file> + <file>images/dx_10_dy_0_50_50_100_100.png</file> + <file>images/dx_-10_dy_0_x_y_w_h.png</file> + <file>images/dx_10_dy_0_x_y_w_h.png</file> + <file>images/dx_-10_dy_-10_50_50_100_100.png</file> + <file>images/dx_10_dy_10_50_50_100_100.png</file> + <file>images/dx_-10_dy_-10_x_y_w_h.png</file> + <file>images/dx_10_dy_10_x_y_w_h.png</file> + <file>images/dx_-128_dy_0_x_y_w_h.png</file> + <file>images/dx_128_dy_0_x_y_w_h.png</file> + <file>images/dx_128_dy_128_64_64_128_128.png</file> + <file>images/dx_-128_dy_-128_x_y_w_h.png</file> + <file>images/dx_128_dy_128_x_y_w_h.png</file> + <file>images/dx_1_dy_0_null.png</file> +</qresource> +</RCC> diff --git a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp new file mode 100644 index 0000000000..38858e5503 --- /dev/null +++ b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp @@ -0,0 +1,1787 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qpixmap.h> +#include <qbitmap.h> +#include <qimage.h> +#include <qimagereader.h> +#include <qmatrix.h> +#include <qdesktopwidget.h> +#include <qpaintengine.h> +#include <qtreewidget.h> +#include <qsplashscreen.h> + +#include <qplatformpixmap_qpa.h> +#include <private/qdrawhelper_p.h> + +#include <QSet> + +#ifdef Q_WS_WIN +#include <windows.h> +#endif + +#ifdef Q_WS_QWS +#include <qscreen_qws.h> +#endif + +#ifdef Q_OS_SYMBIAN +#include <e32std.h> +#include <fbs.h> +#include <gdi.h> +#include <bitdev.h> +#if !defined(QT_NO_OPENVG) +#include <QtOpenVG/qvg.h> +#include <QtOpenVG/private/qpixmapdata_vg_p.h> +#endif +#endif + +#ifdef Q_WS_X11 +#include <QX11Info> +#endif + +//TESTED_CLASS= +//TESTED_FILES= +#if defined(Q_OS_SYMBIAN) +# define SRCDIR "" +#endif +Q_DECLARE_METATYPE(QImage::Format) + +class tst_QPixmap : public QObject +{ + Q_OBJECT + +public: + tst_QPixmap(); + virtual ~tst_QPixmap(); + + +public slots: + void init(); + void cleanup(); + +private slots: + void swap(); + + void fromImage_data(); + void fromImage(); + + void fromUninitializedImage_data(); + void fromUninitializedImage(); + + void convertFromImage_data(); + void convertFromImage(); + + void testMetrics(); + + void scroll_data(); + void scroll(); + + void fill_data(); + void fill(); + void fill_transparent(); + + void createMaskFromColor(); + + void mask(); + void bitmapMask(); + void setGetMask_data(); + void setGetMask(); + void cacheKey(); + void drawBitmap(); + void grabWidget(); + void grabWindow(); + void isNull(); + void task_246446(); + + void convertFromImageNoDetach(); + void convertFromImageDetach(); + +#if defined(Q_WS_WIN) + void toWinHBITMAP_data(); + void toWinHBITMAP(); + void fromWinHBITMAP_data(); + void fromWinHBITMAP(); + + void toWinHICON_data(); + void toWinHICON(); + void fromWinHICON_data(); + void fromWinHICON(); +#endif + +#if defined(Q_OS_SYMBIAN) + void fromSymbianCFbsBitmap_data(); + void fromSymbianCFbsBitmap(); + void toSymbianCFbsBitmap_data(); + void toSymbianCFbsBitmap(); +#endif + + void onlyNullPixmapsOutsideGuiThread(); + void refUnref(); + + void copy(); + void depthOfNullObjects(); + + void transformed(); + void transformed2(); + + void fromImage_crash(); + + void fromData(); + void loadFromDataNullValues(); + + void loadFromDataImage_data(); + void loadFromDataImage(); + + void fromImageReader_data(); + void fromImageReader(); + + void fromImageReaderAnimatedGif_data(); + void fromImageReaderAnimatedGif(); + + void preserveDepth(); + void splash_crash(); + + void toImageDeepCopy(); + + void loadAsBitmapOrPixmap(); + +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_OPENVG) + void vgImageReadBack(); +#endif + void scaled_QTBUG19157(); +}; + +static bool lenientCompare(const QPixmap &actual, const QPixmap &expected) +{ + QImage expectedImage = expected.toImage().convertToFormat(QImage::Format_RGB32); + QImage actualImage = actual.toImage().convertToFormat(QImage::Format_RGB32); + + if (expectedImage.size() != actualImage.size()) + return false; + + int size = actual.width() * actual.height(); + + int threshold = 2; +#ifdef Q_WS_X11 + if (QX11Info::appDepth() == 16) + threshold = 10; +#endif + + QRgb *a = (QRgb *)actualImage.bits(); + QRgb *e = (QRgb *)expectedImage.bits(); + for (int i = 0; i < size; ++i) { + QColor ca(a[i]); + QColor ce(e[i]); + + bool result = true; + + if (qAbs(ca.red() - ce.red()) > threshold) + result = false; + if (qAbs(ca.green() - ce.green()) > threshold) + result = false; + if (qAbs(ca.blue() - ce.blue()) > threshold) + result = false; + + if (!result) + return false; + } + + return true; +} + +Q_DECLARE_METATYPE(QImage) +Q_DECLARE_METATYPE(QPixmap) +Q_DECLARE_METATYPE(QMatrix) +Q_DECLARE_METATYPE(QBitmap) + +tst_QPixmap::tst_QPixmap() +{ +} + +tst_QPixmap::~tst_QPixmap() +{ +} + +void tst_QPixmap::init() +{ +} + +void tst_QPixmap::cleanup() +{ +} + +void tst_QPixmap::swap() +{ + QPixmap p1( 16, 16 ), p2( 32, 32 ); + p1.fill( Qt::white ); + p2.fill( Qt::black ); + const qint64 p1k = p1.cacheKey(); + const qint64 p2k = p2.cacheKey(); + p1.swap(p2); + QCOMPARE(p1.cacheKey(), p2k); + QCOMPARE(p1.size(), QSize(32,32)); + QCOMPARE(p2.cacheKey(), p1k); + QCOMPARE(p2.size(), QSize(16,16)); +} + +void tst_QPixmap::fromImage_data() +{ + bool is16bit = false; +#ifdef Q_WS_X11 + if (QX11Info::appDepth() == 16) + is16bit = true; +#endif + + QTest::addColumn<QImage::Format>("format"); + + QTest::newRow("Format_Mono") << QImage::Format_Mono; + QTest::newRow("Format_MonoLSB") << QImage::Format_MonoLSB; +// QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8; + if (!is16bit) + QTest::newRow("Format_RGB32") << QImage::Format_RGB32; + QTest::newRow("Format_ARGB32") << QImage::Format_ARGB32; + QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied; + if (!is16bit) + QTest::newRow("Format_RGB16") << QImage::Format_RGB16; +} + +void tst_QPixmap::fromImage() +{ + QFETCH(QImage::Format, format); + + QImage image(37, 16, format); + + if (image.colorCount() == 2) { + image.setColor(0, QColor(Qt::color0).rgba()); + image.setColor(1, QColor(Qt::color1).rgba()); + } + image.fill(0x7f7f7f7f); + + const QPixmap pixmap = QPixmap::fromImage(image); +#ifdef Q_WS_X11 + if (pixmap.handle()->classId() == QPlatformPixmap::X11Class && !pixmap.x11PictureHandle()) + QSKIP("Requires XRender support", SkipAll); +#endif + const QImage result = pixmap.toImage(); + image = image.convertToFormat(result.format()); + QCOMPARE(result, image); +} + + +void tst_QPixmap::fromUninitializedImage_data() +{ + QTest::addColumn<QImage::Format>("format"); + + QTest::newRow("Format_Mono") << QImage::Format_Mono; + QTest::newRow("Format_MonoLSB") << QImage::Format_MonoLSB; + QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8; + QTest::newRow("Format_RGB32") << QImage::Format_RGB32; + QTest::newRow("Format_ARGB32") << QImage::Format_ARGB32; + QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("Format_RGB16") << QImage::Format_RGB16; +} + +void tst_QPixmap::fromUninitializedImage() +{ + QFETCH(QImage::Format, format); + + QImage image(100, 100, format); + QPixmap pix = QPixmap::fromImage(image); + + // it simply shouldn't crash... + QVERIFY(true); + +} + +void tst_QPixmap::convertFromImage_data() +{ + QTest::addColumn<QImage>("img1"); + QTest::addColumn<QImage>("img2"); +#ifdef Q_OS_SYMBIAN + const QString prefix = QLatin1String(SRCDIR) + "convertFromImage"; +#else + const QString prefix = QLatin1String(SRCDIR) + "/convertFromImage"; +#endif + { + QImage img1; + QImage img2; + QVERIFY(img1.load(prefix + "/task31722_0/img1.png")); + QVERIFY(img2.load(prefix + "/task31722_0/img2.png")); + QVERIFY(img1.load(prefix + "/task31722_0/img1.png")); + QVERIFY(img2.load(prefix + "/task31722_0/img2.png")); + QTest::newRow("Task 31722 0") << img1 << img2; + } + { + QImage img1; + QImage img2; + QVERIFY(img1.load(prefix + "/task31722_1/img1.png")); + QVERIFY(img2.load(prefix + "/task31722_1/img2.png")); + QTest::newRow("Task 31722 1") << img1 << img2; + } +} + +void tst_QPixmap::convertFromImage() +{ + QFETCH(QImage, img1); + QFETCH(QImage, img2); + + QPixmap pix = QPixmap::fromImage(img1); + pix = QPixmap::fromImage(img2); + + QPixmap res = QPixmap::fromImage(img2); + QVERIFY( pixmapsAreEqual(&pix, &res) ); +} + +void tst_QPixmap::scroll_data() +{ + QTest::addColumn<QImage>("input"); + QTest::addColumn<int>("dx"); + QTest::addColumn<int>("dy"); + QTest::addColumn<QRect>("rect"); + QTest::addColumn<QRegion>("exposed"); + QTest::addColumn<bool>("newPix"); + + QImage input(":/images/designer.png"); + + // Noop tests + QTest::newRow("null") << QImage() << 0 << 0 << QRect() << QRegion() << false; + QTest::newRow("dx_0_dy_0_null") << input << 0 << 0 << QRect() << QRegion() << false; + QTest::newRow("dx_1_dy_0_null") << input << 1 << 0 << QRect() << QRegion() << false; + QTest::newRow("dx_0_dy_1_null") << input << 0 << 1 << QRect() << QRegion() << false; + QTest::newRow("dx_0_dy_0_x_y_w_h") << input << 0 << 0 << input.rect() << QRegion() << false; + + QRegion r; + // Scroll whole pixmap + r = QRegion(); r += QRect(0, 0, 128, 10); + QTest::newRow("dx_0_dy_10_x_y_w_h") << input << 0 << 10 << input.rect() << r << true; + r = QRegion(); r += QRect(0, 0, 10, 128); + QTest::newRow("dx_10_dy_0_x_y_w_h") << input << 10 << 0 << input.rect() << r << true; + r = QRegion(); r += QRect(0, 0, 128, 10); r += QRect(0, 10, 10, 118); + QTest::newRow("dx_10_dy_10_x_y_w_h") << input << 10 << 10 << input.rect() << r << true; + r = QRegion(); r += QRect(118, 0, 10, 128); + QTest::newRow("dx_-10_dy_0_x_y_w_h") << input << -10 << 0 << input.rect() << r << true; + r = QRegion(); r += QRect(0, 118, 128, 10); + QTest::newRow("dx_0_dy_-10_x_y_w_h") << input << 0 << -10 << input.rect() << r << true; + r = QRegion(); r += QRect(118, 0, 10, 118); r += QRect(0, 118, 128, 10); + QTest::newRow("dx_-10_dy_-10_x_y_w_h") << input << -10 << -10 << input.rect() << r << true; + + // Scroll part of pixmap + QTest::newRow("dx_0_dy_0_50_50_100_100") << input << 0 << 0 << QRect(50, 50, 100, 100) << QRegion() << false; + r = QRegion(); r += QRect(50, 50, 10, 78); + QTest::newRow("dx_10_dy_0_50_50_100_100") << input << 10 << 0 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(50, 50, 78, 10); + QTest::newRow("dx_0_dy_10_50_50_100_100") << input << 0 << 10 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(50, 50, 78, 10); r += QRect(50, 60, 10, 68); + QTest::newRow("dx_10_dy_10_50_50_100_100") << input << 10 << 10 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(118, 50, 10, 78); + QTest::newRow("dx_-10_dy_0_50_50_100_100") << input << -10 << 0 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(50, 118, 78, 10); + QTest::newRow("dx_0_dy_-10_50_50_100_100") << input << 0 << -10 << QRect(50, 50, 100, 100) << r << true; + r = QRegion(); r += QRect(118, 50, 10, 68); r += QRect(50, 118, 78, 10); + QTest::newRow("dx_-10_dy_-10_50_50_100_100") << input << -10 << -10 << QRect(50, 50, 100, 100) << r << true; + + // Scroll away the whole pixmap + r = input.rect(); + QTest::newRow("dx_128_dy_0_x_y_w_h") << input << 128 << 0 << input.rect() << r << false; + QTest::newRow("dx_0_dy_128_x_y_w_h") << input << 0 << 128 << input.rect() << r << false; + QTest::newRow("dx_128_dy_128_x_y_w_h") << input << 128 << 128 << input.rect() << r << false; + QTest::newRow("dx_-128_dy_0_x_y_w_h") << input << -128 << 0 << input.rect() << r << false; + QTest::newRow("dx_0_dy_-128_x_y_w_h") << input << 0 << -128 << input.rect() << r << false; + QTest::newRow("dx_-128_dy_-128_x_y_w_h") << input << -128 << -128 << input.rect() << r << false; + + // Scroll away part of the pixmap + r = QRegion(); r += QRect(64, 64, 64, 64); + QTest::newRow("dx_128_dy_128_64_64_128_128") << input << 128 << 128 << QRect(64, 64, 128, 128) << r << false; +} + +void tst_QPixmap::scroll() +{ + QFETCH(QImage, input); + QFETCH(int, dx); + QFETCH(int, dy); + QFETCH(QRect, rect); + QFETCH(QRegion, exposed); + QFETCH(bool, newPix); + + QPixmap pixmap = QPixmap::fromImage(input); + QRegion exp; + qint64 oldKey = pixmap.cacheKey(); + pixmap.scroll(dx, dy, rect, &exp); + if (!newPix) + QCOMPARE(pixmap.cacheKey(), oldKey); + else + QVERIFY(pixmap.cacheKey() != oldKey); + +#if 0 + // Remember to add to resources. + QString fileName = QString("images/%1.png").arg(QTest::currentDataTag()); + pixmap.toImage().save(fileName); +#else + QString fileName = QString(":/images/%1.png").arg(QTest::currentDataTag()); +#endif + QPixmap output(fileName); + QVERIFY(input.isNull() == output.isNull()); + QVERIFY(lenientCompare(pixmap, output)); + QCOMPARE(exp, exposed); +} + +void tst_QPixmap::fill_data() +{ + QTest::addColumn<uint>("pixel"); + QTest::addColumn<bool>("syscolor"); + QTest::addColumn<bool>("bitmap"); + for (int color = Qt::black; color < Qt::darkYellow; ++color) + QTest::newRow(QString("syscolor_%1").arg(color).toLatin1()) + << uint(color) << true << false; + +#ifdef Q_WS_QWS + if (QScreen::instance()->depth() >= 24) { +#elif defined (Q_WS_X11) + QPixmap pm(1, 1); + if (pm.x11PictureHandle()) { +#elif defined (Q_OS_WINCE) + QPixmap pixmap(1,1); + if (QPixmap::grabWidget(QApplication::desktop()).depth() >= 24) { +#else + QPixmap pixmap(1, 1); { +#endif + QTest::newRow("alpha_7f_red") << 0x7fff0000u << false << false; + QTest::newRow("alpha_3f_blue") << 0x3f0000ffu << false << false; + QTest::newRow("alpha_b7_green") << 0xbf00ff00u << false << false; + QTest::newRow("alpha_7f_white") << 0x7fffffffu << false << false; + QTest::newRow("alpha_3f_white") << 0x3fffffffu << false << false; + QTest::newRow("alpha_b7_white") << 0xb7ffffffu << false << false; + QTest::newRow("alpha_7f_black") << 0x7f000000u << false << false; + QTest::newRow("alpha_3f_black") << 0x3f000000u << false << false; + QTest::newRow("alpha_b7_black") << 0xbf000000u << false << false; + } + + QTest::newRow("bitmap_color0") << uint(Qt::color0) << true << true; + QTest::newRow("bitmap_color1") << uint(Qt::color1) << true << true; +} + +void tst_QPixmap::fill() +{ + QFETCH(uint, pixel); + QFETCH(bool, syscolor); + QFETCH(bool, bitmap); + + QColor color; + + if (syscolor) + color = QColor(Qt::GlobalColor(pixel)); + else + color = QColor(qRed(pixel), qGreen(pixel), qBlue(pixel), qAlpha(pixel)); + + QColor compareColor = color; + if (bitmap && syscolor) { + // special case color0 and color1 for bitmaps. + if (pixel == Qt::color0) + compareColor.setRgb(255, 255, 255); + else + compareColor.setRgb(0, 0, 0); + } + + QPixmap pm; + + if (bitmap) + pm = QBitmap(400, 400); + else + pm = QPixmap(400, 400); + +#if defined(Q_WS_X11) + if (!bitmap && pm.handle()->classId() == QPlatformPixmap::X11Class && !pm.x11PictureHandle()) + QSKIP("Requires XRender support", SkipSingle); +#endif + + pm.fill(color); + if (syscolor && !bitmap && pm.depth() < 24) { + QSKIP("Test does not work on displays without true color", SkipSingle); + } + + QImage image = pm.toImage(); + if (bitmap && syscolor) { + int pixelindex = (pixel == Qt::color0) ? 0 : 1; + QCOMPARE(image.pixelIndex(0,0), pixelindex); + } + QImage::Format format = compareColor.alpha() != 255 + ? QImage::Format_ARGB32 + : QImage::Format_RGB32; + image = image.convertToFormat(format); + + + QImage shouldBe(400, 400, format); + shouldBe.fill(compareColor.rgba()); + + QCOMPARE(image, shouldBe); +} + +void tst_QPixmap::fill_transparent() +{ + QPixmap pixmap(10, 10); +#ifdef Q_WS_X11 + if (pixmap.handle()->classId() == QPlatformPixmap::X11Class && !pixmap.x11PictureHandle()) + QSKIP("Requires XRender support", SkipAll); +#endif + pixmap.fill(Qt::transparent); + QVERIFY(pixmap.hasAlphaChannel()); +} + +void tst_QPixmap::mask() +{ + QPixmap pm(100, 100); + QBitmap bm(100, 100); + + pm.fill(); + bm.fill(); + + QVERIFY(!pm.isNull()); + QVERIFY(!bm.isNull()); + if (!pm.hasAlphaChannel()) { + // This would fail if the default pixmap format is + // argb32_premultiplied. The mask will be all 1's. + // Therefore this is skipped when the alpha channel is present. + QVERIFY(pm.mask().isNull()); + } + + QImage img = bm.toImage(); + QVERIFY(img.format() == QImage::Format_MonoLSB + || img.format() == QImage::Format_Mono); + + pm.setMask(bm); + QVERIFY(!pm.mask().isNull()); + + bm = QBitmap(); + // Invalid format here, since isNull() == true + QVERIFY(bm.toImage().isNull()); + QCOMPARE(bm.toImage().format(), QImage::Format_Invalid); + pm.setMask(bm); + QVERIFY(pm.mask().isNull()); + + bm = QBitmap(100, 100); + bm.fill(); + pm.setMask(bm); + QVERIFY(!pm.mask().isNull()); +} + +void tst_QPixmap::bitmapMask() +{ + QImage image(3, 3, QImage::Format_Mono); + image.setColor(0, Qt::color0); + image.setColor(1, Qt::color1); + image.fill(Qt::color0); + image.setPixel(1, 1, Qt::color1); + image.setPixel(0, 0, Qt::color1); + + QImage image_mask(3, 3, QImage::Format_Mono); + image_mask.setColor(0, Qt::color0); + image_mask.setColor(1, Qt::color1); + image_mask.fill(Qt::color0); + image_mask.setPixel(1, 1, Qt::color1); + image_mask.setPixel(2, 0, Qt::color1); + + QBitmap pm = QBitmap::fromImage(image); + QBitmap pm_mask = QBitmap::fromImage(image_mask); + pm.setMask(pm_mask); + + image = pm.toImage(); + image.setColor(0, Qt::color0); + image.setColor(1, Qt::color1); + image_mask = pm_mask.toImage(); + image_mask.setColor(0, Qt::color0); + image_mask.setColor(1, Qt::color1); + + QVERIFY(!image.pixel(0, 0)); + QVERIFY(!image.pixel(2, 0)); + QVERIFY(image.pixel(1, 1)); +} + +void tst_QPixmap::setGetMask_data() +{ + QTest::addColumn<QPixmap>("pixmap"); + QTest::addColumn<QBitmap>("mask"); + QTest::addColumn<QBitmap>("expected"); + + QPixmap pixmap(10, 10); + QBitmap mask(10, 10); + QPainter p; + + p.begin(&pixmap); + p.fillRect(0, 0, 10, 10, QColor(Qt::black)); + p.end(); + + QTest::newRow("nullmask 0") << QPixmap() << QBitmap() << QBitmap(); + QTest::newRow("nullmask 1") << pixmap << QBitmap() << QBitmap(); + mask.clear(); + QTest::newRow("nullmask 2") << pixmap << mask << mask; + QTest::newRow("nullmask 3") << QPixmap(QBitmap()) << QBitmap() << QBitmap(); + + p.begin(&mask); + p.fillRect(1, 1, 5, 5, QColor(Qt::color1)); + p.end(); + QTest::newRow("simple mask 0") << pixmap << mask << mask; +} + +void tst_QPixmap::setGetMask() +{ + QFETCH(QPixmap, pixmap); + QFETCH(QBitmap, mask); + QFETCH(QBitmap, expected); + + pixmap.setMask(mask); + QBitmap result = pixmap.mask(); + + QImage resultImage = result.toImage(); + QImage expectedImage = expected.toImage(); + QCOMPARE(resultImage.convertToFormat(expectedImage.format()), + expectedImage); +} + +void tst_QPixmap::testMetrics() +{ + QPixmap pixmap(100, 100); + + QCOMPARE(pixmap.width(), 100); + QCOMPARE(pixmap.height(), 100); + QVERIFY(pixmap.depth() >= QPixmap::defaultDepth()); + + QBitmap bitmap(100, 100); + + QCOMPARE(bitmap.width(), 100); + QCOMPARE(bitmap.height(), 100); + QCOMPARE(bitmap.depth(), 1); + + QPixmap null; + + QCOMPARE(null.size().width(), null.width()); + QCOMPARE(null.size().height(), null.height()); +} + +void tst_QPixmap::createMaskFromColor() +{ + QImage image(3, 3, QImage::Format_Indexed8); + image.setColorCount(10); + image.setColor(0, 0xffffffff); + image.setColor(1, 0xff000000); + image.setColor(2, 0xffff0000); + image.setColor(3, 0xff0000ff); + image.fill(0); + image.setPixel(1, 0, 1); + image.setPixel(0, 1, 2); + image.setPixel(1, 1, 3); + + QImage im_mask = image.createMaskFromColor(0xffff0000); + QCOMPARE((uint) im_mask.pixel(0, 1), QColor(Qt::color0).rgba()); + QCOMPARE((uint) im_mask.pixel(0, 1), QColor(Qt::color0).rgba()); + + QPixmap pixmap = QPixmap::fromImage(image); + QBitmap mask = pixmap.createMaskFromColor(Qt::red); + QBitmap inv_mask = pixmap.createMaskFromColor(Qt::red, Qt::MaskOutColor); + QCOMPARE((uint) mask.toImage().pixel(0, 1), QColor(Qt::color0).rgba()); + QCOMPARE((uint) inv_mask.toImage().pixel(0, 1), QColor(Qt::color1).rgba()); +} + + +void tst_QPixmap::cacheKey() +{ + QPixmap pixmap1(1, 1); + QPixmap pixmap2(1, 1); + qint64 pixmap1_key = pixmap1.cacheKey(); + + QVERIFY(pixmap1.cacheKey() != pixmap2.cacheKey()); + + pixmap2 = pixmap1; + QVERIFY(pixmap2.cacheKey() == pixmap1.cacheKey()); + + pixmap2.detach(); + QVERIFY(pixmap2.cacheKey() != pixmap1.cacheKey()); + QVERIFY(pixmap1.cacheKey() == pixmap1_key); +} + +// Test drawing a bitmap on a pixmap. +void tst_QPixmap::drawBitmap() +{ + QBitmap bitmap(10,10); + bitmap.fill(Qt::color1); + + QPixmap pixmap(10,10); + QPainter painter2(&pixmap); + painter2.fillRect(0,0,10,10, QBrush(Qt::green)); + painter2.setPen(Qt::red); + painter2.drawPixmap(0,0,10,10, bitmap); + painter2.end(); + + QPixmap expected(10, 10); + expected.fill(Qt::red); + + QVERIFY(lenientCompare(pixmap, expected)); +} + +void tst_QPixmap::grabWidget() +{ + for (int opaque = 0; opaque < 2; ++opaque) { + QWidget widget; + QImage image(128, 128, opaque ? QImage::Format_RGB32 : QImage::Format_ARGB32_Premultiplied); + for (int row = 0; row < image.height(); ++row) { + QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(row)); + for (int col = 0; col < image.width(); ++col) + line[col] = qRgba(rand() & 255, row, col, opaque ? 255 : 127); + } + + QPalette pal = widget.palette(); + pal.setBrush(QPalette::Window, QBrush(image)); + widget.setPalette(pal); + widget.resize(128, 128); + + QPixmap expected(64, 64); + if (!opaque) + expected.fill(Qt::transparent); + + QPainter p(&expected); + p.translate(-64, -64); + p.drawTiledPixmap(0, 0, 128, 128, pal.brush(QPalette::Window).texture(), 0, 0); + p.end(); + + QPixmap actual = QPixmap::grabWidget(&widget, QRect(64, 64, 64, 64)); + QVERIFY(lenientCompare(actual, expected)); + + actual = QPixmap::grabWidget(&widget, 64, 64); + QVERIFY(lenientCompare(actual, expected)); + + // Make sure a widget that is not yet shown is grabbed correctly. + QTreeWidget widget2; + actual = QPixmap::grabWidget(&widget2); + widget2.show(); + expected = QPixmap::grabWidget(&widget2); + + QVERIFY(lenientCompare(actual, expected)); + } +} + +void tst_QPixmap::grabWindow() +{ +#ifdef Q_WS_QPA + QSKIP("QTBUG-20863 grabWindow is broken on most qpa backends", SkipAll); +#endif +#ifdef Q_OS_WINCE + // We get out of memory, if the desktop itself is too big. + if (QApplication::desktop()->width() <= 480) +#endif + QVERIFY(QPixmap::grabWindow(QApplication::desktop()->winId()).isNull() == false); + QWidget w; + w.resize(640, 480); + w.show(); + QTest::qWait(100); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&w); +#endif + QVERIFY(QPixmap::grabWindow(w.winId()).isNull() == false); + + QWidget child(&w); + child.setGeometry(50, 50, 100, 100); + child.setPalette(Qt::red); + child.setAutoFillBackground(true); + child.show(); + QTest::qWait(100); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&child); +#endif + + QPixmap grabWindowPixmap = QPixmap::grabWindow(child.winId()); + QPixmap grabWidgetPixmap = QPixmap::grabWidget(&child); + lenientCompare(grabWindowPixmap, grabWidgetPixmap); +} + +void tst_QPixmap::isNull() +{ + { + QPixmap pixmap(1,1); + QVERIFY(pixmap.isNull() == false); + } + { + QPixmap pixmap(0,0); + QVERIFY(pixmap.isNull()); + } + + { + QPixmap pixmap(0,1); + QVERIFY(pixmap.isNull()); + } + { + QPixmap pixmap(1,0); + QVERIFY(pixmap.isNull()); + } + { + QPixmap pixmap(-1,-1); + QVERIFY(pixmap.isNull()); + } + { + QPixmap pixmap(-1,5); + QVERIFY(pixmap.isNull()); + } +} + +void tst_QPixmap::convertFromImageNoDetach() +{ + QPixmap randomPixmap(10, 10); + if (randomPixmap.handle()->classId() != QPlatformPixmap::RasterClass) + QSKIP("Test only valid for raster pixmaps", SkipAll); + + //first get the screen format + QImage::Format screenFormat = randomPixmap.toImage().format(); + QVERIFY(screenFormat != QImage::Format_Invalid); + + QImage orig(100,100, screenFormat); + + QPixmap pix = QPixmap::fromImage(orig); + QImage copy = pix.toImage(); + + QVERIFY(copy.format() == screenFormat); + + const QImage constOrig = orig; + const QImage constCopy = copy; + QVERIFY(constOrig.bits() == constCopy.bits()); +} + +void tst_QPixmap::convertFromImageDetach() +{ + QImage img(10,10, QImage::Format_RGB32); + img.fill(0); + QVERIFY(!img.isNull()); + QPixmap p = QPixmap::fromImage(img); + QVERIFY(p.isDetached()); + QPixmap copy = p; + QVERIFY(!copy.isDetached()); + QVERIFY(!p.isDetached()); + img.fill(1); + p = QPixmap::fromImage(img); + QVERIFY(copy.isDetached()); +} + +#if defined(Q_WS_WIN) +void tst_QPixmap::toWinHBITMAP_data() +{ + QTest::addColumn<int>("red"); + QTest::addColumn<int>("green"); + QTest::addColumn<int>("blue"); + + QTest::newRow("red") << 255 << 0 << 0; + QTest::newRow("green") << 0 << 255 << 0; + QTest::newRow("blue") << 0 << 0 << 255; +} + +void tst_QPixmap::toWinHBITMAP() +{ + QFETCH(int, red); + QFETCH(int, green); + QFETCH(int, blue); + + QPixmap pm(100, 100); + pm.fill(QColor(red, green, blue)); + + HBITMAP bitmap = pm.toWinHBITMAP(); + + QVERIFY(bitmap != 0); + + // Verify size + BITMAP bitmap_info; + memset(&bitmap_info, 0, sizeof(BITMAP)); + + int res = GetObject(bitmap, sizeof(BITMAP), &bitmap_info); + QVERIFY(res); + + QCOMPARE(100, (int) bitmap_info.bmWidth); + QCOMPARE(100, (int) bitmap_info.bmHeight); + + HDC display_dc = GetDC(0); + HDC bitmap_dc = CreateCompatibleDC(display_dc); + + HBITMAP null_bitmap = (HBITMAP) SelectObject(bitmap_dc, bitmap); + + COLORREF pixel = GetPixel(bitmap_dc, 0, 0); + QCOMPARE((int)GetRValue(pixel), red); + QCOMPARE((int)GetGValue(pixel), green); + QCOMPARE((int)GetBValue(pixel), blue); + + // Clean up + SelectObject(bitmap_dc, null_bitmap); + DeleteObject(bitmap); + DeleteDC(bitmap_dc); + ReleaseDC(0, display_dc); + +} + +void tst_QPixmap::fromWinHBITMAP_data() +{ + toWinHBITMAP_data(); +} + +void tst_QPixmap::fromWinHBITMAP() +{ + QFETCH(int, red); + QFETCH(int, green); + QFETCH(int, blue); + + HDC display_dc = GetDC(0); + HDC bitmap_dc = CreateCompatibleDC(display_dc); + HBITMAP bitmap = CreateCompatibleBitmap(display_dc, 100, 100); + SelectObject(bitmap_dc, bitmap); + + SelectObject(bitmap_dc, GetStockObject(NULL_PEN)); + HGDIOBJ old_brush = SelectObject(bitmap_dc, CreateSolidBrush(RGB(red, green, blue))); + Rectangle(bitmap_dc, 0, 0, 100, 100); + +#ifdef Q_OS_WINCE //the device context has to be deleted before QPixmap::fromWinHBITMAP() + DeleteDC(bitmap_dc); +#endif + QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap); + QCOMPARE(pixmap.width(), 100); + QCOMPARE(pixmap.height(), 100); + + QImage image = pixmap.toImage(); + QRgb pixel = image.pixel(0, 0); + QCOMPARE(qRed(pixel), red); + QCOMPARE(qGreen(pixel), green); + QCOMPARE(qBlue(pixel), blue); + + DeleteObject(SelectObject(bitmap_dc, old_brush)); + DeleteObject(SelectObject(bitmap_dc, bitmap)); +#ifndef Q_OS_WINCE + DeleteDC(bitmap_dc); +#endif + ReleaseDC(0, display_dc); +} + +static void compareImages(const QImage &image1, const QImage &image2) +{ + QCOMPARE(image1.width(), image2.width()); + QCOMPARE(image1.height(), image2.height()); + QCOMPARE(image1.format(), image2.format()); + + static const int fuzz = 1; + + for (int y = 0; y < image1.height(); y++) + { + for (int x = 0; x < image2.width(); x++) + { + QRgb p1 = image1.pixel(x, y); + QRgb p2 = image2.pixel(x, y); + + bool pixelMatches = + qAbs(qRed(p1) - qRed(p2)) <= fuzz + && qAbs(qGreen(p1) - qGreen(p2)) <= fuzz + && qAbs(qBlue(p1) - qBlue(p2)) <= fuzz + && qAbs(qAlpha(p1) - qAlpha(p2)) <= fuzz; + + QVERIFY(pixelMatches); + } + } +} + +void tst_QPixmap::toWinHICON_data() +{ + QTest::addColumn<QString>("image"); + QTest::addColumn<int>("width"); + QTest::addColumn<int>("height"); + + const QString prefix = QLatin1String(SRCDIR) + "/convertFromToHICON"; + + QTest::newRow("32bpp_16x16") << prefix + QLatin1String("/icon_32bpp") << 16 << 16; + QTest::newRow("32bpp_32x32") << prefix + QLatin1String("/icon_32bpp") << 32 << 32; + QTest::newRow("32bpp_48x48") << prefix + QLatin1String("/icon_32bpp") << 48 << 48; + QTest::newRow("32bpp_256x256") << prefix + QLatin1String("/icon_32bpp") << 256 << 256; + + QTest::newRow("8bpp_16x16") << prefix + QLatin1String("/icon_8bpp") << 16 << 16; + QTest::newRow("8bpp_32x32") << prefix + QLatin1String("/icon_8bpp") << 32 << 32; + QTest::newRow("8bpp_48x48") << prefix + QLatin1String("/icon_8bpp") << 48 << 48; +} + +void tst_QPixmap::toWinHICON() +{ +#ifdef Q_OS_WINCE + QSKIP("Test shall be enabled for Windows CE shortly.", SkipAll); +#endif + + QFETCH(int, width); + QFETCH(int, height); + QFETCH(QString, image); + + QPixmap empty(width, height); + empty.fill(Qt::transparent); + + HDC display_dc = GetDC(0); + HDC bitmap_dc = CreateCompatibleDC(display_dc); + HBITMAP bitmap = empty.toWinHBITMAP(QPixmap::Alpha); + SelectObject(bitmap_dc, bitmap); + + QImage imageFromFile(image + QString(QLatin1String("_%1x%2.png")).arg(width).arg(height)); + imageFromFile = imageFromFile.convertToFormat(QImage::Format_ARGB32_Premultiplied); + + HICON icon = QPixmap::fromImage(imageFromFile).toWinHICON(); + + DrawIconEx(bitmap_dc, 0, 0, icon, width, height, 0, 0, DI_NORMAL); + + DestroyIcon(icon); + DeleteDC(bitmap_dc); + + QImage imageFromHICON = QPixmap::fromWinHBITMAP(bitmap, QPixmap::Alpha).toImage(); + + ReleaseDC(0, display_dc); + + // fuzzy comparison must be used, as the pixel values change slightly during conversion + // between QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied, or elsewhere + + // QVERIFY(imageFromHICON == imageFromFile); + compareImages(imageFromHICON, imageFromFile); +} + +void tst_QPixmap::fromWinHICON_data() +{ + toWinHICON_data(); +} + +void tst_QPixmap::fromWinHICON() +{ +#ifdef Q_OS_WINCE + QSKIP("Test shall be enabled for Windows CE shortly.", SkipAll); + +#else + QFETCH(int, width); + QFETCH(int, height); + QFETCH(QString, image); + + HICON icon = (HICON)LoadImage(0, (wchar_t*)(image + QLatin1String(".ico")).utf16(), IMAGE_ICON, width, height, LR_LOADFROMFILE); + QImage imageFromHICON = QPixmap::fromWinHICON(icon).toImage(); + DestroyIcon(icon); + + QImage imageFromFile(image + QString(QLatin1String("_%1x%2.png")).arg(width).arg(height)); + imageFromFile = imageFromFile.convertToFormat(QImage::Format_ARGB32_Premultiplied); + + // fuzzy comparison must be used, as the pixel values change slightly during conversion + // between QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied, or elsewhere + + // QVERIFY(imageFromHICON == imageFromFile); + compareImages(imageFromHICON, imageFromFile); +#endif +} + +#endif // Q_WS_WIN + +#if defined(Q_OS_SYMBIAN) +Q_DECLARE_METATYPE(TDisplayMode) + +void tst_QPixmap::fromSymbianCFbsBitmap_data() +{ + QTest::addColumn<TDisplayMode>("format"); + QTest::addColumn<int>("width"); + QTest::addColumn<int>("height"); + QTest::addColumn<QColor>("color"); + + const int smallWidth = 20; + const int smallHeight = 20; + const int largeWidth = 240; + const int largeHeight = 320; + const int notAlignedWidth = 250; + const int notAlignedHeight = 250; + + // Indexed Color Formats - Disabled since images seem to be blank -> no palette? +// QTest::newRow("EGray2 small") << EGray2 << smallWidth << smallHeight << QColor(Qt::black); +// QTest::newRow("EGray2 big") << EGray2 << largeWidth << largeHeight << QColor(Qt::black); +// QTest::newRow("EGray256 small") << EGray256 << smallWidth << smallHeight << QColor(Qt::blue); +// QTest::newRow("EGray256 big") << EGray256 << largeWidth << largeHeight << QColor(Qt::blue); +// QTest::newRow("EColor256 small") << EColor256 << smallWidth << smallHeight << QColor(Qt::red); +// QTest::newRow("EColor256 big") << EColor256 << largeWidth << largeHeight << QColor(Qt::red); + + // Direct Color Formats + QTest::newRow("EColor4K small") << EColor4K << smallWidth << smallHeight << QColor(Qt::red); + QTest::newRow("EColor4K big") << EColor4K << largeWidth << largeHeight << QColor(Qt::red); + QTest::newRow("EColor4K not aligned") << EColor4K << notAlignedWidth << notAlignedHeight << QColor(Qt::red); + QTest::newRow("EColor64K small") << EColor64K << smallWidth << smallHeight << QColor(Qt::green); + QTest::newRow("EColor64K big") << EColor64K << largeWidth << largeHeight << QColor(Qt::green); + QTest::newRow("EColor64K not aligned") << EColor64K << notAlignedWidth << notAlignedHeight << QColor(Qt::green); + QTest::newRow("EColor16M small") << EColor16M << smallWidth << smallHeight << QColor(Qt::yellow); + QTest::newRow("EColor16M big") << EColor16M << largeWidth << largeHeight << QColor(Qt::yellow); + QTest::newRow("EColor16M not aligned") << EColor16M << notAlignedWidth << notAlignedHeight << QColor(Qt::yellow); + QTest::newRow("EColor16MU small") << EColor16MU << smallWidth << smallHeight << QColor(Qt::red); + QTest::newRow("EColor16MU big") << EColor16MU << largeWidth << largeHeight << QColor(Qt::red); + QTest::newRow("EColor16MU not aligned") << EColor16MU << notAlignedWidth << notAlignedHeight << QColor(Qt::red); + QTest::newRow("EColor16MA small opaque") << EColor16MA << smallWidth << smallHeight << QColor(255, 255, 0); + QTest::newRow("EColor16MA big opaque") << EColor16MA << largeWidth << largeHeight << QColor(255, 255, 0); + QTest::newRow("EColor16MA not aligned opaque") << EColor16MA << notAlignedWidth << notAlignedHeight << QColor(255, 255, 0); + + // Semi-transparent Colors - Disabled for now, since the QCOMPARE fails, but visually confirmed to work +// QTest::newRow("EColor16MA small semi") << EColor16MA << smallWidth << smallHeight << QColor(255, 255, 0, 127); +// QTest::newRow("EColor16MA big semi") << EColor16MA << largeWidth << largeHeight << QColor(255, 255, 0, 127); +// QTest::newRow("EColor16MA small trans") << EColor16MA << smallWidth << smallHeight << QColor(255, 255, 0, 0); +// QTest::newRow("EColor16MA big trans") << EColor16MA << largeWidth << largeHeight << QColor(255, 255, 0, 0); + +#if !defined(__SERIES60_31__) + QTest::newRow("EColor16MAP small") << EColor16MAP << smallWidth << smallHeight << QColor(Qt::red); + QTest::newRow("EColor16MAP big") << EColor16MAP << largeWidth << largeHeight << QColor(Qt::red); +#endif +} + +void tst_QPixmap::fromSymbianCFbsBitmap() +{ + QFETCH(TDisplayMode, format); + QFETCH(int, width); + QFETCH(int, height); + QFETCH(QColor, color); + int expectedDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(format); + + CFbsBitmap *nativeBitmap = 0; + CFbsBitmapDevice *bitmapDevice = 0; + CBitmapContext *bitmapContext = 0; + + nativeBitmap = new (ELeave) CFbsBitmap(); + TInt err = nativeBitmap->Create(TSize(width, height), format); + CleanupStack::PushL(nativeBitmap); + QVERIFY(err == KErrNone); + bitmapDevice = CFbsBitmapDevice::NewL(nativeBitmap); + CleanupStack::PushL(bitmapDevice); + + err = bitmapDevice->CreateBitmapContext(bitmapContext); + CleanupStack::PushL(bitmapContext); + QVERIFY(err == KErrNone); + TRgb symbianColor = TRgb(color.red(), color.green(), color.blue(), color.alpha()); + bitmapContext->SetBrushColor(symbianColor); + bitmapContext->Clear(); + + __UHEAP_MARK; + { // Test the null case + CFbsBitmap *bitmap = 0; + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(bitmap); + QVERIFY(pixmap.isNull()); + } + __UHEAP_MARKEND; + + __UHEAP_MARK; + { // Test the normal case + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(nativeBitmap); +// QCOMPARE(pixmap.depth(), expectedDepth); // Depth is not preserved now + QCOMPARE(pixmap.width(), width); + QCOMPARE(pixmap.height(), height); + QImage image = pixmap.toImage(); + + QColor actualColor(image.pixel(1, 1)); + QCOMPARE(actualColor, color); + + QImage shouldBe(pixmap.width(), pixmap.height(), image.format()); + if (image.format() == QImage::Format_RGB16) + shouldBe.fill(qrgb565(color.rgba()).rawValue()); + else + shouldBe.fill(color.rgba()); + QCOMPARE(image, shouldBe); + } + __UHEAP_MARKEND; + + CleanupStack::PopAndDestroy(3); +} + +void tst_QPixmap::toSymbianCFbsBitmap_data() +{ + QTest::addColumn<int>("red"); + QTest::addColumn<int>("green"); + QTest::addColumn<int>("blue"); + + QTest::newRow("red") << 255 << 0 << 0; + QTest::newRow("green") << 0 << 255 << 0; + QTest::newRow("blue") << 0 << 0 << 255; +} + +void tst_QPixmap::toSymbianCFbsBitmap() +{ + QFETCH(int, red); + QFETCH(int, green); + QFETCH(int, blue); + + QPixmap pm(100, 100); + pm.fill(QColor(red, green, blue)); + + CFbsBitmap *bitmap = pm.toSymbianCFbsBitmap(); + + QVERIFY(bitmap != 0); + + // Verify size + QCOMPARE(100, (int) bitmap->SizeInPixels().iWidth); + QCOMPARE(100, (int) bitmap->SizeInPixels().iHeight); + + // Verify pixel color + TRgb pixel; + bitmap->GetPixel(pixel, TPoint(0,0)); + QCOMPARE((int)pixel.Red(), red); + QCOMPARE((int)pixel.Green(), green); + QCOMPARE((int)pixel.Blue(), blue); + + // Clean up + delete bitmap; +} +#endif + +void tst_QPixmap::onlyNullPixmapsOutsideGuiThread() +{ +#ifdef Q_WS_QPA + QSKIP("QTBUG-20864 can't determine if threaded pixmaps are available for qpa", SkipAll); +#endif +#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) + class Thread : public QThread + { + public: + void run() + { + QTest::ignoreMessage(QtWarningMsg, + "QPixmap: It is not safe to use pixmaps outside the GUI thread"); + QPixmap pixmap; + QVERIFY(pixmap.isNull()); + + QTest::ignoreMessage(QtWarningMsg, + "QPixmap: It is not safe to use pixmaps outside the GUI thread"); + QPixmap pixmap1(100, 100); + QVERIFY(pixmap1.isNull()); + + QTest::ignoreMessage(QtWarningMsg, + "QPixmap: It is not safe to use pixmaps outside the GUI thread"); + QPixmap pixmap2(pixmap1); + QVERIFY(pixmap2.isNull()); + } + }; + Thread thread; +#if defined(Q_OS_SYMBIAN) + thread.setStackSize(0x10000); +#endif + thread.start(); +#if defined(Q_OS_SYMBIAN) + QVERIFY(thread.wait(10000)); +#else + thread.wait(); +#endif + +#endif // !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +} + +void tst_QPixmap::refUnref() +{ + // Simple ref/unref + { + QPixmap p; + } + { + QBitmap b; + } + + // Get a copy of a pixmap that goes out of scope + { + QPixmap b; + { + QPixmap a(10, 10); + a.fill(Qt::color0); + b = a; + } + } + { + QBitmap mask; + { + QBitmap bitmap(10, 10); + bitmap.fill(Qt::color1); + mask = bitmap.mask(); + } + mask.fill(Qt::color0); + } + +} + +void tst_QPixmap::copy() +{ + QPixmap src(32, 32); + { + QPainter p(&src); + p.fillRect(0, 0, 32, 32, Qt::red); + p.fillRect(10, 10, 10, 10, Qt::blue); + } + + QPixmap dest = src.copy(10, 10, 10, 10); + + QPixmap expected(10, 10); + expected.fill(Qt::blue); + QVERIFY(lenientCompare(dest, expected)); + + QPixmap trans; + trans.fill(Qt::transparent); + + QPixmap transCopy = trans.copy(); + QVERIFY(pixmapsAreEqual(&trans, &transCopy)); +} + +void tst_QPixmap::depthOfNullObjects() +{ + QBitmap b1; + QVERIFY(b1.depth() == 0); + QPixmap p4; + QVERIFY(p4.depth() == 0); +} + +void tst_QPixmap::transformed() +{ + QPixmap p1(20, 10); + p1.fill(Qt::red); + { + QPainter p(&p1); + p.drawRect(0, 0, p1.width() - 1, p1.height() - 1); + } + + QPixmap p2(10, 20); + { + QPainter p(&p2); + p.rotate(90); + p.drawPixmap(0, -p1.height(), p1); + } + + QPixmap p3(20, 10); + { + QPainter p(&p3); + p.rotate(180); + p.drawPixmap(-p1.width(), -p1.height(), p1); + } + + QPixmap p4(10, 20); + { + QPainter p(&p4); + p.rotate(270); + p.drawPixmap(-p1.width(), 0, p1); + } + + QPixmap p1_90 = p1.transformed(QTransform().rotate(90)); + QPixmap p1_180 = p1.transformed(QTransform().rotate(180)); + QPixmap p1_270 = p1.transformed(QTransform().rotate(270)); + + QVERIFY(lenientCompare(p1_90, p2)); + QVERIFY(lenientCompare(p1_180, p3)); + QVERIFY(lenientCompare(p1_270, p4)); +} + +void tst_QPixmap::transformed2() +{ + QPixmap pm(3, 3); + pm.fill(Qt::red); + QPainter p(&pm); + p.fillRect(0, 0, 3, 3, QBrush(Qt::Dense4Pattern)); + p.end(); + + QTransform transform; + transform.rotate(-90); + transform.scale(3, 3); + + QPixmap actual = pm.transformed(transform); + + QPixmap expected(9, 9); + expected.fill(Qt::red); + p.begin(&expected); + p.setBrush(Qt::black); + p.setPen(Qt::NoPen); + p.drawRect(3, 0, 3, 3); + p.drawRect(0, 3, 3, 3); + p.drawRect(6, 3, 3, 3); + p.drawRect(3, 6, 3, 3); + p.end(); + + QVERIFY(lenientCompare(actual, expected)); +} + +void tst_QPixmap::fromImage_crash() +{ + QImage *img = new QImage(64, 64, QImage::Format_ARGB32_Premultiplied); + + QPixmap pm = QPixmap::fromImage(*img); + QPainter painter(&pm); + + delete img; +} + +//This is testing QPlatformPixmap::createCompatiblePlatformPixmap - see QTBUG-5977 +void tst_QPixmap::splash_crash() +{ + QPixmap pix; + pix = QPixmap(":/images/designer.png"); + QSplashScreen splash(pix); + splash.show(); + QCoreApplication::processEvents(); + splash.close(); +} + +void tst_QPixmap::fromData() +{ + unsigned char bits[] = { 0xaa, 0x55 }; + + QBitmap bm = QBitmap::fromData(QSize(8, 2), bits); + QImage img = bm.toImage(); + + QSet<QRgb> colors; + for (int y = 0; y < img.height(); ++y) + for (int x = 0; x < img.width(); ++x) + colors << img.pixel(x, y); + + QCOMPARE(colors.size(), 2); + + QCOMPARE(img.pixel(0, 0), QRgb(0xffffffff)); + QCOMPARE(img.pixel(0, 1), QRgb(0xff000000)); +} + +void tst_QPixmap::loadFromDataNullValues() +{ + { + QPixmap pixmap; + pixmap.loadFromData(QByteArray()); + QVERIFY(pixmap.isNull()); + } + { + QPixmap pixmap; + pixmap.loadFromData(0, 123); + QVERIFY(pixmap.isNull()); + } + { + QPixmap pixmap; + const uchar bla[] = "bla"; + pixmap.loadFromData(bla, 0); + QVERIFY(pixmap.isNull()); + } +} + +void tst_QPixmap::loadFromDataImage_data() +{ + QTest::addColumn<QString>("imagePath"); +#ifdef Q_OS_SYMBIAN + const QString prefix = QLatin1String(SRCDIR) + "loadFromData"; +#else + const QString prefix = QLatin1String(SRCDIR) + "/loadFromData"; +#endif + QTest::newRow("designer_argb32.png") << prefix + "/designer_argb32.png"; + // When no extension is provided we try all extensions that has been registered by image providers + QTest::newRow("designer_argb32") << prefix + "/designer_argb32.png"; + QTest::newRow("designer_indexed8_no_alpha.png") << prefix + "/designer_indexed8_no_alpha.png"; + QTest::newRow("designer_indexed8_with_alpha.png") << prefix + "/designer_indexed8_with_alpha.png"; + QTest::newRow("designer_rgb32.png") << prefix + "/designer_rgb32.png"; + QTest::newRow("designer_indexed8_no_alpha.gif") << prefix + "/designer_indexed8_no_alpha.gif"; + QTest::newRow("designer_indexed8_with_alpha.gif") << prefix + "/designer_indexed8_with_alpha.gif"; + QTest::newRow("designer_rgb32.jpg") << prefix + "/designer_rgb32.jpg"; +} + +void tst_QPixmap::loadFromDataImage() +{ + QFETCH(QString, imagePath); + + QImage imageRef(imagePath); + QPixmap pixmapWithCopy = QPixmap::fromImage(imageRef); + + QFile file(imagePath); + file.open(QIODevice::ReadOnly); + QByteArray rawData = file.readAll(); + + QPixmap directLoadingPixmap; + directLoadingPixmap.loadFromData(rawData); + + QVERIFY(pixmapsAreEqual(&pixmapWithCopy, &directLoadingPixmap)); +} + +void tst_QPixmap::fromImageReader_data() +{ + QTest::addColumn<QString>("imagePath"); +#ifdef Q_OS_SYMBIAN + const QString prefix = QLatin1String(SRCDIR) + "loadFromData"; +#else + const QString prefix = QLatin1String(SRCDIR) + "/loadFromData"; +#endif + QTest::newRow("designer_argb32.png") << prefix + "/designer_argb32.png"; + QTest::newRow("designer_indexed8_no_alpha.png") << prefix + "/designer_indexed8_no_alpha.png"; + QTest::newRow("designer_indexed8_with_alpha.png") << prefix + "/designer_indexed8_with_alpha.png"; + QTest::newRow("designer_rgb32.png") << prefix + "/designer_rgb32.png"; + QTest::newRow("designer_indexed8_no_alpha.gif") << prefix + "/designer_indexed8_no_alpha.gif"; + QTest::newRow("designer_indexed8_with_alpha.gif") << prefix + "/designer_indexed8_with_alpha.gif"; + QTest::newRow("designer_rgb32.jpg") << prefix + "/designer_rgb32.jpg"; + QTest::newRow("designer_indexed8_with_alpha_animated") << prefix + "/designer_indexed8_with_alpha_animated.gif"; + QTest::newRow("designer_indexed8_with_alpha_animated") << prefix + "/designer_indexed8_no_alpha_animated.gif"; +} + +void tst_QPixmap::fromImageReader() +{ + QFETCH(QString, imagePath); + + QImage imageRef(imagePath); + QPixmap pixmapWithCopy = QPixmap::fromImage(imageRef); + + QImageReader imageReader(imagePath); + + QPixmap directLoadingPixmap = QPixmap::fromImageReader(&imageReader); + + QVERIFY(pixmapsAreEqual(&pixmapWithCopy, &directLoadingPixmap)); +} + +void tst_QPixmap::fromImageReaderAnimatedGif_data() +{ + QTest::addColumn<QString>("imagePath"); + QTest::newRow("gif with alpha") << QString::fromLatin1("/designer_indexed8_with_alpha_animated.gif"); + QTest::newRow("gif without alpha") << QString::fromLatin1("/designer_indexed8_no_alpha_animated.gif"); +} + +void tst_QPixmap::fromImageReaderAnimatedGif() +{ + QFETCH(QString, imagePath); +#ifdef Q_OS_SYMBIAN + const QString prefix = QLatin1String(SRCDIR) + "loadFromData"; +#else + const QString prefix = QLatin1String(SRCDIR) + "/loadFromData"; +#endif + const QString path = prefix + imagePath; + + QImageReader referenceReader(path); + QImageReader pixmapReader(path); + + QVERIFY(referenceReader.canRead()); + QVERIFY(referenceReader.imageCount() > 1); + + for (int i = 0; i < referenceReader.imageCount(); ++i) { + QImage refImage = referenceReader.read(); + QPixmap refPixmap = QPixmap::fromImage(refImage); + + QPixmap directLoadingPixmap = QPixmap::fromImageReader(&pixmapReader); + QVERIFY(pixmapsAreEqual(&refPixmap, &directLoadingPixmap)); + } +} + +void tst_QPixmap::task_246446() +{ + // This crashed without the bugfix in 246446 + QPixmap pm(10, 10); + pm.fill(Qt::transparent); // force 32-bit depth + QBitmap bm; + pm.setMask(bm); + { + QPixmap pm2(pm); + } + QVERIFY(pm.width() == 10); + QVERIFY(pm.mask().isNull()); +} + +void tst_QPixmap::preserveDepth() +{ + QPixmap target(64, 64); + target.fill(Qt::transparent); + + QPixmap source(64, 64); + source.fill(Qt::white); + + int depth = source.depth(); + + QPainter painter(&target); + painter.setBrush(source); + painter.drawRect(target.rect()); + painter.end(); + + QCOMPARE(depth, source.depth()); +} + +void tst_QPixmap::loadAsBitmapOrPixmap() +{ + QImage tmp(10, 10, QImage::Format_RGB32); + tmp.save("temp_image.png"); + + bool ok; + + // Check that we can load the pixmap as a pixmap and that it then turns into a pixmap + QPixmap pixmap("temp_image.png"); + QVERIFY(!pixmap.isNull()); + QVERIFY(pixmap.depth() > 1); + QVERIFY(!pixmap.isQBitmap()); + + pixmap = QPixmap(); + ok = pixmap.load("temp_image.png"); + QVERIFY(ok); + QVERIFY(!pixmap.isNull()); + QVERIFY(pixmap.depth() > 1); + QVERIFY(!pixmap.isQBitmap()); + + //now we can try to load it without an extension + pixmap = QPixmap(); + ok = pixmap.load("temp_image"); + QVERIFY(ok); + QVERIFY(!pixmap.isNull()); + QVERIFY(pixmap.depth() > 1); + QVERIFY(!pixmap.isQBitmap()); + + // The do the same check for bitmaps.. + QBitmap bitmap("temp_image.png"); + QVERIFY(!bitmap.isNull()); + QVERIFY(bitmap.depth() == 1); + QVERIFY(bitmap.isQBitmap()); + + bitmap = QBitmap(); + ok = bitmap.load("temp_image.png"); + QVERIFY(ok); + QVERIFY(!bitmap.isNull()); + QVERIFY(bitmap.depth() == 1); + QVERIFY(bitmap.isQBitmap()); +} + +void tst_QPixmap::toImageDeepCopy() +{ + QPixmap pixmap(64, 64); + pixmap.fill(Qt::white); + + QPainter painter(&pixmap); + QImage first = pixmap.toImage(); + + painter.setBrush(Qt::black); + painter.drawEllipse(pixmap.rect()); + + QImage second = pixmap.toImage(); + + QVERIFY(first != second); +} + +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_OPENVG) +Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap& pixmap); +class FriendlyVGPlatformPixmap : public QVGPlatformPixmap +{ +public: + FriendlyVGPlatformPixmap(PixelType type) : QVGPlatformPixmap(type) { } + bool sourceIsNull() { return source.isNull(); } + friend QPixmap pixmapFromVGImage(VGImage image); +}; +QPixmap pixmapFromVGImage(VGImage image) +{ + if (image != VG_INVALID_HANDLE) { + int w = vgGetParameteri(image, VG_IMAGE_WIDTH); + int h = vgGetParameteri(image, VG_IMAGE_HEIGHT); + FriendlyVGPlatformPixmap *pd = new FriendlyVGPlatformPixmap(QPlatformPixmap::PixmapType); + pd->resize(w, h); + pd->vgImage = image; + pd->recreate = false; + pd->prevSize = QSize(pd->w, pd->h); + return QPixmap(pd); + } + return QPixmap(); +} +class Content : public QWidget +{ +public: + void paintEvent(QPaintEvent *) { + QPainter painter(this); + QColor testPixel(qRgb(200, 150, 100)); + if (pm.isNull()) { // first phase: create a VGImage + painter.beginNativePainting(); + vgimage = vgCreateImage(VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + QImage img(20, 10, QImage::Format_ARGB32_Premultiplied); + img.fill(qRgb(0, 0, 0)); + QPainter p(&img); + p.fillRect(0, 0, img.width(), img.height(), testPixel); + p.end(); + vgImageSubData(vgimage, img.bits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); + // Now the area 0,0 20x10 (in OpenVG coords) is filled with some color. + painter.endNativePainting(); + } else { // second phase: check if readback works + painter.drawPixmap(0, 0, pm); + // Drawing should not cause readback, this is important for performance; + noreadback_ok = static_cast<FriendlyVGPlatformPixmap *>(pm.handle())->sourceIsNull(); + // However toImage() requires readback. + QImage img = pm.toImage(); + readback_ok = img.width() == pm.width(); + readback_ok &= img.height() == pm.height(); + readback_ok &= !static_cast<FriendlyVGPlatformPixmap *>(pm.handle())->sourceIsNull(); + uint pix = img.pixel(1, 1); + content_ok = qRed(pix) == testPixel.red(); + content_ok &= qGreen(pix) == testPixel.green(); + content_ok &= qBlue(pix) == testPixel.blue(); + pix = img.pixel(img.width() - 1, img.height() - 1); + content_ok &= qRed(pix) == 0; + content_ok &= qGreen(pix) == 0; + content_ok &= qBlue(pix) == 0; + } + } + int w; + int h; + VGImage vgimage; + QPixmap pm; + bool noreadback_ok; + bool readback_ok; + bool content_ok; +}; +void tst_QPixmap::vgImageReadBack() +{ + QPixmap tmp(10, 20); + if (tmp.handle()->classId() == QPlatformPixmap::OpenVGClass) { + Content c; + c.w = 50; + c.h = 60; + c.vgimage = VG_INVALID_HANDLE; + c.noreadback_ok = c.readback_ok = c.content_ok = false; + c.showFullScreen(); + QTest::qWaitForWindowShown(&c); + QVERIFY(c.vgimage != VG_INVALID_HANDLE); + QPixmap pm = pixmapFromVGImage(c.vgimage); + QVERIFY(!pm.isNull()); + QCOMPARE(pm.width(), c.w); + QCOMPARE(pm.height(), c.h); + QVERIFY(qPixmapToVGImage(pm) == c.vgimage); + QVERIFY(static_cast<FriendlyVGPlatformPixmap *>(pm.handle())->sourceIsNull()); + c.pm = pm; + // Make sure the second phase in paintEvent is executed too. + c.hide(); + c.showFullScreen(); + QTest::qWaitForWindowShown(&c); + QVERIFY(c.noreadback_ok); + QVERIFY(c.readback_ok); + QVERIFY(c.content_ok); + } else { + QSKIP("Not using openvg graphicssystem", SkipSingle); + } +} +#endif // Symbian & OpenVG + +void tst_QPixmap::scaled_QTBUG19157() +{ + QPixmap foo(5000, 1); + foo = foo.scaled(1024, 1024, Qt::KeepAspectRatio); + QVERIFY(!foo.isNull()); +} + +QTEST_MAIN(tst_QPixmap) +#include "tst_qpixmap.moc" diff --git a/tests/auto/gui/image/qpixmapcache/.gitignore b/tests/auto/gui/image/qpixmapcache/.gitignore new file mode 100644 index 0000000000..2bc572c2dd --- /dev/null +++ b/tests/auto/gui/image/qpixmapcache/.gitignore @@ -0,0 +1 @@ +tst_qpixmapcache diff --git a/tests/auto/gui/image/qpixmapcache/qpixmapcache.pro b/tests/auto/gui/image/qpixmapcache/qpixmapcache.pro new file mode 100644 index 0000000000..1ffafd6c25 --- /dev/null +++ b/tests/auto/gui/image/qpixmapcache/qpixmapcache.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += gui-private +SOURCES += tst_qpixmapcache.cpp + + + diff --git a/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp b/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp new file mode 100644 index 0000000000..9f7192dc1c --- /dev/null +++ b/tests/auto/gui/image/qpixmapcache/tst_qpixmapcache.cpp @@ -0,0 +1,521 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define Q_TEST_QPIXMAPCACHE + +#include <QtTest/QtTest> + + +#include <qpixmapcache.h> +#include "../../../src/gui/image/qpixmapcache_p.h" + + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPixmapCache : public QObject +{ + Q_OBJECT + +public: + tst_QPixmapCache(); + virtual ~tst_QPixmapCache(); + + +public slots: + void init(); +private slots: + void cacheLimit(); + void setCacheLimit(); + void find(); + void insert(); + void replace(); + void remove(); + void clear(); + void pixmapKey(); + void noLeak(); +}; + +static QPixmapCache::KeyData* getPrivate(QPixmapCache::Key &key) +{ + return (*reinterpret_cast<QPixmapCache::KeyData**>(&key)); +} + +static QPixmapCache::KeyData** getPrivateRef(QPixmapCache::Key &key) +{ + return (reinterpret_cast<QPixmapCache::KeyData**>(&key)); +} + +static int originalCacheLimit; + +tst_QPixmapCache::tst_QPixmapCache() +{ + originalCacheLimit = QPixmapCache::cacheLimit(); +} + +tst_QPixmapCache::~tst_QPixmapCache() +{ +} + +void tst_QPixmapCache::init() +{ + QPixmapCache::setCacheLimit(originalCacheLimit); + QPixmapCache::clear(); +} + +void tst_QPixmapCache::cacheLimit() +{ + // make sure the default is reasonable; + // it was between 2048 and 10240 last time I looked at it + QVERIFY(originalCacheLimit >= 1024 && originalCacheLimit <= 20480); + + QPixmapCache::setCacheLimit(100); + QCOMPARE(QPixmapCache::cacheLimit(), 100); + + QPixmapCache::setCacheLimit(-50); + QCOMPARE(QPixmapCache::cacheLimit(), -50); +} + +void tst_QPixmapCache::setCacheLimit() +{ + QPixmap *p1 = new QPixmap(2, 3); + QPixmapCache::insert("P1", *p1); + QVERIFY(QPixmapCache::find("P1") != 0); + delete p1; + + QPixmapCache::setCacheLimit(0); + QVERIFY(QPixmapCache::find("P1") == 0); + + p1 = new QPixmap(2, 3); + QPixmapCache::setCacheLimit(1000); + QPixmapCache::insert("P1", *p1); + QVERIFY(QPixmapCache::find("P1") != 0); + + delete p1; + + //The int part of the API + p1 = new QPixmap(2, 3); + QPixmapCache::Key key = QPixmapCache::insert(*p1); + QVERIFY(QPixmapCache::find(key, p1) != 0); + delete p1; + + QPixmapCache::setCacheLimit(0); + QVERIFY(QPixmapCache::find(key, p1) == 0); + + p1 = new QPixmap(2, 3); + QPixmapCache::setCacheLimit(1000); + QPixmapCache::replace(key, *p1); + QVERIFY(QPixmapCache::find(key, p1) == 0); + + delete p1; + + //Let check if keys are released when the pixmap cache is + //full or has been flushed. + QPixmapCache::clear(); + p1 = new QPixmap(2, 3); + key = QPixmapCache::insert(*p1); + QVERIFY(QPixmapCache::find(key, p1) != 0); + p1->detach(); // dectach so that the cache thinks no-one is using it. + QPixmapCache::setCacheLimit(0); + QVERIFY(QPixmapCache::find(key, p1) == 0); + QPixmapCache::setCacheLimit(1000); + key = QPixmapCache::insert(*p1); + QCOMPARE(getPrivate(key)->isValid, true); + QCOMPARE(getPrivate(key)->key, 1); + + delete p1; + + //Let check if removing old entries doesn't let you get + // wrong pixmaps + QPixmapCache::clear(); + QPixmap p2; + p1 = new QPixmap(2, 3); + key = QPixmapCache::insert(*p1); + QVERIFY(QPixmapCache::find(key, &p2) != 0); + //we flush the cache + p1->detach(); + p2.detach(); + QPixmapCache::setCacheLimit(0); + QPixmapCache::setCacheLimit(1000); + QPixmapCache::Key key2 = QPixmapCache::insert(*p1); + QCOMPARE(getPrivate(key2)->key, 1); + QVERIFY(QPixmapCache::find(key, &p2) == 0); + QVERIFY(QPixmapCache::find(key2, &p2) != 0); + QCOMPARE(p2, *p1); + + delete p1; + + //Here we simulate the flushing when the app is idle + QPixmapCache::clear(); + QPixmapCache::setCacheLimit(originalCacheLimit); + p1 = new QPixmap(300, 300); + key = QPixmapCache::insert(*p1); + p1->detach(); + QCOMPARE(getPrivate(key)->key, 1); + key2 = QPixmapCache::insert(*p1); + p1->detach(); + key2 = QPixmapCache::insert(*p1); + p1->detach(); + QPixmapCache::Key key3 = QPixmapCache::insert(*p1); + p1->detach(); + QPixmapCache::flushDetachedPixmaps(); + key2 = QPixmapCache::insert(*p1); + QCOMPARE(getPrivate(key2)->key, 1); + //This old key is not valid anymore after the flush + QCOMPARE(getPrivate(key)->isValid, false); + QVERIFY(QPixmapCache::find(key, &p2) == 0); + delete p1; +} + +void tst_QPixmapCache::find() +{ + QPixmap p1(10, 10); + p1.fill(Qt::red); + QVERIFY(QPixmapCache::insert("P1", p1)); + + QPixmap p2; + QVERIFY(QPixmapCache::find("P1", p2)); + QCOMPARE(p2.width(), 10); + QCOMPARE(p2.height(), 10); + QCOMPARE(p1, p2); + + // obsolete + QPixmap *p3 = QPixmapCache::find("P1"); + QVERIFY(p3); + QCOMPARE(p1, *p3); + + //The int part of the API + QPixmapCache::Key key = QPixmapCache::insert(p1); + + QVERIFY(QPixmapCache::find(key, &p2)); + QCOMPARE(p2.width(), 10); + QCOMPARE(p2.height(), 10); + QCOMPARE(p1, p2); + + QPixmapCache::clear(); + QPixmapCache::setCacheLimit(128); + + QPixmap p4(10,10); + key = QPixmapCache::insert(p4); + p4.detach(); + + QPixmap p5(10,10); + QList<QPixmapCache::Key> keys; + for (int i = 0; i < 4000; ++i) + QPixmapCache::insert(p5); + + //at that time the first key has been erase because no more place in the cache + QVERIFY(QPixmapCache::find(key, &p1) == 0); + QCOMPARE(getPrivate(key)->isValid, false); +} + +void tst_QPixmapCache::insert() +{ + QPixmap p1(10, 10); + p1.fill(Qt::red); + + QPixmap p2(10, 10); + p2.fill(Qt::yellow); + + // Calcuate estimated num of items what fits to cache + int estimatedNum = (1024 * QPixmapCache::cacheLimit()) + / ((p1.width() * p1.height() * p1.depth()) / 8); + + // Mare sure we will put enough items to reach the cache limit + const int numberOfKeys = estimatedNum + 1000; + + // make sure it doesn't explode + for (int i = 0; i < numberOfKeys; ++i) + QPixmapCache::insert("0", p1); + + // ditto + for (int j = 0; j < numberOfKeys; ++j) { + QPixmap p3(10, 10); + QPixmapCache::insert(QString::number(j), p3); + } + + int num = 0; + for (int k = 0; k < numberOfKeys; ++k) { + if (QPixmapCache::find(QString::number(k))) + ++num; + } + + if (QPixmapCache::find("0")) + ++num; + + QVERIFY(num <= estimatedNum); + QPixmap p3; + QPixmapCache::insert("null", p3); + + QPixmap c1(10, 10); + c1.fill(Qt::yellow); + QPixmapCache::insert("custom", c1); + QVERIFY(!c1.isDetached()); + QPixmap c2(10, 10); + c2.fill(Qt::red); + QPixmapCache::insert("custom", c2); + //We have deleted the old pixmap in the cache for the same key + QVERIFY(c1.isDetached()); + + //The int part of the API + // make sure it doesn't explode + QList<QPixmapCache::Key> keys; + for (int i = 0; i < numberOfKeys; ++i) { + QPixmap p3(10,10); + keys.append(QPixmapCache::insert(p3)); + } + + num = 0; + for (int k = 0; k < numberOfKeys; ++k) { + if (QPixmapCache::find(keys.at(k), &p2)) + ++num; + } + + estimatedNum = (1024 * QPixmapCache::cacheLimit()) + / ((p1.width() * p1.height() * p1.depth()) / 8); + QVERIFY(num <= estimatedNum); +} + +void tst_QPixmapCache::replace() +{ + //The int part of the API + QPixmap p1(10, 10); + p1.fill(Qt::red); + + QPixmap p2(10, 10); + p2.fill(Qt::yellow); + + QPixmapCache::Key key = QPixmapCache::insert(p1); + QCOMPARE(getPrivate(key)->isValid, true); + + QPixmap p3; + QVERIFY(QPixmapCache::find(key, &p3) == 1); + + QPixmapCache::replace(key, p2); + + QVERIFY(QPixmapCache::find(key, &p3) == 1); + QCOMPARE(getPrivate(key)->isValid, true); + QCOMPARE(getPrivate(key)->key, 1); + + QCOMPARE(p3.width(), 10); + QCOMPARE(p3.height(), 10); + QCOMPARE(p3, p2); + + //Broken keys + QCOMPARE(QPixmapCache::replace(QPixmapCache::Key(), p2), false); +} + +void tst_QPixmapCache::remove() +{ + QPixmap p1(10, 10); + p1.fill(Qt::red); + + QPixmapCache::insert("red", p1); + p1.fill(Qt::yellow); + + QPixmap p2; + QVERIFY(QPixmapCache::find("red", p2)); + QVERIFY(p1.toImage() != p2.toImage()); + QVERIFY(p1.toImage() == p1.toImage()); // sanity check + + QPixmapCache::remove("red"); + QVERIFY(QPixmapCache::find("red") == 0); + QPixmapCache::remove("red"); + QVERIFY(QPixmapCache::find("red") == 0); + + QPixmapCache::remove("green"); + QVERIFY(QPixmapCache::find("green") == 0); + + //The int part of the API + QPixmapCache::clear(); + p1.fill(Qt::red); + QPixmapCache::Key key = QPixmapCache::insert(p1); + p1.fill(Qt::yellow); + + QVERIFY(QPixmapCache::find(key, &p2)); + QVERIFY(p1.toImage() != p2.toImage()); + QVERIFY(p1.toImage() == p1.toImage()); // sanity check + + QPixmapCache::remove(key); + QVERIFY(QPixmapCache::find(key, &p1) == 0); + + //Broken key + QPixmapCache::remove(QPixmapCache::Key()); + QVERIFY(QPixmapCache::find(QPixmapCache::Key(), &p1) == 0); + + //Test if keys are release + QPixmapCache::clear(); + key = QPixmapCache::insert(p1); + QCOMPARE(getPrivate(key)->key, 1); + QPixmapCache::remove(key); + key = QPixmapCache::insert(p1); + QCOMPARE(getPrivate(key)->key, 1); + + //Test if pixmaps are correctly deleted + QPixmapCache::clear(); + key = QPixmapCache::insert(p1); + QCOMPARE(getPrivate(key)->key, 1); + QVERIFY(QPixmapCache::find(key, &p1) != 0); + QPixmapCache::remove(key); + QCOMPARE(p1.isDetached(), true); + + //We mix both part of the API + QPixmapCache::clear(); + p1.fill(Qt::red); + QPixmapCache::insert("red", p1); + key = QPixmapCache::insert(p1); + QPixmapCache::remove(key); + QVERIFY(QPixmapCache::find(key, &p1) == 0); + QVERIFY(QPixmapCache::find("red") != 0); +} + +void tst_QPixmapCache::clear() +{ + QPixmap p1(10, 10); + p1.fill(Qt::red); + + // Calcuate estimated num of items what fits to cache + int estimatedNum = (1024 * QPixmapCache::cacheLimit()) + / ((p1.width() * p1.height() * p1.depth()) / 8); + + // Mare sure we will put enough items to reach the cache limit + const int numberOfKeys = estimatedNum + 1000; + + for (int i = 0; i < numberOfKeys; ++i) + QVERIFY(QPixmapCache::find("x" + QString::number(i)) == 0); + + for (int j = 0; j < numberOfKeys; ++j) + QPixmapCache::insert(QString::number(j), p1); + + int num = 0; + for (int k = 0; k < numberOfKeys; ++k) { + if (QPixmapCache::find(QString::number(k), p1)) + ++num; + } + QVERIFY(num > 0); + + QPixmapCache::clear(); + + for (int k = 0; k < numberOfKeys; ++k) + QVERIFY(QPixmapCache::find(QString::number(k)) == 0); + + //The int part of the API + QPixmap p2(10, 10); + p2.fill(Qt::red); + + QList<QPixmapCache::Key> keys; + for (int k = 0; k < numberOfKeys; ++k) + keys.append(QPixmapCache::insert(p2)); + + QPixmapCache::clear(); + + for (int k = 0; k < numberOfKeys; ++k) { + QVERIFY(QPixmapCache::find(keys.at(k), &p1) == 0); + QCOMPARE(getPrivate(keys[k])->isValid, false); + } +} + +void tst_QPixmapCache::pixmapKey() +{ + QPixmapCache::Key key; + //Default constructed keys have no d pointer unless + //we use them + QVERIFY(!getPrivate(key)); + //Let's put a d pointer + QPixmapCache::KeyData** keyd = getPrivateRef(key); + *keyd = new QPixmapCache::KeyData; + QCOMPARE(getPrivate(key)->ref, 1); + QPixmapCache::Key key2; + //Let's put a d pointer + QPixmapCache::KeyData** key2d = getPrivateRef(key2); + *key2d = new QPixmapCache::KeyData; + QCOMPARE(getPrivate(key2)->ref, 1); + key = key2; + QCOMPARE(getPrivate(key2)->ref, 2); + QCOMPARE(getPrivate(key)->ref, 2); + QPixmapCache::Key key3; + //Let's put a d pointer + QPixmapCache::KeyData** key3d = getPrivateRef(key3); + *key3d = new QPixmapCache::KeyData; + QPixmapCache::Key key4 = key3; + QCOMPARE(getPrivate(key3)->ref, 2); + QCOMPARE(getPrivate(key4)->ref, 2); + key4 = key; + QCOMPARE(getPrivate(key4)->ref, 3); + QCOMPARE(getPrivate(key3)->ref, 1); + QPixmapCache::Key key5(key3); + QCOMPARE(getPrivate(key3)->ref, 2); + QCOMPARE(getPrivate(key5)->ref, 2); + + //let test default constructed keys + QPixmapCache::Key key6; + QVERIFY(!getPrivate(key6)); + QPixmapCache::Key key7; + QVERIFY(!getPrivate(key7)); + key6 = key7; + QVERIFY(!getPrivate(key6)); + QVERIFY(!getPrivate(key7)); + QPixmapCache::Key key8(key7); + QVERIFY(!getPrivate(key8)); +} + +QT_BEGIN_NAMESPACE +extern int q_QPixmapCache_keyHashSize(); +QT_END_NAMESPACE + +void tst_QPixmapCache::noLeak() +{ + QPixmapCache::Key key; + + int oldSize = q_QPixmapCache_keyHashSize(); + for (int i = 0; i < 100; ++i) { + QPixmap pm(128, 128); + pm.fill(Qt::transparent); + key = QPixmapCache::insert(pm); + QPixmapCache::remove(key); + } + int newSize = q_QPixmapCache_keyHashSize(); + + QCOMPARE(oldSize, newSize); +} + +QTEST_MAIN(tst_QPixmapCache) +#include "tst_qpixmapcache.moc" diff --git a/tests/auto/gui/image/qpixmapfilter/noise.png b/tests/auto/gui/image/qpixmapfilter/noise.png Binary files differnew file mode 100644 index 0000000000..1bebaf528e --- /dev/null +++ b/tests/auto/gui/image/qpixmapfilter/noise.png diff --git a/tests/auto/gui/image/qpixmapfilter/qpixmapfilter.pro b/tests/auto/gui/image/qpixmapfilter/qpixmapfilter.pro new file mode 100644 index 0000000000..21e10b7ab9 --- /dev/null +++ b/tests/auto/gui/image/qpixmapfilter/qpixmapfilter.pro @@ -0,0 +1,13 @@ +load(qttest_p4) + +QT += widgets widgets-private +QT += gui-private + +SOURCES += tst_qpixmapfilter.cpp + +wince*: { + addFiles.files = noise.png + addFiles.path = . + DEPLOYMENT += addFiles +} + diff --git a/tests/auto/gui/image/qpixmapfilter/tst_qpixmapfilter.cpp b/tests/auto/gui/image/qpixmapfilter/tst_qpixmapfilter.cpp new file mode 100644 index 0000000000..5634285ad4 --- /dev/null +++ b/tests/auto/gui/image/qpixmapfilter/tst_qpixmapfilter.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qpixmap.h> +#include <private/qpixmapfilter_p.h> +#include <qpainter.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPixmapFilter : public QObject +{ + Q_OBJECT + +public: + tst_QPixmapFilter(); + virtual ~tst_QPixmapFilter(); + + +public slots: + void init(); + void cleanup(); + +private slots: + void colorizeSetColor(); + void colorizeSetStrength(); + void colorizeProcess(); + void colorizeDraw(); + void colorizeDrawStrength(); + void colorizeDrawSubRect(); + void colorizeProcessSubRect(); + void convolutionBoundingRectFor(); + void convolutionDrawSubRect(); + void dropShadowBoundingRectFor(); + void blurIndexed8(); + + void testDefaultImplementations(); +}; + +class CustomFilter : public QPixmapFilter +{ +public: + enum { Type = QPixmapFilter::UserFilter + 1 }; + + CustomFilter() : QPixmapFilter((QPixmapFilter::FilterType) Type, 0) { }; + + void draw(QPainter *p, const QPointF &pt, const QPixmap &src, const QRectF &srcRect = QRectF()) const { + p->drawPixmap(QRectF(pt, srcRect.size()), src, srcRect); + } +}; + +tst_QPixmapFilter::tst_QPixmapFilter() +{ +} + +tst_QPixmapFilter::~tst_QPixmapFilter() +{ +} + +void tst_QPixmapFilter::init() +{ +} + +void tst_QPixmapFilter::cleanup() +{ +} + +void tst_QPixmapFilter::testDefaultImplementations() +{ + CustomFilter filter; + QCOMPARE(filter.type(), (QPixmapFilter::FilterType) CustomFilter::Type); + + QCOMPARE(filter.boundingRectFor(QRectF(1, 2, 4, 8)), QRectF(1, 2, 4, 8)); + + QPixmap src(10, 10); + src.fill(Qt::blue); + + QPixmap test(src.size()); + QPainter p(&test); + filter.draw(&p, QPointF(0, 0), src, src.rect()); + p.end(); + + QCOMPARE(test.toImage().pixel(0, 0), 0xff0000ff); +} + +void tst_QPixmapFilter::colorizeSetColor() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(50, 100, 200)); + QCOMPARE(filter.color(), QColor(50, 100, 200)); +} + +void tst_QPixmapFilter::colorizeSetStrength() +{ + QPixmapColorizeFilter filter; + QCOMPARE(filter.strength(), qreal(1)); + filter.setStrength(0.5); + QCOMPARE(filter.strength(), qreal(0.5)); + filter.setStrength(0.0); + QCOMPARE(filter.strength(), qreal(0.0)); +} + +void tst_QPixmapFilter::colorizeProcess() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(100, 100, 100)); + + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(0, 0, 50, 50)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(30, 20, 10, 40)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(2.2, 6.3, 11.4, 47.5)); + + QPixmap source("noise.png"); + QImage result(source.size(), QImage::Format_ARGB32_Premultiplied); + result.fill(0); + QPainter p(&result); + filter.draw(&p, QPointF(0, 0), source); + p.end(); + QImage resultImg = result; + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + QCOMPARE(qRed(pixel), qGreen(pixel)); + QCOMPARE(qGreen(pixel), qBlue(pixel)); + } + } +} + +void tst_QPixmapFilter::colorizeDraw() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(100, 100, 100)); + + QPixmap pixmap("noise.png"); + QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(result.rect(), QColor(128, 0, 0, 0)); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + filter.draw(&painter, QPointF(0, 0), pixmap); + painter.end(); + + QImage resultImg = result; + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + QCOMPARE(qRed(pixel), qGreen(pixel)); + QCOMPARE(qGreen(pixel), qBlue(pixel)); + } + } +} + +void tst_QPixmapFilter::colorizeDrawStrength() +{ + QPixmapColorizeFilter filter; + filter.setColor(Qt::blue); + filter.setStrength(0.3); + + QImage source(256, 128, QImage::Format_ARGB32); + source.fill(qRgb(255, 0, 0)); + QPixmap pixmap = QPixmap::fromImage(source); + + QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(QPainter::CompositionMode_Source); + filter.draw(&painter, QPointF(0, 0), pixmap); + painter.end(); + + QImage resultImg = result; + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + QCOMPARE(qRed(pixel), 206); + QCOMPARE(qGreen(pixel), 26); + QCOMPARE(qBlue(pixel), 75); + } + } +} + +void tst_QPixmapFilter::colorizeDrawSubRect() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(255, 255, 255)); + + QPixmap pixmap("noise.png"); + QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(result.rect(), QColor(128, 0, 0, 255)); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + filter.draw(&painter, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); + painter.end(); + + QImage resultImg = result; + QImage sourceImg = pixmap.toImage(); + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + if(x>=16 && x<32 && y>=16 && y<32) { + QCOMPARE(qRed(pixel), qGreen(pixel)); + QCOMPARE(qGreen(pixel), qBlue(pixel)); + } else { + QCOMPARE(qRed(pixel), 128); + QCOMPARE(qGreen(pixel), 0); + QCOMPARE(qBlue(pixel), 0); + QCOMPARE(qAlpha(pixel), 255); + } + } + } +} + +void tst_QPixmapFilter::colorizeProcessSubRect() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(200, 200, 200)); + + QPixmap source("noise.png"); + QImage result(QSize(16, 16), QImage::Format_ARGB32_Premultiplied); + result.fill(0); + QPainter p(&result); + filter.draw(&p, QPointF(0, 0), source, QRectF(16, 16, 16, 16)); + p.end(); + + QImage resultImg = result; + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + QCOMPARE(qRed(pixel), qGreen(pixel)); + QCOMPARE(qGreen(pixel), qBlue(pixel)); + } + } +} + +void tst_QPixmapFilter::convolutionBoundingRectFor() +{ + QPixmapConvolutionFilter filter; + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(0, 0, 50, 50)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(30, 20, 10, 40)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(2.2, 6.3, 11.4, 47.5)); + qreal kernel[] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + }; + filter.setConvolutionKernel(kernel, 2, 2); + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-1, -1, 51, 51)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(29, 19, 11, 41)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(1.2, 5.3, 12.4, 48.5)); + + filter.setConvolutionKernel(kernel, 3, 3); + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-1, -1, 52, 52)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(29, 19, 12, 42)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(1.2, 5.3, 13.4, 49.5)); + + filter.setConvolutionKernel(kernel, 4, 4); + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-2, -2, 53, 53)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(28, 18, 13, 43)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(0.2, 4.3, 14.4, 50.5)); +} + +void tst_QPixmapFilter::convolutionDrawSubRect() +{ + QPixmapConvolutionFilter filter; + qreal kernel[] = { + 0, 0, 0, + 0, 0, 0, + 0, 0, 1 + }; + filter.setConvolutionKernel(kernel, 3, 3); + + QPixmap pixmap("noise.png"); + QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(result.rect(), QColor(128, 0, 0, 255)); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + filter.draw(&painter, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); + painter.end(); + + QImage resultImg = result; + QImage sourceImg = pixmap.toImage(); + for(int y = 0; y < resultImg.height()-1; y++) + { + for(int x = 0; x < resultImg.width()-1; x++) + { + QRgb pixel = resultImg.pixel(x,y); + QRgb srcPixel = sourceImg.pixel(x+1,y+1); + if(x>=15 && x<33 && y>=15 && y<33) { + QCOMPARE(pixel, srcPixel); + } else { + QCOMPARE(qRed(pixel), 128); + QCOMPARE(qGreen(pixel), 0); + QCOMPARE(qBlue(pixel), 0); + QCOMPARE(qAlpha(pixel), 255); + } + } + } + + + kernel[2] = 1; + kernel[8] = 0; + filter.setConvolutionKernel(kernel, 3, 3); + + QPainter painter2(&result); + painter2.setCompositionMode(QPainter::CompositionMode_Source); + painter2.fillRect(result.rect(), QColor(128, 0, 0, 255)); + painter2.setCompositionMode(QPainter::CompositionMode_SourceOver); + filter.draw(&painter2, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); + painter2.end(); + + resultImg = result; + sourceImg = pixmap.toImage(); + for(int y = 1; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width()-1; x++) + { + QRgb pixel = resultImg.pixel(x,y); + QRgb srcPixel = sourceImg.pixel(x+1,y-1); + if(x>=15 && x<33 && y>=15 && y<33) { + QCOMPARE(pixel, srcPixel); + } else { + QCOMPARE(qRed(pixel), 128); + QCOMPARE(qGreen(pixel), 0); + QCOMPARE(qBlue(pixel), 0); + QCOMPARE(qAlpha(pixel), 255); + } + } + } + +} + +void tst_QPixmapFilter::dropShadowBoundingRectFor() +{ + QPixmapDropShadowFilter filter; + filter.setBlurRadius(0); + + QCOMPARE(filter.blurRadius(), 0.); + + const QRectF rect1(0, 0, 50, 50); + const QRectF rect2(30, 20, 10, 40); + const QRectF rect3(2.2, 6.3, 11.4, 47.5); + + filter.setOffset(QPointF(0,0)); + QCOMPARE(filter.boundingRectFor(rect1), rect1); + QCOMPARE(filter.boundingRectFor(rect2), rect2); + QCOMPARE(filter.boundingRectFor(rect3), rect3); + + filter.setOffset(QPointF(1,1)); + QCOMPARE(filter.offset(), QPointF(1, 1)); + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(0, 0, 1, 1)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(0, 0, 1, 1)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(0, 0, 1, 1)); + + filter.setOffset(QPointF(-1,-1)); + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-1, -1, 0, 0)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-1, -1, 0, 0)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-1, -1, 0, 0)); + + filter.setBlurRadius(2); + filter.setOffset(QPointF(0,0)); + qreal delta = 2; + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta, -delta, delta, delta)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta, -delta, delta, delta)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta, -delta, delta, delta)); + + filter.setOffset(QPointF(1,1)); + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); + + filter.setOffset(QPointF(-10,-10)); + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta - 10, -delta - 10, 0, 0)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta - 10, -delta - 10, 0, 0)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta - 10, -delta - 10, 0, 0)); +} + +QT_BEGIN_NAMESPACE +void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); +QT_END_NAMESPACE + +void tst_QPixmapFilter::blurIndexed8() +{ + QImage img(16, 32, QImage::Format_Indexed8); + img.setColorCount(256); + for (int i = 0; i < 256; ++i) + img.setColor(i, qRgb(i, i, i)); + + img.fill(255); + + QImage original = img; + qt_blurImage(img, 10, true, false); + QCOMPARE(original.size(), img.size()); + + original = img; + qt_blurImage(img, 10, true, true); + QCOMPARE(original.size(), QSize(img.height(), img.width())); +} + +QTEST_MAIN(tst_QPixmapFilter) +#include "tst_qpixmapfilter.moc" diff --git a/tests/auto/gui/image/qvolatileimage/qvolatileimage.pro b/tests/auto/gui/image/qvolatileimage/qvolatileimage.pro new file mode 100644 index 0000000000..45d80b85f2 --- /dev/null +++ b/tests/auto/gui/image/qvolatileimage/qvolatileimage.pro @@ -0,0 +1,10 @@ +load(qttest_p4) + +QT += gui-private widgets + +SOURCES += tst_qvolatileimage.cpp + +symbian { + TARGET.EPOCHEAPSIZE = 0x200000 0x800000 + LIBS += -lfbscli +} diff --git a/tests/auto/gui/image/qvolatileimage/tst_qvolatileimage.cpp b/tests/auto/gui/image/qvolatileimage/tst_qvolatileimage.cpp new file mode 100644 index 0000000000..bacca66dcd --- /dev/null +++ b/tests/auto/gui/image/qvolatileimage/tst_qvolatileimage.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtGui/qpainter.h> +#include <QtGui/qpaintengine.h> +#include <QtGui/private/qvolatileimage_p.h> +#ifdef Q_OS_SYMBIAN +#include <fbs.h> +#endif + +class tst_QVolatileImage : public QObject +{ + Q_OBJECT + +public: + tst_QVolatileImage() { } + +private slots: + void create(); + void ensureFormat(); + void dataAccess(); + void sharing(); + void paint(); + void fill(); + void copy(); + void bitmap(); +}; + +void tst_QVolatileImage::create() +{ + QVolatileImage nullImg; + QVERIFY(nullImg.isNull()); + + QVolatileImage img(100, 200, QImage::Format_ARGB32); + QVERIFY(!img.isNull()); + QCOMPARE(img.width(), 100); + QCOMPARE(img.height(), 200); + QCOMPARE(img.format(), QImage::Format_ARGB32); + QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height()); + QCOMPARE(img.hasAlphaChannel(), true); + QCOMPARE(img.depth(), 32); + + QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); + img = QVolatileImage(source); + QVERIFY(!img.isNull()); + QCOMPARE(img.width(), 12); + QCOMPARE(img.height(), 23); + QCOMPARE(img.format(), source.format()); + QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height()); + QVERIFY(img.imageRef() == source); + QVERIFY(img.toImage() == source); + QCOMPARE(img.hasAlphaChannel(), true); + QCOMPARE(img.hasAlphaChannel(), img.imageRef().hasAlphaChannel()); + QCOMPARE(img.hasAlphaChannel(), img.toImage().hasAlphaChannel()); + QCOMPARE(img.depth(), 32); + +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone); + QVolatileImage bmpimg(bmp); + QVERIFY(!bmpimg.isNull()); + QCOMPARE(bmpimg.width(), 100); + QCOMPARE(bmpimg.height(), 50); + // Verify that we only did handle duplication, not pixel data copying. + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + delete bmp; + // Check if content is still valid. + QImage copyimg = bmpimg.toImage(); + QCOMPARE(copyimg.format(), QImage::Format_ARGB32_Premultiplied); +#endif +} + +void tst_QVolatileImage::ensureFormat() +{ + QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); + QVolatileImage img(source); + QVERIFY(!img.isNull()); + QVERIFY(img.imageRef() == source); + QVERIFY(img.toImage() == source); + + QVERIFY(img.ensureFormat(QImage::Format_ARGB32_Premultiplied)); // no-op + QVERIFY(img.imageRef() == source); + QVERIFY(img.toImage() == source); + QVERIFY(img.format() == QImage::Format_ARGB32_Premultiplied); + + QVERIFY(img.ensureFormat(QImage::Format_RGB32)); // new data under-the-hood + QVERIFY(img.imageRef() != source); + QVERIFY(img.toImage() != source); + QVERIFY(img.format() == QImage::Format_RGB32); + +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone); + QVolatileImage bmpimg(bmp); + QVERIFY(bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied)); // no-op + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + + // A different format should cause data copying. + QVERIFY(bmpimg.ensureFormat(QImage::Format_RGB32)); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + const uchar *prevBits = bmpimg.constBits(); + + QVERIFY(bmpimg.ensureFormat(QImage::Format_RGB16)); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + QVERIFY(bmpimg.constBits() != prevBits); + prevBits = bmpimg.constBits(); + + QVERIFY(bmpimg.ensureFormat(QImage::Format_MonoLSB)); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + QVERIFY(bmpimg.constBits() != prevBits); + + delete bmp; +#endif +} + +void tst_QVolatileImage::dataAccess() +{ + QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); + QVolatileImage img(source); + QVERIFY(!img.isNull()); + img.beginDataAccess(); + QVERIFY(img.constBits()); + QVERIFY(img.imageRef().constBits()); + QVERIFY(img.bits()); + QVERIFY(img.imageRef().bits()); + img.endDataAccess(); + + img = QVolatileImage(12, 23, QImage::Format_ARGB32); + img.beginDataAccess(); + QVERIFY(img.constBits() && img.bits()); + img.endDataAccess(); +} + +void tst_QVolatileImage::sharing() +{ + QVolatileImage img1(100, 100, QImage::Format_ARGB32); + QVolatileImage img2 = img1; + img1.beginDataAccess(); + img2.beginDataAccess(); + QVERIFY(img1.constBits() == img2.constBits()); + img2.endDataAccess(); + img1.endDataAccess(); + img1.imageRef(); // non-const call, should detach + img1.beginDataAccess(); + img2.beginDataAccess(); + QVERIFY(img1.constBits() != img2.constBits()); + img2.endDataAccess(); + img1.endDataAccess(); + + // toImage() should return a copy of the internal QImage. + // imageRef() is a reference to the internal QImage. + QVERIFY(img1.imageRef().constBits() != img1.toImage().constBits()); + +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone); + QVolatileImage bmpimg(bmp); + QVolatileImage bmpimg2; + bmpimg2 = bmpimg; + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + QCOMPARE(bmpimg2.constBits(), (const uchar *) bmp->DataAddress()); + // Now force a detach, which should copy the pixel data under-the-hood. + bmpimg.imageRef(); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + QCOMPARE(bmpimg2.constBits(), (const uchar *) bmp->DataAddress()); + delete bmp; +#endif +} + +bool fuzzyCompareImages(const QImage &image1, const QImage &image2, int tolerance) +{ + if (image1.bytesPerLine() != image2.bytesPerLine() + || image1.width() != image2.width() + || image1.height() != image2.height()) { + return false; + } + for (int i = 0; i < image1.height(); i++) { + const uchar *line1 = image1.scanLine(i); + const uchar *line2 = image2.scanLine(i); + int bytes = image1.bytesPerLine(); + for (int j = 0; j < bytes; j++) { + int delta = line1[j] - line2[j]; + if (qAbs(delta) > tolerance) + return false; + } + } + return true; +} + +void tst_QVolatileImage::paint() +{ +#ifdef Q_OS_SYMBIAN + QVolatileImage img(100, 100, QImage::Format_ARGB32); + img.beginDataAccess(); + img.imageRef().fill(QColor(Qt::green).rgba()); + QPainter p(&img.imageRef()); + p.drawRect(10, 10, 50, 50); + p.end(); + img.endDataAccess(); + QImage imgA = img.toImage(); + + // The following assumes that on openvg the pixmapdata is backed by QVolatileImage) + // (and that openvg is in use) + // It should pass with any engine nonetheless. + // See if painting into the underlying QImage succeeds. + QPixmap pm(100, 100); + if (pm.paintEngine()->type() == QPaintEngine::Raster) { + pm.fill(Qt::green); + QPainter pmp(&pm); + pmp.drawRect(10, 10, 50, 50); + pmp.end(); + QImage imgB = pm.toImage(); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); + // Exercise the accelerated QVolatileImagePaintEngine::drawPixmap() a bit. + QPixmap targetPm(pm.size()); + targetPm.fill(Qt::black); + pmp.begin(&targetPm); + pmp.drawPixmap(QPointF(0, 0), pm); + pmp.end(); + imgB = targetPm.toImage(); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); + // Now the overload taking rects. + targetPm.fill(Qt::black); + pmp.begin(&targetPm); + QRectF rect(QPointF(0, 0), pm.size()); + pmp.drawPixmap(rect, pm, rect); + pmp.end(); + imgB = targetPm.toImage(); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); + } else { + QSKIP("Pixmaps not painted via raster, skipping paint test", SkipSingle); + } +#endif +} + +void tst_QVolatileImage::fill() +{ + QVolatileImage img(100, 100, QImage::Format_ARGB32_Premultiplied); + QColor col = QColor(10, 20, 30); + img.fill(col.rgba()); + QVERIFY(img.imageRef().pixel(1, 1) == col.rgba()); + QVERIFY(img.toImage().pixel(1, 1) == col.rgba()); + +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = static_cast<CFbsBitmap *>(img.duplicateNativeImage()); + QVERIFY(bmp); + TRgb pix; + bmp->GetPixel(pix, TPoint(1, 1)); + QCOMPARE(pix.Red(), col.red()); + QCOMPARE(pix.Green(), col.green()); + QCOMPARE(pix.Blue(), col.blue()); + delete bmp; +#endif +} + +void tst_QVolatileImage::copy() +{ + QVolatileImage img(100, 100, QImage::Format_RGB32); + img.beginDataAccess(); + img.imageRef().fill(QColor(Qt::green).rgba()); + QPainter p(&img.imageRef()); + p.drawRect(10, 10, 50, 50); + p.end(); + img.endDataAccess(); + + QVolatileImage img2(100, 100, QImage::Format_RGB32); + img2.copyFrom(&img, QRect()); + QImage imgA = img.toImage(); + QImage imgB = img2.toImage(); + QCOMPARE(imgA.size(), imgB.size()); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); + + img2 = QVolatileImage(20, 20, QImage::Format_RGB32); + img2.copyFrom(&img, QRect(5, 5, 20, 20)); + imgA = img.toImage().copy(5, 5, 20, 20); + imgB = img2.toImage(); + QCOMPARE(imgA.size(), imgB.size()); + QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); +} + +void tst_QVolatileImage::bitmap() +{ +#ifdef Q_OS_SYMBIAN + CFbsBitmap *bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(100, 50), EColor64K) == KErrNone); + QVolatileImage bmpimg(bmp); + CFbsBitmap *dupbmp = static_cast<CFbsBitmap *>(bmpimg.duplicateNativeImage()); + QVERIFY(dupbmp); + QVERIFY(dupbmp != bmp); + QCOMPARE(dupbmp->DataAddress(), bmp->DataAddress()); + delete dupbmp; + delete bmp; + bmpimg.beginDataAccess(); + qMemSet(bmpimg.bits(), 0, bmpimg.byteCount()); + qMemSet(bmpimg.bits(), 1, bmpimg.bytesPerLine() * bmpimg.height()); + bmpimg.endDataAccess(); + + // Test bgr->rgb conversion in case of EColor16M. + bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(101, 89), EColor16M) == KErrNone); + bmp->BeginDataAccess(); + TUint32 *addr = bmp->DataAddress(); + uint rgb = QColor(10, 20, 30).rgb(); + qMemCopy(bmp->DataAddress(), &rgb, 3); + bmp->EndDataAccess(); + TRgb symrgb; + bmp->GetPixel(symrgb, TPoint(0, 0)); + QVERIFY(symrgb.Red() == 10 && symrgb.Green() == 20 && symrgb.Blue() == 30); + bmpimg = QVolatileImage(bmp); + QVERIFY(bmpimg.toImage().pixel(0, 0) == rgb); + // check if there really was a conversion + bmp->BeginDataAccess(); + bmpimg.beginDataAccess(); + qMemCopy(&rgb, bmpimg.constBits(), 3); + uint rgb2 = rgb; + qMemCopy(&rgb2, bmp->DataAddress(), 3); + QVERIFY(rgb != rgb2); + bmpimg.endDataAccess(true); + bmp->EndDataAccess(true); + delete bmp; + + bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(101, 89), EGray2) == KErrNone); + bmpimg = QVolatileImage(bmp); // inverts pixels, but should do it in place + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + QCOMPARE(bmpimg.format(), QImage::Format_MonoLSB); + bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied); + QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); + QCOMPARE(bmpimg.format(), QImage::Format_ARGB32_Premultiplied); + delete bmp; + + // The following two formats must be optimal always. + bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(101, 89), EColor16MAP) == KErrNone); + bmpimg = QVolatileImage(bmp); + QCOMPARE(bmpimg.format(), QImage::Format_ARGB32_Premultiplied); + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied); + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + delete bmp; + bmp = new CFbsBitmap; + QVERIFY(bmp->Create(TSize(101, 89), EColor16MU) == KErrNone); + bmpimg = QVolatileImage(bmp); + QCOMPARE(bmpimg.format(), QImage::Format_RGB32); + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + bmpimg.ensureFormat(QImage::Format_RGB32); + QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); + delete bmp; + +#else + QSKIP("CFbsBitmap is only available on Symbian, skipping bitmap test", SkipSingle); +#endif +} + +int main(int argc, char *argv[]) +{ + QApplication::setGraphicsSystem("openvg"); + QApplication app(argc, argv); + tst_QVolatileImage tc; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_qvolatileimage.moc" diff --git a/tests/auto/gui/kernel/kernel.pro b/tests/auto/gui/kernel/kernel.pro new file mode 100644 index 0000000000..880c3c8613 --- /dev/null +++ b/tests/auto/gui/kernel/kernel.pro @@ -0,0 +1,17 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qclipboard \ + qdrag \ + qevent \ + qfileopenevent \ + qguivariant \ + qkeysequence \ + qmouseevent \ + qmouseevent_modal \ + qpalette \ + qshortcut \ + qtouchevent \ + +symbian { + SUBDIRS += qsoftkeymanager +} diff --git a/tests/auto/gui/kernel/qclipboard/.gitignore b/tests/auto/gui/kernel/qclipboard/.gitignore new file mode 100644 index 0000000000..4fcf7d55fc --- /dev/null +++ b/tests/auto/gui/kernel/qclipboard/.gitignore @@ -0,0 +1,5 @@ +tst_qclipboard +copier/copier +copier/copier.exe +paster/paster +paster/paster.exe diff --git a/tests/auto/gui/kernel/qclipboard/copier/copier.pro b/tests/auto/gui/kernel/qclipboard/copier/copier.pro new file mode 100644 index 0000000000..d345d33eb5 --- /dev/null +++ b/tests/auto/gui/kernel/qclipboard/copier/copier.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +CONFIG -= app_bundle +QT += widgets +win32: DESTDIR = ../copier +# Input +SOURCES += main.cpp + diff --git a/tests/auto/gui/kernel/qclipboard/copier/main.cpp b/tests/auto/gui/kernel/qclipboard/copier/main.cpp new file mode 100644 index 0000000000..e4417352ff --- /dev/null +++ b/tests/auto/gui/kernel/qclipboard/copier/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QApplication> +#include <QClipboard> +#include <QStringList> +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + QClipboard *board = QApplication::clipboard(); +#ifdef Q_OS_WINCE + board->setText(QLatin1String("testString.!")); +#else + board->setText(app.arguments().at(1)); +#endif + return 0; +} diff --git a/tests/auto/gui/kernel/qclipboard/paster/main.cpp b/tests/auto/gui/kernel/qclipboard/paster/main.cpp new file mode 100644 index 0000000000..4df4d7fb45 --- /dev/null +++ b/tests/auto/gui/kernel/qclipboard/paster/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QApplication> +#include <QClipboard> +#include <QStringList> + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + QClipboard *board = QApplication::clipboard(); +#ifdef Q_OS_WINCE + return (board->text() == QLatin1String("testString.!")) ? 0 : 1; +#else + return (board->text() == app.arguments().at(1)) ? 0 : 1; +#endif +} diff --git a/tests/auto/gui/kernel/qclipboard/paster/paster.pro b/tests/auto/gui/kernel/qclipboard/paster/paster.pro new file mode 100644 index 0000000000..d214c9e90a --- /dev/null +++ b/tests/auto/gui/kernel/qclipboard/paster/paster.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +win32: DESTDIR = ../paster +CONFIG -= app_bundle +QT += widgets +# Input +SOURCES += main.cpp + + diff --git a/tests/auto/gui/kernel/qclipboard/qclipboard.pro b/tests/auto/gui/kernel/qclipboard/qclipboard.pro new file mode 100644 index 0000000000..692ca5dd3f --- /dev/null +++ b/tests/auto/gui/kernel/qclipboard/qclipboard.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +SUBDIRS = test copier paster + + diff --git a/tests/auto/gui/kernel/qclipboard/test/test.pro b/tests/auto/gui/kernel/qclipboard/test/test.pro new file mode 100644 index 0000000000..12c6b6ce4f --- /dev/null +++ b/tests/auto/gui/kernel/qclipboard/test/test.pro @@ -0,0 +1,32 @@ +load(qttest_p4) +SOURCES += ../tst_qclipboard.cpp +TARGET = ../tst_qclipboard + +win32 { + CONFIG(debug, debug|release) { + TARGET = ../../debug/tst_qclipboard +} else { + TARGET = ../../release/tst_qclipboard + } +} + +wince*|symbian: { + copier.files = ../copier/copier.exe + copier.path = copier + paster.files = ../paster/paster.exe + paster.path = paster + + symbian: { + LIBS += -lbafl -lestor -letext + + load(data_caging_paths) + rsc.files = $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/copier.rsc + rsc.files += $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/paster.rsc + rsc.path = $$APP_RESOURCE_DIR + reg_resource.files = $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/copier_reg.rsc + reg_resource.files += $${EPOCROOT}$$HW_ZDIR$$REG_RESOURCE_IMPORT_DIR/paster_reg.rsc + reg_resource.path = $$REG_RESOURCE_IMPORT_DIR + } + + DEPLOYMENT += copier paster rsc reg_resource +}
\ No newline at end of file diff --git a/tests/auto/gui/kernel/qclipboard/tst_qclipboard.cpp b/tests/auto/gui/kernel/qclipboard/tst_qclipboard.cpp new file mode 100644 index 0000000000..4d3bb29e13 --- /dev/null +++ b/tests/auto/gui/kernel/qclipboard/tst_qclipboard.cpp @@ -0,0 +1,422 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtCore/QDebug> +#include <QtWidgets/QApplication> +#include <QtGui/QClipboard> +#ifdef Q_WS_MAC +#include <Carbon/Carbon.h> +#endif +#ifdef Q_OS_SYMBIAN +#include "private/qcore_symbian_p.h" +#include "txtetext.h" +#include <baclipb.h> +#endif +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include "txtclipboard.h" +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QClipboard : public QObject +{ + Q_OBJECT +private slots: + + void copy_exit_paste(); + void capabiliyFunctions(); + void modes(); + void testSignals(); + void setMimeData(); + void clearBeforeSetText(); +#ifdef Q_OS_SYMBIAN + void pasteCopySymbian(); + void copyPasteSymbian(); +#endif + +private: + bool nativeClipboardWorking(); +}; + + +bool tst_QClipboard::nativeClipboardWorking() +{ +#ifdef Q_WS_MAC + PasteboardRef pasteboard; + OSStatus status = PasteboardCreate(0, &pasteboard); + if (status == noErr) + CFRelease(pasteboard); + return status == noErr; +#endif + return true; +} + +Q_DECLARE_METATYPE(QClipboard::Mode) + +/* + Tests that the capability functions are implemented on all + platforms. +*/ +void tst_QClipboard::capabiliyFunctions() +{ + QClipboard * const clipboard = QApplication::clipboard(); + + clipboard->supportsSelection(); + clipboard->supportsFindBuffer(); + clipboard->ownsSelection(); + clipboard->ownsClipboard(); + clipboard->ownsFindBuffer(); +} + +/* + Test that text inserted into the clipboard in different modes is + kept separate. +*/ +void tst_QClipboard::modes() +{ + QClipboard * const clipboard = QApplication::clipboard(); + + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + + const QString defaultMode = "default mode text;"; + clipboard->setText(defaultMode); + QCOMPARE(clipboard->text(), defaultMode); + + if (clipboard->supportsSelection()) { + const QString selectionMode = "selection mode text"; + clipboard->setText(selectionMode, QClipboard::Selection); + QCOMPARE(clipboard->text(QClipboard::Selection), selectionMode); + QCOMPARE(clipboard->text(), defaultMode); + } + + if (clipboard->supportsFindBuffer()) { + const QString searchMode = "find mode text"; + clipboard->setText(searchMode, QClipboard::FindBuffer); + QCOMPARE(clipboard->text(QClipboard::FindBuffer), searchMode); + QCOMPARE(clipboard->text(), defaultMode); + } +} + +/* + Test that the appropriate signals are emitted when the cliboard + contents is changed by calling the qt functions. +*/ +void tst_QClipboard::testSignals() +{ + qRegisterMetaType<QClipboard::Mode>("QClipboard::Mode"); + + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + + QClipboard * const clipboard = QApplication::clipboard(); + + QSignalSpy changedSpy(clipboard, SIGNAL(changed(QClipboard::Mode))); + QSignalSpy dataChangedSpy(clipboard, SIGNAL(dataChanged())); + QSignalSpy searchChangedSpy(clipboard, SIGNAL(findBufferChanged())); + QSignalSpy selectionChangedSpy(clipboard, SIGNAL(selectionChanged())); + + const QString text = "clipboard text;"; + + // Test the default mode signal. + clipboard->setText(text); + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(searchChangedSpy.count(), 0); + QCOMPARE(selectionChangedSpy.count(), 0); + QCOMPARE(changedSpy.count(), 1); + QCOMPARE(changedSpy.at(0).count(), 1); + QCOMPARE(qVariantValue<QClipboard::Mode>(changedSpy.at(0).at(0)), QClipboard::Clipboard); + + changedSpy.clear(); + + // Test the selection mode signal. + if (clipboard->supportsSelection()) { + clipboard->setText(text, QClipboard::Selection); + QCOMPARE(selectionChangedSpy.count(), 1); + QCOMPARE(changedSpy.count(), 1); + QCOMPARE(changedSpy.at(0).count(), 1); + QCOMPARE(qVariantValue<QClipboard::Mode>(changedSpy.at(0).at(0)), QClipboard::Selection); + } else { + QCOMPARE(selectionChangedSpy.count(), 0); + } + QCOMPARE(dataChangedSpy.count(), 1); + QCOMPARE(searchChangedSpy.count(), 0); + + changedSpy.clear(); + + // Test the search mode signal. + if (clipboard->supportsFindBuffer()) { + clipboard->setText(text, QClipboard::FindBuffer); + QCOMPARE(searchChangedSpy.count(), 1); + QCOMPARE(changedSpy.count(), 1); + QCOMPARE(changedSpy.at(0).count(), 1); + QCOMPARE(qVariantValue<QClipboard::Mode>(changedSpy.at(0).at(0)), QClipboard::FindBuffer); + } else { + QCOMPARE(searchChangedSpy.count(), 0); + } + QCOMPARE(dataChangedSpy.count(), 1); +} + +/* + Test that pasted text remain on the clipboard + after a Qt application exits. +*/ +void tst_QClipboard::copy_exit_paste() +{ +#ifndef QT_NO_PROCESS +#if defined Q_WS_X11 || defined Q_WS_QWS || defined (Q_WS_QPA) + QSKIP("This test does not make sense on X11 and embedded, copied data disappears from the clipboard when the application exits ", SkipAll); + // ### It's still possible to test copy/paste - just keep the apps running +#elif defined (Q_OS_SYMBIAN) && defined (Q_CC_NOKIAX86) + QSKIP("emulator cannot launch multiple processes",SkipAll); +#endif + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + const QStringList stringArgument = QStringList() << "Test string."; + QCOMPARE(QProcess::execute("copier/copier", stringArgument), 0); +#ifdef Q_WS_MAC + // The Pasteboard needs a moment to breathe (at least on older Macs). + QTest::qWait(100); +#endif + QCOMPARE(QProcess::execute("paster/paster", stringArgument), 0); +#endif +} + +void tst_QClipboard::setMimeData() +{ + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + QMimeData *mimeData = new QMimeData; + const QString TestName(QLatin1String("tst_QClipboard::setMimeData() mimeData")); + mimeData->setObjectName(TestName); +#if defined(Q_OS_WINCE) + // need to set text on CE + mimeData->setText(QLatin1String("Qt/CE foo")); +#endif + + QApplication::clipboard()->setMimeData(mimeData); + QCOMPARE(QApplication::clipboard()->mimeData(), (const QMimeData *)mimeData); + QCOMPARE(QApplication::clipboard()->mimeData()->objectName(), TestName); + + // set it to the same data again, it shouldn't delete mimeData (and crash as a result) + QApplication::clipboard()->setMimeData(mimeData); + QCOMPARE(QApplication::clipboard()->mimeData(), (const QMimeData *)mimeData); + QCOMPARE(QApplication::clipboard()->mimeData()->objectName(), TestName); + QApplication::clipboard()->clear(); + const QMimeData *appMimeData = QApplication::clipboard()->mimeData(); + QVERIFY(appMimeData != mimeData || appMimeData->objectName() != TestName); + + // check for crash when using the same mimedata object on several clipboards + QMimeData *data = new QMimeData; + data->setText("foo"); + + QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard); + QApplication::clipboard()->setMimeData(data, QClipboard::Selection); + QApplication::clipboard()->setMimeData(data, QClipboard::FindBuffer); + + QSignalSpy spySelection(QApplication::clipboard(), SIGNAL(selectionChanged())); + QSignalSpy spyData(QApplication::clipboard(), SIGNAL(dataChanged())); + QSignalSpy spyFindBuffer(QApplication::clipboard(), SIGNAL(findBufferChanged())); + + QApplication::clipboard()->clear(QClipboard::Clipboard); + QApplication::clipboard()->clear(QClipboard::Selection); // used to crash on X11 + QApplication::clipboard()->clear(QClipboard::FindBuffer); + +#if defined(Q_WS_X11) + QCOMPARE(spySelection.count(), 1); + QCOMPARE(spyData.count(), 1); + QCOMPARE(spyFindBuffer.count(), 0); +#elif defined(Q_WS_MAC) + QCOMPARE(spySelection.count(), 0); + QCOMPARE(spyData.count(), 1); + QCOMPARE(spyFindBuffer.count(), 1); +#elif defined(Q_WS_WIN) + QCOMPARE(spySelection.count(), 0); + QCOMPARE(spyData.count(), 1); + QCOMPARE(spyFindBuffer.count(), 0); +#endif + + // an other crash test + data = new QMimeData; + data->setText("foo"); + + QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard); + QApplication::clipboard()->setMimeData(data, QClipboard::Selection); + QApplication::clipboard()->setMimeData(data, QClipboard::FindBuffer); + + QMimeData *newData = new QMimeData; + newData->setText("bar"); + + spySelection.clear(); + spyData.clear(); + spyFindBuffer.clear(); + + QApplication::clipboard()->setMimeData(newData, QClipboard::Clipboard); + QApplication::clipboard()->setMimeData(newData, QClipboard::Selection); // used to crash on X11 + QApplication::clipboard()->setMimeData(newData, QClipboard::FindBuffer); + +#if defined(Q_WS_X11) + QCOMPARE(spySelection.count(), 1); + QCOMPARE(spyData.count(), 1); + QCOMPARE(spyFindBuffer.count(), 0); +#elif defined(Q_WS_MAC) + QCOMPARE(spySelection.count(), 0); + QCOMPARE(spyData.count(), 1); + QCOMPARE(spyFindBuffer.count(), 1); +#elif defined(Q_WS_WIN) + QCOMPARE(spySelection.count(), 0); + QCOMPARE(spyData.count(), 1); + QCOMPARE(spyFindBuffer.count(), 0); +#endif +} + +void tst_QClipboard::clearBeforeSetText() +{ + QApplication::processEvents(); + + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + + const QString text = "tst_QClipboard::clearBeforeSetText()"; + + // setText() should work after processEvents() + QApplication::clipboard()->setText(text); + QCOMPARE(QApplication::clipboard()->text(), text); + QApplication::processEvents(); + QCOMPARE(QApplication::clipboard()->text(), text); + + // same with clear() + QApplication::clipboard()->clear(); + QVERIFY(QApplication::clipboard()->text().isEmpty()); + QApplication::processEvents(); + QVERIFY(QApplication::clipboard()->text().isEmpty()); + + // setText() again + QApplication::clipboard()->setText(text); + QCOMPARE(QApplication::clipboard()->text(), text); + QApplication::processEvents(); + QCOMPARE(QApplication::clipboard()->text(), text); + + // clear() immediately followed by setText() should still return the text + QApplication::clipboard()->clear(); + QVERIFY(QApplication::clipboard()->text().isEmpty()); + QApplication::clipboard()->setText(text); + QCOMPARE(QApplication::clipboard()->text(), text); + QApplication::processEvents(); + QCOMPARE(QApplication::clipboard()->text(), text); +} + +/* + Test that text copied from qt application + can be pasted with symbian clipboard +*/ +#ifdef Q_OS_SYMBIAN +// ### This test case only makes sense in symbian +void tst_QClipboard::pasteCopySymbian() +{ + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + const QString string("Test string symbian."); + QApplication::clipboard()->setText(string); + + const TInt KPlainTextBegin = 0; + RFs fs = qt_s60GetRFs(); + CClipboard* cb = CClipboard::NewForReadingLC(fs); + + CPlainText* text = CPlainText::NewL(); + CleanupStack::PushL(text); + TInt dataLength = text->PasteFromStoreL(cb->Store(), cb->StreamDictionary(), + KPlainTextBegin); + if (dataLength == 0) { + User::Leave(KErrNotFound); + } + HBufC* hBuf = HBufC::NewL(dataLength); + TPtr buf = hBuf->Des(); + text->Extract(buf, KPlainTextBegin, dataLength); + + QString storeString = qt_TDesC2QString(buf); + CleanupStack::PopAndDestroy(text); + CleanupStack::PopAndDestroy(cb); + + QCOMPARE(string, storeString); +} +#endif + +/* + Test that text copied to symbian clipboard + can be pasted to qt clipboard +*/ +#ifdef Q_OS_SYMBIAN +// ### This test case only makes sense in symbian +void tst_QClipboard::copyPasteSymbian() +{ + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + const QString string("Test string symbian."); + const TInt KPlainTextBegin = 0; + + RFs fs = qt_s60GetRFs(); + CClipboard* cb = CClipboard::NewForWritingLC(fs); + CStreamStore& store = cb->Store(); + CStreamDictionary& dict = cb->StreamDictionary(); + RStoreWriteStream symbianStream; + TStreamId symbianStId = symbianStream.CreateLC(cb->Store()); + + CPlainText* text = CPlainText::NewL(); + CleanupStack::PushL(text); + TPtrC textPtr(qt_QString2TPtrC(string)); + text->InsertL(KPlainTextBegin, textPtr); + text->CopyToStoreL(store, dict, KPlainTextBegin, textPtr.Length()); + CleanupStack::PopAndDestroy(text); + (cb->StreamDictionary()).AssignL(KClipboardUidTypePlainText, symbianStId); + cb->CommitL(); + CleanupStack::PopAndDestroy(2, cb); + + QCOMPARE(QApplication::clipboard()->text(), string); +} +#endif + +QTEST_MAIN(tst_QClipboard) + +#include "tst_qclipboard.moc" diff --git a/tests/auto/gui/kernel/qdrag/.gitignore b/tests/auto/gui/kernel/qdrag/.gitignore new file mode 100644 index 0000000000..d210808afe --- /dev/null +++ b/tests/auto/gui/kernel/qdrag/.gitignore @@ -0,0 +1 @@ +tst_qdrag diff --git a/tests/auto/gui/kernel/qdrag/qdrag.pro b/tests/auto/gui/kernel/qdrag/qdrag.pro new file mode 100644 index 0000000000..d9d645559b --- /dev/null +++ b/tests/auto/gui/kernel/qdrag/qdrag.pro @@ -0,0 +1,9 @@ +############################################################ +# Project file for autotest for file qdrag.h +############################################################ + +load(qttest_p4) +QT += widgets +SOURCES += tst_qdrag.cpp + + diff --git a/tests/auto/gui/kernel/qdrag/tst_qdrag.cpp b/tests/auto/gui/kernel/qdrag/tst_qdrag.cpp new file mode 100644 index 0000000000..4d18cefb2c --- /dev/null +++ b/tests/auto/gui/kernel/qdrag/tst_qdrag.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qdebug.h> +#include <qdrag.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QDrag : public QObject +{ +Q_OBJECT + +public: + tst_QDrag(); + virtual ~tst_QDrag(); + +private slots: + void getSetCheck(); +}; + +tst_QDrag::tst_QDrag() +{ +} + +tst_QDrag::~tst_QDrag() +{ +} + +// Testing get/set functions +void tst_QDrag::getSetCheck() +{ + QDrag obj1(0); + // QMimeData * QDrag::mimeData() + // void QDrag::setMimeData(QMimeData *) + QMimeData *var1 = new QMimeData; + obj1.setMimeData(var1); + QCOMPARE(var1, obj1.mimeData()); + obj1.setMimeData(var1); + QCOMPARE(var1, obj1.mimeData()); + obj1.setMimeData((QMimeData *)0); + QCOMPARE((QMimeData *)0, obj1.mimeData()); + // delete var1; // No delete, since QDrag takes ownership + + Qt::DropAction result = obj1.start(); + QCOMPARE(result, Qt::IgnoreAction); + result = obj1.start(Qt::MoveAction | Qt::LinkAction); + QCOMPARE(result, Qt::IgnoreAction); +} + +QTEST_MAIN(tst_QDrag) +#include "tst_qdrag.moc" diff --git a/tests/auto/gui/kernel/qevent/.gitignore b/tests/auto/gui/kernel/qevent/.gitignore new file mode 100644 index 0000000000..2a3ef2a115 --- /dev/null +++ b/tests/auto/gui/kernel/qevent/.gitignore @@ -0,0 +1 @@ +tst_qevent diff --git a/tests/auto/gui/kernel/qevent/qevent.pro b/tests/auto/gui/kernel/qevent/qevent.pro new file mode 100644 index 0000000000..6042b6cdc9 --- /dev/null +++ b/tests/auto/gui/kernel/qevent/qevent.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qevent.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/gui/kernel/qevent/tst_qevent.cpp b/tests/auto/gui/kernel/qevent/tst_qevent.cpp new file mode 100644 index 0000000000..ae39380883 --- /dev/null +++ b/tests/auto/gui/kernel/qevent/tst_qevent.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qcoreevent.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QEvent : public QObject +{ + Q_OBJECT +public: + tst_QEvent(); + ~tst_QEvent(); + +private slots: + void registerEventType_data(); + void registerEventType(); +}; + +tst_QEvent::tst_QEvent() +{ } + +tst_QEvent::~tst_QEvent() +{ } + +void tst_QEvent::registerEventType_data() +{ + QTest::addColumn<int>("hint"); + QTest::addColumn<int>("expected"); + + // default argument + QTest::newRow("default") << -1 << int(QEvent::MaxUser); + // hint not valid + QTest::newRow("User-1") << int(QEvent::User - 1) << int(QEvent::MaxUser - 1); + // hint valid, but already taken + QTest::newRow("MaxUser-1") << int(QEvent::MaxUser - 1) << int(QEvent::MaxUser - 2); + // hint valid, but not taken + QTest::newRow("User + 1000") << int(QEvent::User + 1000) << int(QEvent::User + 1000); +} + +void tst_QEvent::registerEventType() +{ + QFETCH(int, hint); + QFETCH(int, expected); + QCOMPARE(QEvent::registerEventType(hint), expected); +} + +QTEST_MAIN(tst_QEvent) +#include "tst_qevent.moc" diff --git a/tests/auto/gui/kernel/qfileopenevent/qfileopenevent.pro b/tests/auto/gui/kernel/qfileopenevent/qfileopenevent.pro new file mode 100644 index 0000000000..73724828db --- /dev/null +++ b/tests/auto/gui/kernel/qfileopenevent/qfileopenevent.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +QT += widgets +SUBDIRS = test qfileopeneventexternal diff --git a/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.cpp b/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.cpp new file mode 100644 index 0000000000..5d1a6a390f --- /dev/null +++ b/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> +#include <QApplication> +#include <QEvent> + +struct MyApplication : public QApplication +{ + MyApplication(int& argc, char** argv) + : QApplication(argc, argv) + {} + + bool event(QEvent * event) + { + if (event->type() == QEvent::FileOpen) { + QFileOpenEvent* ev = static_cast<QFileOpenEvent *>(event); + QFile file; + bool ok = ev->openFile(file, QFile::Append | QFile::Unbuffered); + if (ok) + file.write(QByteArray("+external")); + return true; + } else { + return QApplication::event(event); + } + } +}; + +int main(int argc, char *argv[]) +{ + MyApplication a(argc, argv); + a.sendPostedEvents(&a, QEvent::FileOpen); + return 0; +} diff --git a/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.pro b/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.pro new file mode 100644 index 0000000000..cb61b82e38 --- /dev/null +++ b/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.pro @@ -0,0 +1,10 @@ +TEMPLATE = app +TARGET = qfileopeneventexternal +QT += core gui widgets +SOURCES += qfileopeneventexternal.cpp +symbian: { + RSS_RULES += "embeddability=KAppEmbeddable;" + RSS_RULES.datatype_list += "priority = EDataTypePriorityHigh; type = \"application/x-tst_qfileopenevent\";" + LIBS += -lapparc \ + -leikcore -lefsrv -lcone +} diff --git a/tests/auto/gui/kernel/qfileopenevent/test/test.pro b/tests/auto/gui/kernel/qfileopenevent/test/test.pro new file mode 100644 index 0000000000..3f16dcf6ee --- /dev/null +++ b/tests/auto/gui/kernel/qfileopenevent/test/test.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +TARGET = tst_qfileopenevent +HEADERS += +SOURCES += tst_qfileopenevent.cpp +symbian { + LIBS+=-lefsrv -lapgrfx -lapmime +} diff --git a/tests/auto/gui/kernel/qfileopenevent/test/tst_qfileopenevent.cpp b/tests/auto/gui/kernel/qfileopenevent/test/tst_qfileopenevent.cpp new file mode 100644 index 0000000000..69cc4ccc01 --- /dev/null +++ b/tests/auto/gui/kernel/qfileopenevent/test/tst_qfileopenevent.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QEvent> + +#ifdef Q_OS_SYMBIAN +#include <apgcli.h> +#include "private/qcore_symbian_p.h" +#endif + +class tst_qfileopenevent : public QObject +{ + Q_OBJECT +public: + tst_qfileopenevent(){} + ~tst_qfileopenevent(); + +public slots: + void initTestCase(); + +private slots: + void constructor(); + void fileOpen(); + void handleLifetime(); + void multiOpen(); + void sendAndReceive(); + void external_data(); + void external(); + +private: +#ifdef Q_OS_SYMBIAN + RFile createRFile(const TDesC& filename, const TDesC8& content); +#else + void createFile(const QString &filename, const QByteArray &content); +#endif + QFileOpenEvent * createFileAndEvent(const QString &filename, const QByteArray &content); + void checkReadAndWrite(QFileOpenEvent& event, const QByteArray& readContent, const QByteArray& writeContent, bool writeOk); + QByteArray readFileContent(QFileOpenEvent& event); + bool appendFileContent(QFileOpenEvent& event, const QByteArray& writeContent); + + bool event(QEvent *); + +private: +#ifdef Q_OS_SYMBIAN + struct AutoRFs : public RFs + { + AutoRFs() + { + qt_symbian_throwIfError(Connect()); + qt_symbian_throwIfError(ShareProtected()); + } + + ~AutoRFs() + { + Close(); + } + }; + AutoRFs fsSession; +#endif +}; + +tst_qfileopenevent::~tst_qfileopenevent() +{ +}; + +void tst_qfileopenevent::initTestCase() +{ +} + +#ifdef Q_OS_SYMBIAN +RFile tst_qfileopenevent::createRFile(const TDesC& filename, const TDesC8& content) +{ + RFile file; + qt_symbian_throwIfError(file.Replace(fsSession, filename, EFileWrite)); + qt_symbian_throwIfError(file.Write(content)); + return file; +} +#else +void tst_qfileopenevent::createFile(const QString &filename, const QByteArray &content) +{ + QFile file(filename); + file.open(QFile::WriteOnly); + file.write(content); + file.close(); +} +#endif + +QFileOpenEvent * tst_qfileopenevent::createFileAndEvent(const QString &filename, const QByteArray &content) +{ +#ifdef Q_OS_SYMBIAN + RFile rFile = createRFile(qt_QString2TPtrC(filename), TPtrC8((TText8*)content.constData(), content.size())); + QScopedPointer<RFile, QScopedPointerRCloser<RFile> > closeRFile(&rFile); + return new QFileOpenEvent(rFile); +#else + createFile(filename, content); + return new QFileOpenEvent(filename); +#endif +} + +void tst_qfileopenevent::constructor() +{ + // check that filename get/set works + QFileOpenEvent nameTest(QLatin1String("fileNameTest")); + QCOMPARE(nameTest.file(), QLatin1String("fileNameTest")); + + // check that url get/set works + QFileOpenEvent urlTest(QUrl(QLatin1String("file:///urlNameTest"))); + QCOMPARE(urlTest.url().toString(), QLatin1String("file:///urlNameTest")); + +#ifdef Q_OS_SYMBIAN + // check that RFile construction works + RFile rFile = createRFile(_L("testRFile"), _L8("test content")); + QFileOpenEvent rFileTest(rFile); + QString targetName(QLatin1String("testRFile")); + QCOMPARE(rFileTest.file().right(targetName.size()), targetName); + QCOMPARE(rFileTest.url().toString().right(targetName.size()), targetName); + rFile.Close(); +#endif +} + +QByteArray tst_qfileopenevent::readFileContent(QFileOpenEvent& event) +{ + QFile file; + event.openFile(file, QFile::ReadOnly); + file.seek(0); + QByteArray data = file.readAll(); + return data; +} + +bool tst_qfileopenevent::appendFileContent(QFileOpenEvent& event, const QByteArray& writeContent) +{ + QFile file; + bool ok = event.openFile(file, QFile::Append | QFile::Unbuffered); + if (ok) + ok = file.write(writeContent) == writeContent.size(); + return ok; +} + +void tst_qfileopenevent::checkReadAndWrite(QFileOpenEvent& event, const QByteArray& readContent, const QByteArray& writeContent, bool writeOk) +{ + QCOMPARE(readFileContent(event), readContent); + QCOMPARE(appendFileContent(event, writeContent), writeOk); + QCOMPARE(readFileContent(event), writeOk ? readContent+writeContent : readContent); +} + +void tst_qfileopenevent::fileOpen() +{ +#ifdef Q_OS_SYMBIAN + // create writeable file + { + RFile rFile = createRFile(_L("testFileOpen"), _L8("test content")); + QFileOpenEvent rFileTest(rFile); + checkReadAndWrite(rFileTest, QByteArray("test content"), QByteArray("+RFileWrite"), true); + rFile.Close(); + } + + // open read-only RFile + { + RFile rFile; + int err = rFile.Open(fsSession, _L("testFileOpen"), EFileRead); + QFileOpenEvent rFileTest(rFile); + checkReadAndWrite(rFileTest, QByteArray("test content+RFileWrite"), QByteArray("+RFileRead"), false); + rFile.Close(); + } +#else + createFile(QLatin1String("testFileOpen"), QByteArray("test content+RFileWrite")); +#endif + + // filename event + QUrl fileUrl; // need to get the URL during the file test, for use in the URL test + { + QFileOpenEvent nameTest(QLatin1String("testFileOpen")); + fileUrl = nameTest.url(); + checkReadAndWrite(nameTest, QByteArray("test content+RFileWrite"), QByteArray("+nameWrite"), true); + } + + // url event + { + QFileOpenEvent urlTest(fileUrl); + checkReadAndWrite(urlTest, QByteArray("test content+RFileWrite+nameWrite"), QByteArray("+urlWrite"), true); + } + + QFile::remove(QLatin1String("testFileOpen")); +} + +void tst_qfileopenevent::handleLifetime() +{ + QScopedPointer<QFileOpenEvent> event(createFileAndEvent(QLatin1String("testHandleLifetime"), QByteArray("test content"))); + + // open a QFile after the original RFile is closed + QFile qFile; + QCOMPARE(event->openFile(qFile, QFile::Append | QFile::Unbuffered), true); + event.reset(0); + + // write to the QFile after the event is closed + QString writeContent(QLatin1String("+closed original handles")); + QCOMPARE(int(qFile.write(writeContent.toUtf8())), writeContent.size()); + qFile.close(); + + // check the content + QFile check("testHandleLifetime"); + check.open(QFile::ReadOnly); + QString content(check.readAll()); + QCOMPARE(content, QLatin1String("test content+closed original handles")); + check.close(); + + QFile::remove(QLatin1String("testHandleLifetime")); +} + +void tst_qfileopenevent::multiOpen() +{ + QScopedPointer<QFileOpenEvent> event(createFileAndEvent(QLatin1String("testMultiOpen"), QByteArray("itlum"))); + + QFile files[5]; + for (int i=0; i<5; i++) { + QCOMPARE(event->openFile(files[i], QFile::ReadOnly), true); + } + for (int i=0; i<5; i++) + files[i].seek(i); + QString str; + for (int i=4; i>=0; i--) { + char c; + files[i].getChar(&c); + str.append(c); + files[i].close(); + } + QCOMPARE(str, QLatin1String("multi")); + + QFile::remove(QLatin1String("testMultiOpen")); +} + +bool tst_qfileopenevent::event(QEvent *event) +{ + if (event->type() != QEvent::FileOpen) + return QObject::event(event); + QFileOpenEvent* fileOpenEvent = static_cast<QFileOpenEvent *>(event); + appendFileContent(*fileOpenEvent, "+received"); + return true; +} + +void tst_qfileopenevent::sendAndReceive() +{ + QScopedPointer<QFileOpenEvent> event(createFileAndEvent(QLatin1String("testSendAndReceive"), QByteArray("sending"))); + + QCoreApplication::instance()->postEvent(this, event.take()); + QCoreApplication::instance()->processEvents(); + + // QTBUG-17468: On Mac, processEvents doesn't always process posted events + QCoreApplication::instance()->sendPostedEvents(); + + // check the content + QFile check("testSendAndReceive"); + QCOMPARE(check.open(QFile::ReadOnly), true); + QString content(check.readAll()); + QCOMPARE(content, QLatin1String("sending+received")); + check.close(); + + QFile::remove(QLatin1String("testSendAndReceive")); +} + +void tst_qfileopenevent::external_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<QByteArray>("targetContent"); + QTest::addColumn<bool>("sendHandle"); + + QString privateName(QLatin1String("tst_qfileopenevent_external")); + QString publicName(QLatin1String("C:\\Data\\tst_qfileopenevent_external")); + QByteArray writeSuccess("original+external"); + QByteArray writeFail("original"); + QTest::newRow("public name") << publicName << writeSuccess << false; + QTest::newRow("data caged name") << privateName << writeFail << false; + QTest::newRow("public handle") << publicName << writeSuccess << true; + QTest::newRow("data caged handle") << privateName << writeSuccess << true; +} + +void tst_qfileopenevent::external() +{ +#ifndef Q_OS_SYMBIAN + QSKIP("external app file open test only valid in Symbian", SkipAll); +#else + + QFETCH(QString, filename); + QFETCH(QByteArray, targetContent); + QFETCH(bool, sendHandle); + + RFile rFile = createRFile(qt_QString2TPtrC(filename), _L8("original")); + + // launch app with the file + RApaLsSession apa; + QCOMPARE(apa.Connect(), KErrNone); + TThreadId threadId; + TDataType type(_L8("application/x-tst_qfileopenevent")); + if (sendHandle) { + QCOMPARE(apa.StartDocument(rFile, type, threadId), KErrNone); + rFile.Close(); + } else { + TFileName fullName; + rFile.FullName(fullName); + rFile.Close(); + QCOMPARE(apa.StartDocument(fullName, type, threadId), KErrNone); + } + + // wait for app exit + RThread appThread; + if (appThread.Open(threadId) == KErrNone) { + TRequestStatus status; + appThread.Logon(status); + User::WaitForRequest(status); + } + + // check the contents + QFile check(filename); + QCOMPARE(check.open(QFile::ReadOnly), true); + QCOMPARE(check.readAll(), targetContent); + bool ok = check.remove(); + + QFile::remove(filename); +#endif +} + +QTEST_MAIN(tst_qfileopenevent) +#include "tst_qfileopenevent.moc" diff --git a/tests/auto/gui/kernel/qguivariant/.gitignore b/tests/auto/gui/kernel/qguivariant/.gitignore new file mode 100644 index 0000000000..ea64ae90a0 --- /dev/null +++ b/tests/auto/gui/kernel/qguivariant/.gitignore @@ -0,0 +1 @@ +tst_qguivariant diff --git a/tests/auto/gui/kernel/qguivariant/qguivariant.pro b/tests/auto/gui/kernel/qguivariant/qguivariant.pro new file mode 100644 index 0000000000..68082f0037 --- /dev/null +++ b/tests/auto/gui/kernel/qguivariant/qguivariant.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qguivariant.cpp + + + diff --git a/tests/auto/gui/kernel/qguivariant/tst_qguivariant.cpp b/tests/auto/gui/kernel/qguivariant/tst_qguivariant.cpp new file mode 100644 index 0000000000..988580b874 --- /dev/null +++ b/tests/auto/gui/kernel/qguivariant/tst_qguivariant.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qvariant.h> + + + +class tst_QGuiVariant : public QObject +{ + Q_OBJECT + +public: + tst_QGuiVariant(); + +private slots: + void variantWithoutApplication(); +}; + +tst_QGuiVariant::tst_QGuiVariant() +{} + +void tst_QGuiVariant::variantWithoutApplication() +{ + QVariant v = QString("red"); + + QVERIFY(qvariant_cast<QColor>(v) == QColor(Qt::red)); +} + + +QTEST_APPLESS_MAIN(tst_QGuiVariant) +#include "tst_qguivariant.moc" diff --git a/tests/auto/gui/kernel/qkeysequence/.gitignore b/tests/auto/gui/kernel/qkeysequence/.gitignore new file mode 100644 index 0000000000..e06a7b0f43 --- /dev/null +++ b/tests/auto/gui/kernel/qkeysequence/.gitignore @@ -0,0 +1 @@ +tst_qkeysequence diff --git a/tests/auto/gui/kernel/qkeysequence/keys_de.qm b/tests/auto/gui/kernel/qkeysequence/keys_de.qm Binary files differnew file mode 100644 index 0000000000..5d7aedd765 --- /dev/null +++ b/tests/auto/gui/kernel/qkeysequence/keys_de.qm diff --git a/tests/auto/gui/kernel/qkeysequence/keys_de.ts b/tests/auto/gui/kernel/qkeysequence/keys_de.ts new file mode 100644 index 0000000000..1db18f1fdd --- /dev/null +++ b/tests/auto/gui/kernel/qkeysequence/keys_de.ts @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS><TS version="1.1" language="de"> +<context> + <name>tst_QKeySequence</name> + <message> + <location filename="tst_qkeysequence.cpp" line="369"/> + <source>Shift+K</source> + <translation type="obsolete">Umschalt+K</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="370"/> + <source>Ctrl+K</source> + <translation type="obsolete">Strg+K</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="371"/> + <source>Alt+K</source> + <translation type="obsolete">Alt+K</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="391"/> + <source>Shift++</source> + <translation>Umschalt++</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="392"/> + <source>Ctrl++</source> + <translation>Strg++</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="393"/> + <source>Alt++</source> + <translation>Alt++</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="394"/> + <source>Meta++</source> + <translation>Meta++</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="401"/> + <source>Shift+,, Shift++</source> + <translation>Umschalt+,, Umschalt++</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="402"/> + <source>Shift+,, Ctrl++</source> + <translation>Umschalt+,, Strg++</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="403"/> + <source>Shift+,, Alt++</source> + <translation>Umschalt+,, Alt++</translation> + </message> + <message> + <location filename="tst_qkeysequence.cpp" line="404"/> + <source>Shift+,, Meta++</source> + <translation>Umschalt+,, Meta++</translation> + </message> +</context> +</TS> diff --git a/tests/auto/gui/kernel/qkeysequence/qkeysequence.pro b/tests/auto/gui/kernel/qkeysequence/qkeysequence.pro new file mode 100644 index 0000000000..6cfbe459ea --- /dev/null +++ b/tests/auto/gui/kernel/qkeysequence/qkeysequence.pro @@ -0,0 +1,8 @@ +load(qttest_p4) + +QT += widgets widgets-private +QT += core-private gui-private + +SOURCES += tst_qkeysequence.cpp + +RESOURCES += qkeysequence.qrc diff --git a/tests/auto/gui/kernel/qkeysequence/qkeysequence.qrc b/tests/auto/gui/kernel/qkeysequence/qkeysequence.qrc new file mode 100644 index 0000000000..e224faaddd --- /dev/null +++ b/tests/auto/gui/kernel/qkeysequence/qkeysequence.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource> + <file>keys_de.qm</file> + <file>qt_de.qm</file> + </qresource> +</RCC> diff --git a/tests/auto/gui/kernel/qkeysequence/qt_de.qm b/tests/auto/gui/kernel/qkeysequence/qt_de.qm Binary files differnew file mode 100644 index 0000000000..595e4d7e8f --- /dev/null +++ b/tests/auto/gui/kernel/qkeysequence/qt_de.qm diff --git a/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp b/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp new file mode 100644 index 0000000000..5753fb8df4 --- /dev/null +++ b/tests/auto/gui/kernel/qkeysequence/tst_qkeysequence.cpp @@ -0,0 +1,636 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <private/qapplication_p.h> +#include <qkeysequence.h> +#include <private/qkeysequence_p.h> +#include <QTranslator> +#include <QLibraryInfo> + +//TESTED_CLASS= +//TESTED_FILES= + +#ifdef Q_WS_MAC +#include <Carbon/Carbon.h> +struct MacSpecialKey { + int key; + ushort macSymbol; +}; + +static const int NumEntries = 21; +static const MacSpecialKey entries[NumEntries] = { + { Qt::Key_Escape, 0x238B }, + { Qt::Key_Tab, 0x21E5 }, + { Qt::Key_Backtab, 0x21E4 }, + { Qt::Key_Backspace, 0x232B }, + { Qt::Key_Return, 0x21B5 }, + { Qt::Key_Enter, 0x21B5 }, + { Qt::Key_Delete, 0x2326 }, + { Qt::Key_Home, 0x2196 }, + { Qt::Key_End, 0x2198 }, + { Qt::Key_Left, 0x2190 }, + { Qt::Key_Up, 0x2191 }, + { Qt::Key_Right, 0x2192 }, + { Qt::Key_Down, 0x2193 }, + { Qt::Key_PageUp, 0x21DE }, + { Qt::Key_PageDown, 0x21DF }, + { Qt::Key_Shift, kShiftUnicode }, + { Qt::Key_Control, kCommandUnicode }, + { Qt::Key_Meta, kControlUnicode }, + { Qt::Key_Alt, kOptionUnicode }, + { Qt::Key_CapsLock, 0x21EA }, +}; + +static bool operator<(const MacSpecialKey &entry, int key) +{ + return entry.key < key; +} + +static bool operator<(int key, const MacSpecialKey &entry) +{ + return key < entry.key; +} + +static const MacSpecialKey * const MacSpecialKeyEntriesEnd = entries + NumEntries; + +static QChar macSymbolForQtKey(int key) +{ + const MacSpecialKey *i = qBinaryFind(entries, MacSpecialKeyEntriesEnd, key); + if (i == MacSpecialKeyEntriesEnd) + return QChar(); + return QChar(i->macSymbol); +} + +#endif + +class tst_QKeySequence : public QObject +{ + Q_OBJECT + +public: + tst_QKeySequence(); + virtual ~tst_QKeySequence(); + +private slots: + void swap(); + void operatorQString_data(); + void operatorQString(); + void compareConstructors_data(); + void compareConstructors(); + void symetricConstructors_data(); + void symetricConstructors(); + void checkMultipleNames(); + void checkMultipleCodes(); + void mnemonic_data(); + void mnemonic(); + void toString_data(); + void toString(); + void streamOperators_data(); + void streamOperators(); + void fromString_data(); + void fromString(); + void ensureSorted(); + void standardKeys_data(); + void standardKeys(); + void keyBindings(); + void translated_data(); + void translated(); + void i18nKeys_data(); + void i18nKeys(); + + + void initTestCase(); +private: + QTranslator *ourTranslator; + QTranslator *qtTranslator; +#ifdef Q_WS_MAC + static const QString MacCtrl; + static const QString MacMeta; + static const QString MacAlt; + static const QString MacShift; +#endif + + +}; + +#ifdef Q_WS_MAC +const QString tst_QKeySequence::MacCtrl = QString(QChar(0x2318)); +const QString tst_QKeySequence::MacMeta = QString(QChar(0x2303)); +const QString tst_QKeySequence::MacAlt = QString(QChar(0x2325)); +const QString tst_QKeySequence::MacShift = QString(QChar(0x21E7)); +#endif + +tst_QKeySequence::tst_QKeySequence() +{ +} + +tst_QKeySequence::~tst_QKeySequence() +{ + +} + +void tst_QKeySequence::initTestCase() +{ + ourTranslator = new QTranslator(this); + ourTranslator->load(":/keys_de"); + qtTranslator = new QTranslator(this); + qtTranslator->load(":/qt_de"); +} + +void tst_QKeySequence::swap() +{ + QKeySequence ks1(Qt::CTRL+Qt::Key_O); + QKeySequence ks2(Qt::CTRL+Qt::Key_L); + ks1.swap(ks2); + QCOMPARE(ks1[0], int(Qt::CTRL+Qt::Key_L)); + QCOMPARE(ks2[0], int(Qt::CTRL+Qt::Key_O)); +} + +void tst_QKeySequence::operatorQString_data() +{ + QTest::addColumn<int>("modifiers"); + QTest::addColumn<int>("keycode"); + QTest::addColumn<QString>("keystring"); + + QTest::newRow( "No modifier" ) << 0 << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << QString( "\x0c5" ); + +#ifndef Q_WS_MAC + QTest::newRow( "Ctrl+Left" ) << int(Qt::CTRL) << int(Qt::Key_Left) << QString( "Ctrl+Left" ); + QTest::newRow( "Ctrl+," ) << int(Qt::CTRL) << int(Qt::Key_Comma) << QString( "Ctrl+," ); + QTest::newRow( "Alt+Left" ) << int(Qt::ALT) << int(Qt::Key_Left) << QString( "Alt+Left" ); + QTest::newRow( "Alt+Shift+Left" ) << int(Qt::ALT | Qt::SHIFT) << int(Qt::Key_Left) << QString( "Alt+Shift+Left" ); + QTest::newRow( "Ctrl" ) << int(Qt::CTRL) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << QString( "Ctrl+\x0c5" ); + QTest::newRow( "Alt" ) << int(Qt::ALT) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << QString( "Alt+\x0c5" ); + QTest::newRow( "Shift" ) << int(Qt::SHIFT) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << QString( "Shift+\x0c5" ); + QTest::newRow( "Meta" ) << int(Qt::META) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << QString( "Meta+\x0c5" ); +#else + QTest::newRow( "Ctrl+Left" ) << int(Qt::CTRL) << int(Qt::Key_Left) << MacCtrl + macSymbolForQtKey(Qt::Key_Left); + QTest::newRow( "Ctrl+," ) << int(Qt::CTRL) << int(Qt::Key_Comma) << MacCtrl + ","; + QTest::newRow( "Alt+Left" ) << int(Qt::ALT) << int(Qt::Key_Left) << MacAlt + macSymbolForQtKey(Qt::Key_Left); + QTest::newRow( "Alt+Shift+Left" ) << int(Qt::ALT | Qt::SHIFT) << int(Qt::Key_Left) << MacAlt + MacShift + macSymbolForQtKey(Qt::Key_Left); + QTest::newRow( "Ctrl" ) << int(Qt::CTRL) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << MacCtrl + "\x0c5"; + QTest::newRow( "Alt" ) << int(Qt::ALT) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << MacAlt + "\x0c5"; + QTest::newRow( "Shift" ) << int(Qt::SHIFT) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << MacShift + "\x0c5"; + QTest::newRow( "Meta" ) << int(Qt::META) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL) << MacMeta + "\x0c5"; +#endif +} + +void tst_QKeySequence::symetricConstructors_data() +{ + QTest::addColumn<int>("modifiers"); + QTest::addColumn<int>("keycode"); + + QTest::newRow( "No modifier" ) << 0 << int(Qt::Key_Aring | Qt::UNICODE_ACCEL); + QTest::newRow( "Ctrl" ) << int(Qt::CTRL) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL); + QTest::newRow( "Alt" ) << int(Qt::ALT) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL); + QTest::newRow( "Shift" ) << int(Qt::SHIFT) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL); + QTest::newRow( "Meta" ) << int(Qt::META) << int(Qt::Key_Aring | Qt::UNICODE_ACCEL); +} + +void tst_QKeySequence::compareConstructors_data() +{ + operatorQString_data(); +} + +// operator QString() +void tst_QKeySequence::operatorQString() +{ + QKeySequence seq; + QFETCH( int, modifiers ); + QFETCH( int, keycode ); + QFETCH( QString, keystring ); + + seq = QKeySequence( modifiers | keycode ); + + QCOMPARE( (QString)seq, keystring ); +} + +// this verifies that the constructors can handle the same strings in and out +void tst_QKeySequence::symetricConstructors() +{ + QFETCH( int, modifiers ); + QFETCH( int, keycode ); + + QKeySequence seq1( modifiers | keycode ); + QKeySequence seq2( (QString)seq1 ); + + QVERIFY( seq1 == seq2 ); +} + +/* Compares QKeySequence constructurs with int or QString arguments + We don't do this for 3.0 since it doesn't support unicode accelerators */ +void tst_QKeySequence::compareConstructors() +{ + QFETCH( int, modifiers ); + QFETCH( int, keycode ); + QFETCH( QString, keystring ); + + QKeySequence qstringSeq( keystring ); + QKeySequence intSeq( modifiers | keycode ); + + QVERIFY( qstringSeq == intSeq ); +} + +void tst_QKeySequence::checkMultipleNames() +{ + QKeySequence oldK( "Ctrl+Page Up" ); + QKeySequence newK( "Ctrl+PgUp" ); + QVERIFY( oldK == newK ); +} + +//TODO: could test third constructor, or test fromString on all constructor-data +void tst_QKeySequence::checkMultipleCodes() +{ + QKeySequence seq1("Alt+d, l"); + QKeySequence seq2 = QKeySequence::fromString("Alt+d, l"); + QVERIFY( seq1 == seq2 ); + + QKeySequence seq3("Alt+d,l"); + QKeySequence seq4 = QKeySequence::fromString("Alt+d,l"); + QVERIFY( seq3 == seq4 ); +} + +/* +* We must ensure that the keyBindings data is always sorted +* so that we can safely perform binary searches. +*/ +void tst_QKeySequence::ensureSorted() +{ +//### accessing static members from private classes does not work on msvc at the moment +#if defined(QT_BUILD_INTERNAL) && !defined(Q_WS_WIN) + uint N = QKeySequencePrivate::numberOfKeyBindings; + uint val = QKeySequencePrivate::keyBindings[0].shortcut; + for ( uint i = 1 ; i < N ; ++i) { + uint nextval = QKeySequencePrivate::keyBindings[i].shortcut; + if (nextval < val) + qDebug() << "Data not sorted at index " << i; + QVERIFY(nextval >= val); + val = nextval; + } +#endif +} + +void tst_QKeySequence::standardKeys_data() +{ + QTest::addColumn<int>("standardKey"); + QTest::addColumn<QString>("expected"); + QTest::newRow("unknownkey") << (int)QKeySequence::UnknownKey<< QString(""); + QTest::newRow("copy") << (int)QKeySequence::Copy << QString("CTRL+C"); + QTest::newRow("cut") << (int)QKeySequence::Cut << QString("CTRL+X"); + QTest::newRow("paste") << (int)QKeySequence::Paste << QString("CTRL+V"); + QTest::newRow("delete") << (int)QKeySequence::Delete<< QString("DEL"); + QTest::newRow("open") << (int)QKeySequence::Open << QString("CTRL+O"); + QTest::newRow("find") << (int)QKeySequence::Find<< QString("CTRL+F"); +#ifdef Q_WS_WIN + QTest::newRow("addTab") << (int)QKeySequence::AddTab<< QString("CTRL+T"); + QTest::newRow("findNext") << (int)QKeySequence::FindNext<< QString("F3"); + QTest::newRow("findPrevious") << (int)QKeySequence::FindPrevious << QString("SHIFT+F3"); + QTest::newRow("close") << (int)QKeySequence::Close<< QString("CTRL+F4"); + QTest::newRow("replace") << (int)QKeySequence::Replace<< QString("CTRL+H"); +#endif + QTest::newRow("bold") << (int)QKeySequence::Bold << QString("CTRL+B"); + QTest::newRow("italic") << (int)QKeySequence::Italic << QString("CTRL+I"); + QTest::newRow("underline") << (int)QKeySequence::Underline << QString("CTRL+U"); + QTest::newRow("selectall") << (int)QKeySequence::SelectAll << QString("CTRL+A"); + QTest::newRow("print") << (int)QKeySequence::Print << QString("CTRL+P"); + QTest::newRow("movenextchar") << (int)QKeySequence::MoveToNextChar<< QString("RIGHT"); + QTest::newRow("zoomIn") << (int)QKeySequence::ZoomIn<< QString("CTRL++"); + QTest::newRow("zoomOut") << (int)QKeySequence::ZoomOut<< QString("CTRL+-"); + QTest::newRow("whatsthis") << (int)QKeySequence::WhatsThis<< QString("SHIFT+F1"); + +#if defined(Q_WS_MAC) + QTest::newRow("help") << (int)QKeySequence::HelpContents<< QString("Ctrl+?"); + QTest::newRow("nextChild") << (int)QKeySequence::NextChild << QString("CTRL+}"); + QTest::newRow("previousChild") << (int)QKeySequence::PreviousChild << QString("CTRL+{"); + QTest::newRow("MoveToEndOfBlock") << (int)QKeySequence::MoveToEndOfBlock << QString("ALT+DOWN"); + QTest::newRow("forward") << (int)QKeySequence::Forward << QString("CTRL+]"); + QTest::newRow("backward") << (int)QKeySequence::Back << QString("CTRL+["); + QTest::newRow("SelectEndOfDocument") << (int)QKeySequence::SelectEndOfDocument<< QString("CTRL+SHIFT+DOWN"); //mac only +#elif defined(Q_WS_S60) + QTest::newRow("help") << (int)QKeySequence::HelpContents<< QString("F2"); + QTest::newRow("SelectEndOfDocument") << (int)QKeySequence::SelectEndOfDocument<< QString("CTRL+SHIFT+END"); //mac only +#else + QTest::newRow("help") << (int)QKeySequence::HelpContents<< QString("F1"); + QTest::newRow("nextChild") << (int)QKeySequence::NextChild<< QString("CTRL+Tab"); + QTest::newRow("previousChild") << (int)QKeySequence::PreviousChild<< QString("CTRL+SHIFT+BACKTAB"); + QTest::newRow("forward") << (int)QKeySequence::Forward << QString("ALT+RIGHT"); + QTest::newRow("backward") << (int)QKeySequence::Back << QString("ALT+LEFT"); + QTest::newRow("MoveToEndOfBlock") << (int)QKeySequence::MoveToEndOfBlock<< QString(""); //mac only + QTest::newRow("SelectEndOfDocument") << (int)QKeySequence::SelectEndOfDocument<< QString("CTRL+SHIFT+END"); //mac only +#endif +} + +void tst_QKeySequence::standardKeys() +{ + QFETCH(int, standardKey); + QFETCH(QString, expected); + QKeySequence ks((QKeySequence::StandardKey)standardKey); + QKeySequence ks2(expected); + QVERIFY(ks == ks2); +} + +void tst_QKeySequence::keyBindings() +{ + QList<QKeySequence> bindings = QKeySequence::keyBindings(QKeySequence::Copy); + QList<QKeySequence> expected; +#if defined(Q_WS_MAC) || defined (Q_WS_S60) + expected << QKeySequence("CTRL+C"); +#elif defined Q_WS_X11 + expected << QKeySequence("CTRL+C") << QKeySequence("F16") << QKeySequence("CTRL+INSERT"); +#else + expected << QKeySequence("CTRL+C") << QKeySequence("CTRL+INSERT"); +#endif + QVERIFY(bindings == expected); +} + + + +void tst_QKeySequence::mnemonic_data() +{ + QTest::addColumn<QString>("string"); + QTest::addColumn<QString>("key"); + QTest::addColumn<bool>("warning"); + + QTest::newRow("1") << QString::fromLatin1("&bonjour") << QString::fromLatin1("ALT+B") << false; + QTest::newRow("2") << QString::fromLatin1("&&bonjour") << QString() << false; + QTest::newRow("3") << QString::fromLatin1("&&bon&jour") << QString::fromLatin1("ALT+J") << false; + QTest::newRow("4") << QString::fromLatin1("&&bon&jo&ur") << QString::fromLatin1("ALT+J") << true; + QTest::newRow("5") << QString::fromLatin1("b&on&&jour") << QString::fromLatin1("ALT+O") << false; + QTest::newRow("6") << QString::fromLatin1("bonjour") << QString() << false; + QTest::newRow("7") << QString::fromLatin1("&&&bonjour") << QString::fromLatin1("ALT+B") << false; + QTest::newRow("8") << QString::fromLatin1("bonjour&&&") << QString() << false; + QTest::newRow("9") << QString::fromLatin1("bo&&nj&o&&u&r") << QString::fromLatin1("ALT+O") << true; + QTest::newRow("10") << QString::fromLatin1("BON&JOUR") << QString::fromLatin1("ALT+J") << false; + QTest::newRow("11") << QString::fromUtf8("bonjour") << QString() << false; +} + +void tst_QKeySequence::mnemonic() +{ +#ifdef Q_WS_MAC + QSKIP("mnemonics are not used on Mac OS X", SkipAll); +#endif + QFETCH(QString, string); + QFETCH(QString, key); + QFETCH(bool, warning); + +#ifndef QT_NO_DEBUG + if (warning) { + QString str = QString::fromLatin1("QKeySequence::mnemonic: \"%1\" contains multiple occurrences of '&'").arg(string); + QTest::ignoreMessage(QtWarningMsg, qPrintable(str)); + // qWarning(qPrintable(str)); + } +#endif + QKeySequence seq = QKeySequence::mnemonic(string); + QKeySequence res = QKeySequence(key); + + QCOMPARE(seq, res); +} + + + +void tst_QKeySequence::toString_data() +{ + QTest::addColumn<QString>("strSequence"); + QTest::addColumn<QString>("neutralString"); + QTest::addColumn<QString>("platformString"); + + +#ifndef Q_WS_MAC + QTest::newRow("Ctrl+Left") << QString("Ctrl+Left") << QString("Ctrl+Left") << QString("Ctrl+Left"); + QTest::newRow("Alt+Left") << QString("Alt+Left") << QString("Alt+Left") << QString("Alt+Left"); + QTest::newRow("Alt+Shift+Left") << QString("Alt+Shift+Left") << QString("Alt+Shift+Left") << QString("Alt+Shift+Left"); + QTest::newRow("Ctrl") << QString("Ctrl+\x0c5") << QString("Ctrl+\x0c5") << QString("Ctrl+\x0c5"); + QTest::newRow("Alt") << QString("Alt+\x0c5") << QString("Alt+\x0c5") << QString("Alt+\x0c5"); + QTest::newRow("Shift") << QString("Shift+\x0c5") << QString("Shift+\x0c5") << QString("Shift+\x0c5"); + QTest::newRow("Meta") << QString("Meta+\x0c5") << QString("Meta+\x0c5") << QString("Meta+\x0c5"); + QTest::newRow("Ctrl+Plus") << QString("Ctrl++") << QString("Ctrl++") << QString("Ctrl++"); + QTest::newRow("Ctrl+,") << QString("Ctrl+,") << QString("Ctrl+,") << QString("Ctrl+,"); + QTest::newRow("Ctrl+,,Ctrl+,") << QString("Ctrl+,,Ctrl+,") << QString("Ctrl+,, Ctrl+,") << QString("Ctrl+,, Ctrl+,"); + QTest::newRow("MultiKey") << QString("Alt+X, Ctrl+Y, Z") << QString("Alt+X, Ctrl+Y, Z") + << QString("Alt+X, Ctrl+Y, Z"); + + QTest::newRow("Invalid") << QString("Ctrly") << QString("") << QString(""); +#else + /* + QTest::newRow("Ctrl+Left") << MacCtrl + "Left" << QString("Ctrl+Left") << MacCtrl + macSymbolForQtKey(Qt::Key_Left); + QTest::newRow("Alt+Left") << MacAlt + "Left" << QString("Alt+Left") << MacAlt + macSymbolForQtKey(Qt::Key_Left); + QTest::newRow("Alt+Shift+Left") << MacAlt + MacShift + "Left" << QString("Alt+Shift+Left") + << MacAlt + MacShift + macSymbolForQtKey(Qt::Key_Left); + */ + QTest::newRow("Ctrl+Right,Left") << MacCtrl + "Right, Left" << QString("Ctrl+Right, Left") << MacCtrl + macSymbolForQtKey(Qt::Key_Right) + QString(", ") + macSymbolForQtKey(Qt::Key_Left); + QTest::newRow("Ctrl") << MacCtrl + "\x0c5" << QString("Ctrl+\x0c5") << MacCtrl + "\x0c5"; + QTest::newRow("Alt") << MacAlt + "\x0c5" << QString("Alt+\x0c5") << MacAlt + "\x0c5"; + QTest::newRow("Shift") << MacShift + "\x0c5" << QString("Shift+\x0c5") << MacShift + "\x0c5"; + QTest::newRow("Meta") << MacMeta + "\x0c5" << QString("Meta+\x0c5") << MacMeta + "\x0c5"; + QTest::newRow("Ctrl+Plus") << MacCtrl + "+" << QString("Ctrl++") << MacCtrl + "+"; + QTest::newRow("Ctrl+,") << MacCtrl + "," << QString("Ctrl+,") << MacCtrl + ","; + QTest::newRow("Ctrl+,,Ctrl+,") << MacCtrl + ",, " + MacCtrl + "," << QString("Ctrl+,, Ctrl+,") << MacCtrl + ",, " + MacCtrl + ","; + QTest::newRow("MultiKey") << MacAlt + "X, " + MacCtrl + "Y, Z" << QString("Alt+X, Ctrl+Y, Z") + << MacAlt + "X, " + MacCtrl + "Y, Z"; + QTest::newRow("Invalid") << QString("Ctrly") << QString("") << QString(""); +#endif +} + +void tst_QKeySequence::toString() +{ + QFETCH(QString, strSequence); + QFETCH(QString, neutralString); + QFETCH(QString, platformString); + + QKeySequence ks1(strSequence); + + QCOMPARE(ks1.toString(QKeySequence::NativeText), platformString); + QCOMPARE(ks1.toString(QKeySequence::PortableText), neutralString); + +} + +void tst_QKeySequence::streamOperators_data() +{ + operatorQString_data(); +} + +void tst_QKeySequence::streamOperators() +{ + QFETCH( int, modifiers ); + QFETCH( int, keycode ); + + QByteArray data; + QKeySequence refK( modifiers | keycode ); + QKeySequence orgK( "Ctrl+A" ); + QKeySequence copyOrgK = orgK; + QVERIFY( copyOrgK == orgK ); + + QDataStream in(&data, QIODevice::WriteOnly); + in << refK; + QDataStream out(&data, QIODevice::ReadOnly); + out >> orgK; + + QVERIFY( orgK == refK ); + + // check if detached + QVERIFY( orgK != copyOrgK ); +} + +void tst_QKeySequence::fromString_data() +{ + toString_data(); +} + +void tst_QKeySequence::fromString() +{ + QFETCH(QString, strSequence); + QFETCH(QString, neutralString); + QFETCH(QString, platformString); + + QKeySequence ks1(strSequence); + QKeySequence ks2 = QKeySequence::fromString(ks1.toString()); + QKeySequence ks3 = QKeySequence::fromString(neutralString, QKeySequence::PortableText); + QKeySequence ks4 = QKeySequence::fromString(platformString, QKeySequence::NativeText); + + + // assume the transitive property exists here. + QCOMPARE(ks2, ks1); + QCOMPARE(ks3, ks1); + QCOMPARE(ks4, ks1); +} + +void tst_QKeySequence::translated_data() +{ + qApp->installTranslator(ourTranslator); + qApp->installTranslator(qtTranslator); + + QTest::addColumn<QString>("transKey"); + QTest::addColumn<QString>("compKey"); + + QTest::newRow("Shift++") << tr("Shift++") << QString("Umschalt++"); + QTest::newRow("Ctrl++") << tr("Ctrl++") << QString("Strg++"); + QTest::newRow("Alt++") << tr("Alt++") << QString("Alt++"); + QTest::newRow("Meta++") << tr("Meta++") << QString("Meta++"); + + QTest::newRow("Shift+,, Shift++") << tr("Shift+,, Shift++") << QString("Umschalt+,, Umschalt++"); + QTest::newRow("Shift+,, Ctrl++") << tr("Shift+,, Ctrl++") << QString("Umschalt+,, Strg++"); + QTest::newRow("Shift+,, Alt++") << tr("Shift+,, Alt++") << QString("Umschalt+,, Alt++"); + QTest::newRow("Shift+,, Meta++") << tr("Shift+,, Meta++") << QString("Umschalt+,, Meta++"); + + QTest::newRow("Ctrl+,, Shift++") << tr("Ctrl+,, Shift++") << QString("Strg+,, Umschalt++"); + QTest::newRow("Ctrl+,, Ctrl++") << tr("Ctrl+,, Ctrl++") << QString("Strg+,, Strg++"); + QTest::newRow("Ctrl+,, Alt++") << tr("Ctrl+,, Alt++") << QString("Strg+,, Alt++"); + QTest::newRow("Ctrl+,, Meta++") << tr("Ctrl+,, Meta++") << QString("Strg+,, Meta++"); + + qApp->removeTranslator(ourTranslator); + qApp->removeTranslator(qtTranslator); +} + +void tst_QKeySequence::translated() +{ + QFETCH(QString, transKey); + QFETCH(QString, compKey); +#ifdef Q_WS_MAC + QSKIP("No need to translate modifiers on Mac OS X", SkipAll); +#elif defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + QSKIP("No need to translate modifiers on WinCE or Symbian", SkipAll); +#endif + + qApp->installTranslator(ourTranslator); + qApp->installTranslator(qtTranslator); + + QKeySequence ks1(transKey); + QCOMPARE(ks1.toString(QKeySequence::NativeText), compKey); + + qApp->removeTranslator(ourTranslator); + qApp->removeTranslator(qtTranslator); +} + + +void tst_QKeySequence::i18nKeys_data() +{ + QTest::addColumn<int>("keycode"); + QTest::addColumn<QString>("keystring"); + + // Japanese keyboard support + QTest::newRow("Kanji") << (int)Qt::Key_Kanji << QString("Kanji"); + QTest::newRow("Muhenkan") << (int)Qt::Key_Muhenkan << QString("Muhenkan"); + QTest::newRow("Henkan") << (int)Qt::Key_Henkan << QString("Henkan"); + QTest::newRow("Romaji") << (int)Qt::Key_Romaji << QString("Romaji"); + QTest::newRow("Hiragana") << (int)Qt::Key_Hiragana << QString("Hiragana"); + QTest::newRow("Katakana") << (int)Qt::Key_Katakana << QString("Katakana"); + QTest::newRow("Hiragana Katakana") << (int)Qt::Key_Hiragana_Katakana << QString("Hiragana Katakana"); + QTest::newRow("Zenkaku") << (int)Qt::Key_Zenkaku << QString("Zenkaku"); + QTest::newRow("Hankaku") << (int)Qt::Key_Hankaku << QString("Hankaku"); + QTest::newRow("Zenkaku Hankaku") << (int)Qt::Key_Zenkaku_Hankaku << QString("Zenkaku Hankaku"); + QTest::newRow("Touroku") << (int)Qt::Key_Touroku << QString("Touroku"); + QTest::newRow("Massyo") << (int)Qt::Key_Massyo << QString("Massyo"); + QTest::newRow("Kana Lock") << (int)Qt::Key_Kana_Lock << QString("Kana Lock"); + QTest::newRow("Kana Shift") << (int)Qt::Key_Kana_Shift << QString("Kana Shift"); + QTest::newRow("Eisu Shift") << (int)Qt::Key_Eisu_Shift << QString("Eisu Shift"); + QTest::newRow("Eisu_toggle") << (int)Qt::Key_Eisu_toggle << QString("Eisu toggle"); + QTest::newRow("Code input") << (int)Qt::Key_Codeinput << QString("Code input"); + QTest::newRow("Multiple Candidate") << (int)Qt::Key_MultipleCandidate << QString("Multiple Candidate"); + QTest::newRow("Previous Candidate") << (int)Qt::Key_PreviousCandidate << QString("Previous Candidate"); + + // Korean keyboard support + QTest::newRow("Hangul") << (int)Qt::Key_Hangul << QString("Hangul"); + QTest::newRow("Hangul Start") << (int)Qt::Key_Hangul_Start << QString("Hangul Start"); + QTest::newRow("Hangul End") << (int)Qt::Key_Hangul_End << QString("Hangul End"); + QTest::newRow("Hangul Hanja") << (int)Qt::Key_Hangul_Hanja << QString("Hangul Hanja"); + QTest::newRow("Hangul Jamo") << (int)Qt::Key_Hangul_Jamo << QString("Hangul Jamo"); + QTest::newRow("Hangul Romaja") << (int)Qt::Key_Hangul_Romaja << QString("Hangul Romaja"); + QTest::newRow("Hangul Jeonja") << (int)Qt::Key_Hangul_Jeonja << QString("Hangul Jeonja"); + QTest::newRow("Hangul Banja") << (int)Qt::Key_Hangul_Banja << QString("Hangul Banja"); + QTest::newRow("Hangul PreHanja") << (int)Qt::Key_Hangul_PreHanja << QString("Hangul PreHanja"); + QTest::newRow("Hangul PostHanja") << (int)Qt::Key_Hangul_PostHanja << QString("Hangul PostHanja"); + QTest::newRow("Hangul Special") << (int)Qt::Key_Hangul_Special << QString("Hangul Special"); +} + +void tst_QKeySequence::i18nKeys() +{ + QFETCH(int, keycode); + QFETCH(QString, keystring); + QKeySequence seq(keycode); + + QCOMPARE(seq, QKeySequence(keystring)); + QCOMPARE(seq.toString(), keystring); +} + +QTEST_MAIN(tst_QKeySequence) +#include "tst_qkeysequence.moc" diff --git a/tests/auto/gui/kernel/qmouseevent/.gitignore b/tests/auto/gui/kernel/qmouseevent/.gitignore new file mode 100644 index 0000000000..17cd6be116 --- /dev/null +++ b/tests/auto/gui/kernel/qmouseevent/.gitignore @@ -0,0 +1 @@ +tst_qmouseevent diff --git a/tests/auto/gui/kernel/qmouseevent/qmouseevent.pro b/tests/auto/gui/kernel/qmouseevent/qmouseevent.pro new file mode 100644 index 0000000000..58cebd3d06 --- /dev/null +++ b/tests/auto/gui/kernel/qmouseevent/qmouseevent.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qmouseevent.cpp diff --git a/tests/auto/gui/kernel/qmouseevent/tst_qmouseevent.cpp b/tests/auto/gui/kernel/qmouseevent/tst_qmouseevent.cpp new file mode 100644 index 0000000000..5998aa0c08 --- /dev/null +++ b/tests/auto/gui/kernel/qmouseevent/tst_qmouseevent.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qapplication.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qdialog.h> + + +#include <qevent.h> +#include <qwidget.h> + +//TESTED_CLASS= +//TESTED_FILES=gui/widgets/qmenubar.h gui/widgets/qmenubar.cpp + +class MouseEventWidget : public QWidget +{ +public: + MouseEventWidget(QWidget *parent = 0) : QWidget(parent) + { + setFocusPolicy(Qt::StrongFocus); + } + bool mousePressEventRecieved; + bool mouseReleaseEventRecieved; + int mousePressButton; + int mousePressButtons; + int mousePressModifiers; + int mouseReleaseButton; + int mouseReleaseButtons; + int mouseReleaseModifiers; +protected: + void mousePressEvent(QMouseEvent *e) + { + QWidget::mousePressEvent(e); + mousePressButton = e->button(); + mousePressButtons = e->buttons(); + mousePressModifiers = e->modifiers(); + mousePressEventRecieved = TRUE; + e->accept(); + } + void mouseReleaseEvent(QMouseEvent *e) + { + QWidget::mouseReleaseEvent(e); + mouseReleaseButton = e->button(); + mouseReleaseButtons = e->buttons(); + mouseReleaseModifiers = e->modifiers(); + mouseReleaseEventRecieved = TRUE; + e->accept(); + } +}; + +class tst_QMouseEvent : public QObject +{ + Q_OBJECT + +public: + tst_QMouseEvent(); + virtual ~tst_QMouseEvent(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void checkMousePressEvent_data(); + void checkMousePressEvent(); + void checkMouseReleaseEvent_data(); + void checkMouseReleaseEvent(); + +private: + MouseEventWidget* testMouseWidget; +}; + + + +tst_QMouseEvent::tst_QMouseEvent() +{ +} + +tst_QMouseEvent::~tst_QMouseEvent() +{ + +} + +void tst_QMouseEvent::initTestCase() +{ + testMouseWidget = new MouseEventWidget(0); + testMouseWidget->show(); +} + +void tst_QMouseEvent::cleanupTestCase() +{ + delete testMouseWidget; +} + +void tst_QMouseEvent::init() +{ + testMouseWidget->mousePressEventRecieved = FALSE; + testMouseWidget->mouseReleaseEventRecieved = FALSE; + testMouseWidget->mousePressButton = 0; + testMouseWidget->mousePressButtons = 0; + testMouseWidget->mousePressModifiers = 0; + testMouseWidget->mouseReleaseButton = 0; + testMouseWidget->mouseReleaseButtons = 0; + testMouseWidget->mouseReleaseModifiers = 0; +} + +void tst_QMouseEvent::cleanup() +{ +} + +void tst_QMouseEvent::checkMousePressEvent_data() +{ + QTest::addColumn<int>("buttonPressed"); + QTest::addColumn<int>("keyPressed"); + + QTest::newRow("leftButton-nokey") << int(Qt::LeftButton) << int(Qt::NoButton); + QTest::newRow("leftButton-shiftkey") << int(Qt::LeftButton) << int(Qt::ShiftModifier); + QTest::newRow("leftButton-controlkey") << int(Qt::LeftButton) << int(Qt::ControlModifier); + QTest::newRow("leftButton-altkey") << int(Qt::LeftButton) << int(Qt::AltModifier); + QTest::newRow("leftButton-metakey") << int(Qt::LeftButton) << int(Qt::MetaModifier); + QTest::newRow("rightButton-nokey") << int(Qt::RightButton) << int(Qt::NoButton); + QTest::newRow("rightButton-shiftkey") << int(Qt::RightButton) << int(Qt::ShiftModifier); + QTest::newRow("rightButton-controlkey") << int(Qt::RightButton) << int(Qt::ControlModifier); + QTest::newRow("rightButton-altkey") << int(Qt::RightButton) << int(Qt::AltModifier); + QTest::newRow("rightButton-metakey") << int(Qt::RightButton) << int(Qt::MetaModifier); + QTest::newRow("midButton-nokey") << int(Qt::MidButton) << int(Qt::NoButton); + QTest::newRow("midButton-shiftkey") << int(Qt::MidButton) << int(Qt::ShiftModifier); + QTest::newRow("midButton-controlkey") << int(Qt::MidButton) << int(Qt::ControlModifier); + QTest::newRow("midButton-altkey") << int(Qt::MidButton) << int(Qt::AltModifier); + QTest::newRow("midButton-metakey") << int(Qt::MidButton) << int(Qt::MetaModifier); +} + +void tst_QMouseEvent::checkMousePressEvent() +{ + QFETCH(int,buttonPressed); + QFETCH(int,keyPressed); + int button = buttonPressed; + int buttons = button; + int modifiers = keyPressed; + + QTest::mousePress(testMouseWidget, Qt::MouseButton(buttonPressed), Qt::KeyboardModifiers(keyPressed)); + QVERIFY(testMouseWidget->mousePressEventRecieved); + QCOMPARE(testMouseWidget->mousePressButton, button); + QCOMPARE(testMouseWidget->mousePressButtons, buttons); + QCOMPARE(testMouseWidget->mousePressModifiers, modifiers); + + QTest::mouseRelease(testMouseWidget, Qt::MouseButton(buttonPressed), Qt::KeyboardModifiers(keyPressed)); +} + +void tst_QMouseEvent::checkMouseReleaseEvent_data() +{ + QTest::addColumn<int>("buttonReleased"); + QTest::addColumn<int>("keyPressed"); + + QTest::newRow("leftButton-nokey") << int(Qt::LeftButton) << int(Qt::NoButton); + QTest::newRow("leftButton-shiftkey") << int(Qt::LeftButton) << int(Qt::ShiftModifier); + QTest::newRow("leftButton-controlkey") << int(Qt::LeftButton) << int(Qt::ControlModifier); + QTest::newRow("leftButton-altkey") << int(Qt::LeftButton) << int(Qt::AltModifier); + QTest::newRow("leftButton-metakey") << int(Qt::LeftButton) << int(Qt::MetaModifier); + QTest::newRow("rightButton-nokey") << int(Qt::RightButton) << int(Qt::NoButton); + QTest::newRow("rightButton-shiftkey") << int(Qt::RightButton) << int(Qt::ShiftModifier); + QTest::newRow("rightButton-controlkey") << int(Qt::RightButton) << int(Qt::ControlModifier); + QTest::newRow("rightButton-altkey") << int(Qt::RightButton) << int(Qt::AltModifier); + QTest::newRow("rightButton-metakey") << int(Qt::RightButton) << int(Qt::MetaModifier); + QTest::newRow("midButton-nokey") << int(Qt::MidButton) << int(Qt::NoButton); + QTest::newRow("midButton-shiftkey") << int(Qt::MidButton) << int(Qt::ShiftModifier); + QTest::newRow("midButton-controlkey") << int(Qt::MidButton) << int(Qt::ControlModifier); + QTest::newRow("midButton-altkey") << int(Qt::MidButton) << int(Qt::AltModifier); + QTest::newRow("midButton-metakey") << int(Qt::MidButton) << int(Qt::MetaModifier); +} + +void tst_QMouseEvent::checkMouseReleaseEvent() +{ + QFETCH(int,buttonReleased); + QFETCH(int,keyPressed); + int button = buttonReleased; + int buttons = 0; + int modifiers = keyPressed; + + QTest::mouseClick(testMouseWidget, Qt::MouseButton(buttonReleased), Qt::KeyboardModifiers(keyPressed)); + QVERIFY(testMouseWidget->mouseReleaseEventRecieved); + QCOMPARE(testMouseWidget->mouseReleaseButton, button); + QCOMPARE(testMouseWidget->mouseReleaseButtons, buttons); + QCOMPARE(testMouseWidget->mouseReleaseModifiers, modifiers); +} + +QTEST_MAIN(tst_QMouseEvent) +#include "tst_qmouseevent.moc" diff --git a/tests/auto/gui/kernel/qmouseevent_modal/.gitignore b/tests/auto/gui/kernel/qmouseevent_modal/.gitignore new file mode 100644 index 0000000000..e15c9eb18c --- /dev/null +++ b/tests/auto/gui/kernel/qmouseevent_modal/.gitignore @@ -0,0 +1 @@ +tst_qmouseevent_modal diff --git a/tests/auto/gui/kernel/qmouseevent_modal/qmouseevent_modal.pro b/tests/auto/gui/kernel/qmouseevent_modal/qmouseevent_modal.pro new file mode 100644 index 0000000000..2f28de2675 --- /dev/null +++ b/tests/auto/gui/kernel/qmouseevent_modal/qmouseevent_modal.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qmouseevent_modal.cpp + + + diff --git a/tests/auto/gui/kernel/qmouseevent_modal/tst_qmouseevent_modal.cpp b/tests/auto/gui/kernel/qmouseevent_modal/tst_qmouseevent_modal.cpp new file mode 100644 index 0000000000..7006feeeb8 --- /dev/null +++ b/tests/auto/gui/kernel/qmouseevent_modal/tst_qmouseevent_modal.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qapplication.h> +#include <qfontinfo.h> + + +#include <qpushbutton.h> +#include <qscrollbar.h> +#include <qtimer.h> + +#include <qdialog.h> + + +//TESTED_CLASS= +//TESTED_FILES=gui/widgets/qmenubar.h gui/widgets/qmenubar.cpp + +class TstWidget; +class TstDialog; +QT_FORWARD_DECLARE_CLASS(QPushButton) + +class tst_qmouseevent_modal : public QObject +{ + Q_OBJECT + +public: + tst_qmouseevent_modal(); + virtual ~tst_qmouseevent_modal(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void mousePressRelease(); + +private: + TstWidget *w; +}; + +class TstWidget : public QWidget +{ + Q_OBJECT +public: + TstWidget(); +public slots: + void buttonPressed(); +public: + QPushButton *pb; + TstDialog *d; +}; + + +class TstDialog : public QDialog +{ + Q_OBJECT +public: + TstDialog( QWidget *mouseWidget, QWidget *parent, const char *name ); + int count() { return c; } +protected: + void showEvent ( QShowEvent * ); +public slots: + void releaseMouse(); + void closeDialog(); +private: + QWidget *m; + int c; +}; + +tst_qmouseevent_modal::tst_qmouseevent_modal() +{ +} + +tst_qmouseevent_modal::~tst_qmouseevent_modal() +{ +} + +void tst_qmouseevent_modal::initTestCase() +{ + w = new TstWidget; + w->show(); +} + +void tst_qmouseevent_modal::cleanupTestCase() +{ + delete w; + w = 0; +} + +void tst_qmouseevent_modal::init() +{ +} + +void tst_qmouseevent_modal::cleanup() +{ +} + +/* + Test for task 22500 +*/ +void tst_qmouseevent_modal::mousePressRelease() +{ + + QVERIFY( !w->d->isVisible() ); + QVERIFY( w->d->count() == 0 ); + + QTest::mousePress( w->pb, Qt::LeftButton ); + QTest::qWait(200); + + QVERIFY( !w->d->isVisible() ); + QVERIFY( w->d->count() == 1 ); + QVERIFY( !w->pb->isDown() ); + + QTest::mousePress( w->pb, Qt::LeftButton ); + QTest::qWait(200); + + QVERIFY( !w->d->isVisible() ); + QVERIFY( w->d->count() == 2 ); + QVERIFY( !w->pb->isDown() ); + + // With the current QWS mouse handling, the 3rd press would fail... + + QTest::mousePress( w->pb, Qt::LeftButton ); + QTest::qWait(200); + + QVERIFY( !w->d->isVisible() ); + QVERIFY( w->d->count() == 3 ); + QVERIFY( !w->pb->isDown() ); + + QTest::mousePress( w->pb, Qt::LeftButton ); + QTest::qWait(200); + + QVERIFY( !w->d->isVisible() ); + QVERIFY( w->d->count() == 4 ); + QVERIFY( !w->pb->isDown() ); +} + + +TstWidget::TstWidget() +{ + pb = new QPushButton( "Press me", this ); + pb->setObjectName("testbutton"); + QSize s = pb->sizeHint(); + pb->setGeometry( 5, 5, s.width(), s.height() ); + + connect( pb, SIGNAL(pressed()), this, SLOT(buttonPressed()) ); + +// QScrollBar *sb = new QScrollBar( Qt::Horizontal, this ); + +// sb->setGeometry( 5, pb->geometry().bottom() + 5, 100, sb->sizeHint().height() ); + + d = new TstDialog( pb, this , 0 ); +} + +void TstWidget::buttonPressed() +{ + d->exec(); +} + +TstDialog::TstDialog( QWidget *mouseWidget, QWidget *parent, const char *name ) + :QDialog( parent ) +{ + setObjectName(name); + setModal(true); + m = mouseWidget; + c = 0; +} + +void TstDialog::showEvent ( QShowEvent * ) +{ + QTimer::singleShot(1, this, SLOT(releaseMouse())); + QTimer::singleShot(100, this, SLOT(closeDialog())); +} + +void TstDialog::releaseMouse() +{ + QTest::mouseRelease(m, Qt::LeftButton); +} + +void TstDialog::closeDialog() +{ + if ( isVisible() ) { + c++; + accept(); + } +} + +QTEST_MAIN(tst_qmouseevent_modal) +#include "tst_qmouseevent_modal.moc" diff --git a/tests/auto/gui/kernel/qpalette/.gitignore b/tests/auto/gui/kernel/qpalette/.gitignore new file mode 100644 index 0000000000..3c1aebac19 --- /dev/null +++ b/tests/auto/gui/kernel/qpalette/.gitignore @@ -0,0 +1 @@ +tst_qpalette diff --git a/tests/auto/gui/kernel/qpalette/qpalette.pro b/tests/auto/gui/kernel/qpalette/qpalette.pro new file mode 100644 index 0000000000..4b240e5f9c --- /dev/null +++ b/tests/auto/gui/kernel/qpalette/qpalette.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qpalette.cpp + + + diff --git a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp new file mode 100644 index 0000000000..b63b8bf7b0 --- /dev/null +++ b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include "qpalette.h" +#include <qapplication.h> + +//TESTED_CLASS=QPalette +//TESTED_FILES=qpalette.h qpalette.cpp + +class tst_QPalette : public QObject +{ +Q_OBJECT + +public: + tst_QPalette(); + virtual ~tst_QPalette(); + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void roleValues_data(); + void roleValues(); +}; + +tst_QPalette::tst_QPalette() +{ +} + +tst_QPalette::~tst_QPalette() +{ +} + +void tst_QPalette::initTestCase() +{ +} + +void tst_QPalette::cleanupTestCase() +{ +} + +void tst_QPalette::init() +{ +} + +void tst_QPalette::cleanup() +{ +} + +void tst_QPalette::roleValues_data() +{ + QTest::addColumn<int>("role"); + QTest::addColumn<int>("value"); + + QTest::newRow("QPalette::WindowText") << int(QPalette::WindowText) << 0; + QTest::newRow("QPalette::Button") << int(QPalette::Button) << 1; + QTest::newRow("QPalette::Light") << int(QPalette::Light) << 2; + QTest::newRow("QPalette::Midlight") << int(QPalette::Midlight) << 3; + QTest::newRow("QPalette::Dark") << int(QPalette::Dark) << 4; + QTest::newRow("QPalette::Mid") << int(QPalette::Mid) << 5; + QTest::newRow("QPalette::Text") << int(QPalette::Text) << 6; + QTest::newRow("QPalette::BrightText") << int(QPalette::BrightText) << 7; + QTest::newRow("QPalette::ButtonText") << int(QPalette::ButtonText) << 8; + QTest::newRow("QPalette::Base") << int(QPalette::Base) << 9; + QTest::newRow("QPalette::Window") << int(QPalette::Window) << 10; + QTest::newRow("QPalette::Shadow") << int(QPalette::Shadow) << 11; + QTest::newRow("QPalette::Highlight") << int(QPalette::Highlight) << 12; + QTest::newRow("QPalette::HighlightedText") << int(QPalette::HighlightedText) << 13; + QTest::newRow("QPalette::Link") << int(QPalette::Link) << 14; + QTest::newRow("QPalette::LinkVisited") << int(QPalette::LinkVisited) << 15; + QTest::newRow("QPalette::AlternateBase") << int(QPalette::AlternateBase) << 16; + QTest::newRow("QPalette::NoRole") << int(QPalette::NoRole) << 17; + QTest::newRow("QPalette::ToolTipBase") << int(QPalette::ToolTipBase) << 18; + QTest::newRow("QPalette::ToolTipText") << int(QPalette::ToolTipText) << 19; + + // Change this value as you add more roles. + QTest::newRow("QPalette::NColorRoles") << int(QPalette::NColorRoles) << 20; +} + +void tst_QPalette::roleValues() +{ + QFETCH(int, role); + QFETCH(int, value); + QCOMPARE(role, value); +} + +QTEST_MAIN(tst_QPalette) +#include "tst_qpalette.moc" diff --git a/tests/auto/gui/kernel/qshortcut/.gitignore b/tests/auto/gui/kernel/qshortcut/.gitignore new file mode 100644 index 0000000000..3a17eb18e3 --- /dev/null +++ b/tests/auto/gui/kernel/qshortcut/.gitignore @@ -0,0 +1 @@ +tst_qshortcut diff --git a/tests/auto/gui/kernel/qshortcut/qshortcut.pro b/tests/auto/gui/kernel/qshortcut/qshortcut.pro new file mode 100644 index 0000000000..3f68d2377e --- /dev/null +++ b/tests/auto/gui/kernel/qshortcut/qshortcut.pro @@ -0,0 +1,11 @@ +load(qttest_p4) + +# Project Configuration ---------------------------------------------- +INCLUDEPATH += ../ + +# Normal Test Files -------------------------------------------------- +QT += widgets +HEADERS += +SOURCES += tst_qshortcut.cpp + + diff --git a/tests/auto/gui/kernel/qshortcut/tst_qshortcut.cpp b/tests/auto/gui/kernel/qshortcut/tst_qshortcut.cpp new file mode 100644 index 0000000000..d761b19542 --- /dev/null +++ b/tests/auto/gui/kernel/qshortcut/tst_qshortcut.cpp @@ -0,0 +1,1273 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qapplication.h> +#include <qtextedit.h> +#include <qpushbutton.h> +#include <qmainwindow.h> +#include <qstatusbar.h> +#include <qboxlayout.h> +#include <qdebug.h> +#include <qstring.h> +#include <qshortcut.h> + +class AccelForm; +QT_BEGIN_NAMESPACE +class QMainWindow; +class QTextEdit; +QT_END_NAMESPACE + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QShortcut : public QObject +{ + Q_OBJECT +public: + tst_QShortcut(); + virtual ~tst_QShortcut(); + + + enum Action { + SetupAccel, + TestAccel, + ClearAll + } currentAction; + + enum Widget { + NoWidget, + TriggerSlot1, + TriggerSlot2, + TriggerSlot3, + TriggerSlot4, + TriggerSlot5, + TriggerSlot6, + TriggerSlot7 + }; + + enum Result { + NoResult, + Slot1Triggered, + Slot2Triggered, + Slot3Triggered, + Slot4Triggered, + Slot5Triggered, + Slot6Triggered, + Slot7Triggered, + Ambiguous + } currentResult; + +public slots: + void slotTrig1() { currentResult = Slot1Triggered; } + void slotTrig2() { currentResult = Slot2Triggered; } + void slotTrig3() { currentResult = Slot3Triggered; } + void slotTrig4() { currentResult = Slot4Triggered; } + void slotTrig5() { currentResult = Slot5Triggered; } + void slotTrig6() { currentResult = Slot6Triggered; } + void slotTrig7() { currentResult = Slot7Triggered; } + void ambigSlot1() { currentResult = Ambiguous; ambigResult = Slot1Triggered; } + void ambigSlot2() { currentResult = Ambiguous; ambigResult = Slot2Triggered; } + void ambigSlot3() { currentResult = Ambiguous; ambigResult = Slot3Triggered; } + void ambigSlot4() { currentResult = Ambiguous; ambigResult = Slot4Triggered; } + void ambigSlot5() { currentResult = Ambiguous; ambigResult = Slot5Triggered; } + void ambigSlot6() { currentResult = Ambiguous; ambigResult = Slot6Triggered; } + void ambigSlot7() { currentResult = Ambiguous; ambigResult = Slot7Triggered; } + void statusMessage( const QString& message ) { sbText = message; } + void shortcutDestroyed(QObject* obj); + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void number_data(); + void number(); + void text_data(); + void text(); + void disabledItems(); + void ambiguousItems(); + void ambiguousRotation(); + void keypressConsumption(); + void unicodeCompare(); + void context(); + +protected: + static Qt::KeyboardModifiers toButtons( int key ); + void defElements(); + + void clearAllShortcuts(); + QShortcut *setupShortcut(int testWidget, const QKeySequence &ks); + QShortcut *setupShortcut(int testWidget, const QString &txt, int k1 = 0, int k2 = 0, int k3 = 0, int k4 = 0); + + QShortcut *setupShortcut(QWidget *parent, const char *name, int testWidget, const QString &txt, int k1 = 0, int k2 = 0, int k3 = 0, int k4 = 0); + QShortcut *setupShortcut(QWidget *parent, const char *name, int testWidget, const QKeySequence &ks, Qt::ShortcutContext context = Qt::WindowShortcut); + + void sendKeyEvents(QWidget *w, int k1, QChar c1 = 0, int k2 = 0, QChar c2 = 0, int k3 = 0, QChar c3 = 0, int k4 = 0, QChar c4 = 0); + void sendKeyEvents(int k1, QChar c1 = 0, int k2 = 0, QChar c2 = 0, int k3 = 0, QChar c3 = 0, int k4 = 0, QChar c4 = 0); + + void testElement(); + + QMainWindow *mainW; + QList<QShortcut*> shortcuts; + QTextEdit *edit; + QString sbText; + Result ambigResult; +}; + +QT_BEGIN_NAMESPACE +template<> struct QMetaTypeId<tst_QShortcut::Widget> +{ enum { Defined = 1 }; static inline int qt_metatype_id() { return QMetaType::Int; } }; +template<> struct QMetaTypeId<tst_QShortcut::Result> +{ enum { Defined = 1 }; static inline int qt_metatype_id() { return QMetaType::Int; } }; +template<> struct QMetaTypeId<tst_QShortcut::Action> +{ enum { Defined = 1 }; static inline int qt_metatype_id() { return QMetaType::Int; } }; +QT_END_NAMESPACE + +class TestEdit : public QTextEdit +{ + Q_OBJECT +public: + TestEdit(QWidget *parent, const char *name) + : QTextEdit(parent) + { + setObjectName(name); + } + +protected: + bool event(QEvent *e) { + // Make testedit allow any Ctrl+Key as shortcut + if (e->type() == QEvent::ShortcutOverride) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + if (ke->modifiers() == Qt::ControlModifier + && ke->key() > Qt::Key_Any + && ke->key() < Qt::Key_ydiaeresis) { + ke->ignore(); + return true; + } + } + + // If keypress not processed as normal, check for + // Ctrl+Key event, and input custom string for + // result comparison. + if (e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent*>(e); + if (ke->modifiers() && ke->key() > Qt::Key_Any + && ke->key() < Qt::Key_ydiaeresis) { + if (ke->modifiers() == Qt::ControlModifier) + insertPlainText(QString("<Ctrl+%1>").arg(char(ke->key()))); + else if (ke->modifiers() == Qt::AltModifier) + insertPlainText(QString("<Alt+%1>").arg(char(ke->key()))); + else if (ke->modifiers() == Qt::ShiftModifier) + insertPlainText(QString("<Shift+%1>").arg(char(ke->key()))); + return true; + } + } + return QTextEdit::event(e); + } +}; + +tst_QShortcut::tst_QShortcut(): mainW( 0 ) +{ +} + +tst_QShortcut::~tst_QShortcut() +{ + clearAllShortcuts(); +} + +void tst_QShortcut::initTestCase() +{ + currentResult = NoResult; + mainW = new QMainWindow(0); + mainW->setWindowFlags(Qt::X11BypassWindowManagerHint); + edit = new TestEdit(mainW, "test_edit"); + mainW->setFixedSize( 100, 100 ); + mainW->setCentralWidget( edit ); + mainW->show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(mainW); +#endif + mainW->activateWindow(); + QTest::qWait(100); + connect( mainW->statusBar(), SIGNAL(messageChanged(const QString&)), + this, SLOT(statusMessage(const QString&)) ); +} + +void tst_QShortcut::cleanupTestCase() +{ + delete mainW; +} + +Qt::KeyboardModifiers tst_QShortcut::toButtons( int key ) +{ + Qt::KeyboardModifiers result = Qt::NoModifier; + if ( key & Qt::SHIFT ) + result |= Qt::ShiftModifier; + if ( key & Qt::CTRL ) + result |= Qt::ControlModifier; + if ( key & Qt::META ) + result |= Qt::MetaModifier; + if ( key & Qt::ALT ) + result |= Qt::AltModifier; + return result; +} + +void tst_QShortcut::defElements() +{ + QTest::addColumn<int>("action"); + QTest::addColumn<int>("testWidget"); + QTest::addColumn<QString>("txt"); + QTest::addColumn<int>("k1"); + QTest::addColumn<int>("c1"); + QTest::addColumn<int>("k2"); + QTest::addColumn<int>("c2"); + QTest::addColumn<int>("k3"); + QTest::addColumn<int>("c3"); + QTest::addColumn<int>("k4"); + QTest::addColumn<int>("c4"); + QTest::addColumn<int>("result"); +} + +void tst_QShortcut::number() +{ + // We expect a failure on these tests, until QtTestKeyboard is + // fixed to do real platform dependent keyboard simulations + if (QTest::currentDataTag() == QString("N006a:Shift+Tab - [BackTab]") + || QTest::currentDataTag() == QString("N006b:Shift+Tab - [Shift+BackTab]")) + QEXPECT_FAIL("", "FLAW IN QTESTKEYBOARD: Keyboard events not passed through " + "platform dependent key handling code", Continue); + testElement(); +} +void tst_QShortcut::text() +{ + testElement(); +} +// ------------------------------------------------------------------ +// Number Elements -------------------------------------------------- +// ------------------------------------------------------------------ +void tst_QShortcut::number_data() +{ + defElements(); + + // Clear all + QTest::newRow("N00 - clear") << ClearAll <<0<<QString("")<<0<<0<<0<<0<<0<<0<<0<<0<<0; + + //=========================================== + // [Shift + key] on non-shift shortcuts testing + //=========================================== + + /* Testing Single Sequences + Shift + Qt::Key_M on Qt::Key_M + Qt::Key_M on Qt::Key_M + Shift + Qt::Key_Plus on Qt::Key_Pluss + Qt::Key_Plus on Qt::Key_Pluss + */ + QTest::newRow("N001 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("N001:Shift + M - [M]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N001:M - [M]") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N001 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("N001:Shift++ [+]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N001:+ [+]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N001 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Shift + Qt::Key_M on Shift + Qt::Key_M + Qt::Key_M on Shift + Qt::Key_M + Shift + Qt::Key_Plus on Shift + Qt::Key_Pluss + Qt::Key_Plus on Shift + Qt::Key_Pluss + */ + QTest::newRow("N002 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::SHIFT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N002:M - [Shift+M]") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N002 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N002:Shift++ [Shift++]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N002:+ [Shift++]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N002 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Shift + Qt::Key_F1 on Qt::Key_F1 + Qt::Key_F1 on Qt::Key_F1 + */ + QTest::newRow("N003 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("N003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N003:F1 - [F1]") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N003 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + /* Testing Single Sequences + Shift + Qt::Key_F1 on Shift + Qt::Key_F1 + Qt::Key_F1 on Shift + Qt::Key_F1 + */ + + QTest::newRow("N004 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N004:Shift+F1 - [Shift+F1]")<< TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N004 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Qt::Key_Tab on Qt::Key_Tab + Shift + Qt::Key_Tab on Qt::Key_Tab + Qt::Key_Backtab on Qt::Key_Tab + Shift + Qt::Key_Backtab on Qt::Key_Tab + */ + QTest::newRow("N005a - slot1") << SetupAccel << TriggerSlot1 << QString("")<< int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005a:Tab - [Tab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("N005a:Shift+Tab - [Tab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + // (Shift+)BackTab != Tab, but Shift+BackTab == Shift+Tab + QTest::newRow("N005a:Backtab - [Tab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005a:Shift+Backtab - [Tab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005a - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Qt::Key_Tab on Shift + Qt::Key_Tab + Shift + Qt::Key_Tab on Shift + Qt::Key_Tab + Qt::Key_Backtab on Shift + Qt::Key_Tab + Shift + Qt::Key_Backtab on Shift + Qt::Key_Tab + */ + QTest::newRow("N005b - slot1") << SetupAccel << TriggerSlot1 << QString("")<< int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005b:Tab - [Shift+Tab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005b:Shift+Tab - [Shift+Tab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N005b:BackTab - [Shift+Tab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N005b:Shift+BackTab - [Shift+Tab]")<< TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N005b - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Qt::Key_Tab on Qt::Key_Backtab + Shift + Qt::Key_Tab on Qt::Key_Backtab + Qt::Key_Backtab on Qt::Key_Backtab + Shift + Qt::Key_Backtab on Qt::Key_Backtab + */ + QTest::newRow("N006a - slot1") << SetupAccel << TriggerSlot1 << QString("")<< int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006a:Tab - [BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + // This should work, since platform dependent code will transform the + // Shift+Tab into a Shift+BackTab, which should trigger the shortcut + QTest::newRow("N006a:Shift+Tab - [BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL + QTest::newRow("N006a:BackTab - [BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("N006a:Shift+BackTab - [BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N006a - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Qt::Key_Tab on Shift + Qt::Key_Backtab + Shift + Qt::Key_Tab on Shift + Qt::Key_Backtab + Qt::Key_Backtab on Shift + Qt::Key_Backtab + Shift + Qt::Key_Backtab on Shift + Qt::Key_Backtab + */ + QTest::newRow("N006b - slot1") << SetupAccel << TriggerSlot1 << QString("")<< int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006b:Tab - [Shift+BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006b:Shift+Tab - [Shift+BackTab]")<< TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Tab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N006b:BackTab - [Shift+BackTab]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N006b:Shift+BackTab - [Shift+BackTab]")<< TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Backtab) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; //XFAIL + QTest::newRow("N006b - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + //=========================================== + // [Shift + key] and [key] on shortcuts with + // and without modifiers + //=========================================== + + /* Testing Single Sequences + Qt::Key_F1 + Shift + Qt::Key_F1 + */ + QTest::newRow("N007 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N007 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N007:F1") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N007:Shift + F1") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N007 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Qt::Key_M + Shift + Qt::Key_M + Ctrl + Qt::Key_M + Alt + Qt::Key_M + */ + QTest::newRow("N01 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N02 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N03 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N04 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N:Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Shift+Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N:Ctrl+Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Alt+Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + + /* Testing Single Sequence Ambiguity + Qt::Key_M on shortcut2 + */ + QTest::newRow("N05 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N:Qt::Key_M on slot") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous; + QTest::newRow("N05 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Specialkeys + Qt::Key_aring + Qt::Key_Aring + Qt::UNICODE_ACCEL + Qt::Key_K + */ + QTest::newRow("N06 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N07 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N08 - slot2") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::UNICODE_ACCEL + Qt::Key_K) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + + QTest::newRow("N:Qt::Key_aring") << TestAccel << NoWidget << QString("") << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Qt::Key_Aring") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString("") << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N:Qt::UNICODE_ACCEL + Qt::Key_K") << TestAccel << NoWidget << QString("") << int(Qt::UNICODE_ACCEL + Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N09 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Multiple Sequences + Qt::Key_M + Qt::Key_I, Qt::Key_M + Shift+Qt::Key_I, Qt::Key_M + */ + QTest::newRow("N10 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N11 - slot2") << SetupAccel << TriggerSlot2 << QString("") << int(Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("N12 - slot1") << SetupAccel << TriggerSlot1 << QString("") << int(Qt::SHIFT + Qt::Key_I) << 0 << int(Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << NoResult; + + QTest::newRow("N:Qt::Key_M (2)") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("N:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("N13 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all +} + +// ------------------------------------------------------------------ +// Text Elements ---------------------------------------------------- +// ------------------------------------------------------------------ +void tst_QShortcut::text_data() +{ + defElements(); + // Clear all + QTest::newRow("T00 - clear") << ClearAll <<0<<QString("")<<0<<0<<0<<0<<0<<0<<0<<0<<0; + + //=========================================== + // [Shift + key] on non-shift shortcuts testing + //=========================================== + + /* Testing Single Sequences + Shift + Qt::Key_M on Qt::Key_M + Qt::Key_M on Qt::Key_M + Shift + Qt::Key_Plus on Qt::Key_Pluss + Qt::Key_Plus on Qt::Key_Pluss + */ + QTest::newRow("T001 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("T001:Shift+M - [M]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T001:M - [M]") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T001 - slot2") << SetupAccel << TriggerSlot2 << QString("+") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("T001:Shift++ [+]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T001:+ [+]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T001 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Shift + Qt::Key_M on Shift + Qt::Key_M + Qt::Key_M on Shift + Qt::Key_M + Shift + Qt::Key_Plus on Shift + Qt::Key_Pluss + Qt::Key_Plus on Shift + Qt::Key_Pluss + Shift + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Pluss + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Pluss + */ + QTest::newRow("T002 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T002:Shift+M - [Shift+M]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T002:M - [Shift+M]") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T002 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T002:Shift++ [Shift++]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T002:+ [Shift++]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T002 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Shift + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Plus + Ctrl + Qt::Key_Plus on Ctrl + Qt::Key_Plus + Qt::Key_Plus on Ctrl + Qt::Key_Plus + */ + QTest::newRow("T002b - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl++") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("T002b:Shift+Ctrl++ [Ctrl++]")<< TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T002b:Ctrl++ [Ctrl++]") << TestAccel << NoWidget << QString("") << int(Qt::CTRL + Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T002b:+ [Ctrl++]") << TestAccel << NoWidget << QString("") << int(Qt::Key_Plus) << int('+') << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T002b - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Shift + Qt::Key_F1 on Qt::Key_F1 + Qt::Key_F1 on Qt::Key_F1 + */ + QTest::newRow("T003 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + //commented out because the behaviour changed, those tests should be updated + //QTest::newRow("T003:Shift+F1 - [F1]") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T003:F1 - [F1]") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T003 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Shift + Qt::Key_F1 on Shift + Qt::Key_F1 + Qt::Key_F1 on Shift + Qt::Key_F1 + */ + QTest::newRow("T004 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T004:Shift+F1 - [Shift+F1]")<< TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T004:F1 - [Shift+F1]") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T004 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + //=========================================== + // [Shift + key] and [key] on shortcuts with + // and without modifiers + //=========================================== + + /* Testing Single Sequences + Qt::Key_F1 + Shift + Qt::Key_F1 + */ + QTest::newRow("T007 - slot1") << SetupAccel << TriggerSlot1 << QString("F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T007 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+F1") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T007:F1") << TestAccel << NoWidget << QString("") << int(Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T007:Shift + F1") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_F1) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T007 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Sequences + Qt::Key_M + Shift + Qt::Key_M + Ctrl + Qt::Key_M + Alt + Qt::Key_M + */ + QTest::newRow("T01 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T02 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T03 - slot1") << SetupAccel << TriggerSlot1 << QString("Ctrl+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T04 - slot2") << SetupAccel << TriggerSlot2 << QString("Alt+M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + + QTest::newRow("T:Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Shift + Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_M) << int('M') << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Ctrl + Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::CTRL + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Alt + Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::ALT + Qt::Key_M) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + + /* Testing Single Sequence Ambiguity + Qt::Key_M on shortcut2 + */ + QTest::newRow("T05 - slot2") << SetupAccel << TriggerSlot2 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T:Qt::Key_M on TriggerSlot2") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Ambiguous; + QTest::newRow("T06 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Single Specialkeys + Qt::Key_aring + Qt::Key_Aring + Qt::UNICODE_ACCEL + Qt::Key_K + */ + /* see comments above on the #ifdef'ery */ + QTest::newRow("T06 - slot1") << SetupAccel << TriggerSlot1 << QString("\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T07 - slot2") << SetupAccel << TriggerSlot2 << QString("Shift+\x0C5")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T08 - slot2") << SetupAccel << TriggerSlot1 << QString("K") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T:Qt::Key_aring") << TestAccel << NoWidget << QString("") << int(Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Qt::Key_Aring") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT+Qt::Key_Aring) << 0 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Qt::Key_aring - Text Form") << TestAccel << NoWidget << QString("") << 0 << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Qt::Key_Aring - Text Form") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT+0) << 0xC5 << 0 << 0 << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Qt::UNICODE_ACCEL + Qt::Key_K") << TestAccel << NoWidget << QString("") << int(Qt::UNICODE_ACCEL + Qt::Key_K) << int('k') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T09 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all + + /* Testing Multiple Sequences + Qt::Key_M + Qt::Key_I, Qt::Key_M + Shift+Qt::Key_I, Qt::Key_M + */ + QTest::newRow("T10 - slot1") << SetupAccel << TriggerSlot1 << QString("M") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T11 - slot2") << SetupAccel << TriggerSlot2 << QString("I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T12 - slot1") << SetupAccel << TriggerSlot1 << QString("Shift+I, M")<< 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << NoResult; + QTest::newRow("T:Qt::Key_M (2)") << TestAccel << NoWidget << QString("") << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T:Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::Key_I) << int('i') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot2Triggered; + QTest::newRow("T:Shift+Qt::Key_I, Qt::Key_M") << TestAccel << NoWidget << QString("") << int(Qt::SHIFT + Qt::Key_I) << int('I') << int(Qt::Key_M) << int('m') << 0 << 0 << 0 << 0 << Slot1Triggered; + QTest::newRow("T13 - clear") << ClearAll << 0 << QString("") << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; // Clear all +} + +// ------------------------------------------------------------------ +// Disabled Elements ------------------------------------------------ +// ------------------------------------------------------------------ +void tst_QShortcut::disabledItems() +{ + clearAllShortcuts(); + mainW->activateWindow(); + qApp->syncX(); + QTest::qWait(100); + + /* Testing Disabled Shortcuts + Qt::Key_M on slot1 + Shift + Qt::Key_M on slot1 + Qt::Key_M on slot2 (disabled) + Shift + Qt::Key_M on slot2 (disabled) + */ + + // Setup two identical shortcuts on different pushbuttons + QPushButton pb1(mainW); + QPushButton pb2(mainW); + pb1.setObjectName("pushbutton-1"); + pb2.setObjectName("pushbutton-2"); + pb1.show(); // Must be show for QShortcutMap::correctSubWindow to trigger + pb2.show(); + + QShortcut *cut1 = setupShortcut(&pb1, "shortcut1-pb1", TriggerSlot1, "M"); + QShortcut *cut2 = setupShortcut(&pb1, "shortcut2-pb1", TriggerSlot1, "Shift+M"); + QShortcut *cut3 = setupShortcut(&pb2, "shortcut3-pb2", TriggerSlot2, "M"); + QShortcut *cut4 = setupShortcut(&pb2, "shortcut4-pb2", TriggerSlot2, "Shift+M"); + + cut3->setEnabled(false); + cut4->setEnabled(false); + + currentResult = NoResult; + sendKeyEvents(Qt::Key_M, 'm'); + QCOMPARE(currentResult, Slot1Triggered); + + currentResult = NoResult; + sendKeyEvents(Qt::SHIFT+Qt::Key_M, 'M'); + QCOMPARE(currentResult, Slot1Triggered); + + cut2->setEnabled(false); + cut4->setEnabled(true); + + /* Testing Disabled Shortcuts + Qt::Key_M on slot1 + Shift + Qt::Key_M on slot1 (disabled) + Qt::Key_M on slot2 (disabled) + Shift + Qt::Key_M on slot2 + */ + currentResult = NoResult; + sendKeyEvents( Qt::Key_M, 'm' ); + QCOMPARE( currentResult, Slot1Triggered ); + + currentResult = NoResult; + sendKeyEvents( Qt::SHIFT+Qt::Key_M, 'M' ); + QCOMPARE( currentResult, Slot2Triggered ); + + + /* Testing Disabled Accel + Qt::Key_F5 on slot1 + Shift + Qt::Key_F5 on slot2 (disabled) + */ + clearAllShortcuts(); + cut1 = setupShortcut(&pb1, "shortcut1-pb1", TriggerSlot1, "F5"); + cut4 = setupShortcut(&pb2, "shortcut4-pb2", TriggerSlot2, "Shift+F5"); + + cut1->setKey(QKeySequence("F5")); + cut4->setKey(QKeySequence("Shift+F5")); + + cut1->setEnabled(true); + cut4->setEnabled(false); + + currentResult = NoResult; + sendKeyEvents( Qt::Key_F5, 0 ); + QCOMPARE( currentResult, Slot1Triggered ); + + currentResult = NoResult; + sendKeyEvents( Qt::SHIFT+Qt::Key_F5, 0 ); + QCOMPARE( currentResult, NoResult ); + +#if 0 + qFatal("Not testing statusbar text feedback yet, since not implemented"); + /* Testing Disabled Accel, and the corresponding statusbar feedback + Ctrl + Qt::Key_K, Ctrl + Qt::Key_L on slot1 + Ctrl + Qt::Key_K, Ctrl + Qt::Key_M on slot2 (disabled) + */ + cut1->setKey(QKeySequence("Ctrl+K, Ctrl+L")); + cut4->setKey(QKeySequence("Ctrl+K, Ctrl+M")); + + cut1->setEnabled(true); + cut4->setEnabled(false); + + currentResult = NoResult; + sendKeyEvents( Qt::CTRL+Qt::Key_K, 0 ); + sendKeyEvents( Qt::CTRL+Qt::Key_Q, 0 ); + QCOMPARE( currentResult, NoResult ); + if (over_330) + QCOMPARE( sbText, QString("Ctrl+K, Ctrl+Q not defined") ); + + currentResult = NoResult; + sendKeyEvents( Qt::CTRL+Qt::Key_K, 0 ); + sendKeyEvents( Qt::CTRL+Qt::Key_M, 0 ); + QCOMPARE( currentResult, NoResult ); + if (over_330) + QCOMPARE( sbText, QString::null ); + + currentResult = NoResult; + sendKeyEvents( Qt::CTRL+Qt::Key_K, 0 ); + sendKeyEvents( Qt::CTRL+Qt::Key_L, 0 ); + QCOMPARE( currentResult, Slot1Triggered ); + if (over_330) + QCOMPARE( sbText, QString::null ); +#endif + clearAllShortcuts(); + cut1 = 0; + cut4 = 0; +} +// ------------------------------------------------------------------ +// Ambiguous Elements ----------------------------------------------- +// ------------------------------------------------------------------ +void tst_QShortcut::ambiguousRotation() +{ + clearAllShortcuts(); + /* Testing Shortcut rotation scheme + Ctrl + Qt::Key_A on slot1 (disabled) + Ctrl + Qt::Key_A on slot2 (disabled) + Ctrl + Qt::Key_A on slot3 + Ctrl + Qt::Key_A on slot4 + Ctrl + Qt::Key_A on slot5 (disabled) + Ctrl + Qt::Key_A on slot6 + Ctrl + Qt::Key_A on slot7 (disabled) + */ + QShortcut *cut1 = setupShortcut(TriggerSlot1, "Ctrl+A"); + QShortcut *cut2 = setupShortcut(TriggerSlot2, "Ctrl+A"); + QShortcut *cut3 = setupShortcut(TriggerSlot3, "Ctrl+A"); + QShortcut *cut4 = setupShortcut(TriggerSlot4, "Ctrl+A"); + QShortcut *cut5 = setupShortcut(TriggerSlot5, "Ctrl+A"); + QShortcut *cut6 = setupShortcut(TriggerSlot6, "Ctrl+A"); + QShortcut *cut7 = setupShortcut(TriggerSlot7, "Ctrl+A"); + + cut1->setEnabled(false); + cut2->setEnabled(false); + cut5->setEnabled(false); + cut7->setEnabled(false); + + // Test proper rotation + // Start on first + // Go to last + // Go back to first + // Continue... + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot3Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot4Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot6Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot3Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot4Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot6Triggered); + + /* Testing Shortcut rotation scheme + Ctrl + Qt::Key_A on slot1 + Ctrl + Qt::Key_A on slot2 + Ctrl + Qt::Key_A on slot3 (disabled) + Ctrl + Qt::Key_A on slot4 (disabled) + Ctrl + Qt::Key_A on slot5 + Ctrl + Qt::Key_A on slot6 (disabled) + Ctrl + Qt::Key_A on slot7 + */ + + cut1->setEnabled(true); + cut2->setEnabled(true); + cut5->setEnabled(true); + cut7->setEnabled(true); + + cut3->setEnabled(false); + cut4->setEnabled(false); + cut6->setEnabled(false); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot1Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot2Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot5Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot7Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot1Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot2Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot5Triggered); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(Qt::CTRL+Qt::Key_A); + QCOMPARE(currentResult, Ambiguous); + QCOMPARE(ambigResult, Slot7Triggered); + + clearAllShortcuts(); + cut1 = 0; cut2 = 0; + cut3 = 0; cut4 = 0; + cut5 = 0; cut6 = 0; + cut7 = 0; +} + +void tst_QShortcut::ambiguousItems() +{ + clearAllShortcuts(); + /* Testing Ambiguous Shortcuts + Qt::Key_M on Pushbutton 1 + Qt::Key_M on Pushbutton 2 + */ + + // Setup two identical shortcuts on different pushbuttons + QPushButton pb1(mainW); + QPushButton pb2(mainW); + pb1.setObjectName("pushbutton-1"); + pb2.setObjectName("pushbutton-2"); + pb1.show(); // Must be show for QShortcutMap::correctSubWindow to trigger + pb2.show(); + + QShortcut *cut1 = setupShortcut(&pb1, "shortcut1-pb1", TriggerSlot1, "M"); + QShortcut *cut2 = setupShortcut(&pb1, "shortcut2-pb2", TriggerSlot2, "M"); + + currentResult = NoResult; + sendKeyEvents( Qt::Key_M, 'm' ); + QCOMPARE( currentResult, Ambiguous ); + QCOMPARE( ambigResult, Slot1Triggered ); + + currentResult = NoResult; + sendKeyEvents( Qt::Key_M, 'm' ); + QCOMPARE( currentResult, Ambiguous ); + QCOMPARE( ambigResult, Slot2Triggered ); + + currentResult = NoResult; + sendKeyEvents( Qt::Key_M, 'm' ); + QCOMPARE( currentResult, Ambiguous ); + QCOMPARE( ambigResult, Slot1Triggered ); + + clearAllShortcuts(); + cut1 = 0; cut2 = 0; +} + + +// ------------------------------------------------------------------ +// Unicode and non-unicode Elements --------------------------------- +// ------------------------------------------------------------------ +void tst_QShortcut::unicodeCompare() +{ + clearAllShortcuts(); + /* Testing Unicode/non-Unicode Shortcuts + Qt::Key_M on Pushbutton 1 + Qt::Key_M on Pushbutton 2 + */ + QPushButton pb1(mainW); + QPushButton pb2(mainW); + pb1.setObjectName("pushbutton-1"); + pb2.setObjectName("pushbutton-2"); + pb1.show(); // Must be show for QShortcutMap::correctSubWindow to trigger + pb2.show(); + + QKeySequence ks1("Ctrl+M"); // Unicode + QKeySequence ks2(Qt::CTRL+Qt::Key_M); // non-Unicode + QShortcut *cut1 = setupShortcut(&pb1, "shortcut1-pb1", TriggerSlot1, ks1); + QShortcut *cut2 = setupShortcut(&pb1, "shortcut2-pb2", TriggerSlot2, ks2); + + currentResult = NoResult; + sendKeyEvents( Qt::CTRL+Qt::Key_M, 0 ); + QCOMPARE( currentResult, Ambiguous ); + // They _are_ ambiguous, so the QKeySequence operator== + // should indicate the same + QVERIFY( ks1 == ks2 ); + QVERIFY( !(ks1 != ks2) ); + + clearAllShortcuts(); + cut1 = 0; cut2 = 0; +} + +// ------------------------------------------------------------------ +// Keypress consumption verification -------------------------------- +// ------------------------------------------------------------------ +void tst_QShortcut::keypressConsumption() +{ + clearAllShortcuts(); + edit->clear(); + QCOMPARE(edit->toPlainText().size(), 0); + + QShortcut *cut1 = setupShortcut(edit, "shortcut1-line", TriggerSlot1, "Ctrl+I, A"); + QShortcut *cut2 = setupShortcut(edit, "shortcut1-line", TriggerSlot2, "Ctrl+I, B"); + + currentResult = NoResult; + ambigResult = NoResult; + sendKeyEvents(edit, Qt::CTRL + Qt::Key_I, 0); // Send key to edit + QCOMPARE( currentResult, NoResult ); + QCOMPARE( ambigResult, NoResult ); + QCOMPARE(edit->toPlainText(), QString("")); + + // Make sure next keypress is eaten (failing multiple keysequence) + sendKeyEvents(edit, Qt::Key_C, 'c'); // Send key to edit + QCOMPARE( currentResult, NoResult ); + QCOMPARE( ambigResult, NoResult ); + QCOMPARE(edit->toPlainText(), QString("")); + + // Next keypress should be normal + sendKeyEvents(edit, Qt::Key_C, 'c'); // Send key to edit + QCOMPARE( currentResult, NoResult ); + QCOMPARE( ambigResult, NoResult ); + QCOMPARE(edit->toPlainText(), QString("c")); + + currentResult = NoResult; + ambigResult = NoResult; + edit->clear(); + QCOMPARE(edit->toPlainText().size(), 0); + + cut1->setEnabled(false); + cut2->setEnabled(false); + + // Make sure keypresses is passed on, since all multiple keysequences + // with Ctrl+I are disabled + sendKeyEvents(edit, Qt::CTRL + Qt::Key_I, 0); // Send key to edit + QCOMPARE( currentResult, NoResult ); + QCOMPARE( ambigResult, NoResult ); + QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>")); + + sendKeyEvents(edit, Qt::Key_A, 'a'); // Send key to edit + QCOMPARE( currentResult, NoResult ); + QCOMPARE( ambigResult, NoResult ); + QVERIFY(edit->toPlainText().endsWith("<Ctrl+I>a")); + + clearAllShortcuts(); +} + +// ------------------------------------------------------------------ +// Context Validation ----------------------------------------------- +// ------------------------------------------------------------------ +void tst_QShortcut::context() +{ + clearAllShortcuts(); + + QWidget myBox; + TestEdit *other1 = new TestEdit(&myBox, "test_edit_other1"); + TestEdit *other2 = new TestEdit(&myBox, "test_edit_other2"); + QHBoxLayout *layout = new QHBoxLayout(&myBox); + layout->addWidget(other1); + layout->addWidget(other2); + myBox.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&myBox); +#endif + + setupShortcut(other1, "ActiveWindow", TriggerSlot1, QKeySequence("Alt+1"), Qt::WindowShortcut); + setupShortcut(other2, "Focus", TriggerSlot2, QKeySequence("Alt+2"), Qt::WidgetShortcut); + setupShortcut(edit, "Application", TriggerSlot3, QKeySequence("Alt+3"), Qt::ApplicationShortcut); + + currentResult = NoResult; + ambigResult = NoResult; + edit->clear(); + other1->clear(); + other2->clear(); + + // edit doesn't have focus, so ActiveWindow context should work + // ..but Focus context shouldn't.. + // Changing focus to edit should make focus context work + // Application context should always work + + + // Focus on 'other1' edit, so Active Window context should trigger + other1->activateWindow(); // <--- + QApplication::setActiveWindow(other1); + QCOMPARE(qApp->activeWindow(), other1->window()); + QCOMPARE(qApp->focusWidget(), (QWidget *)other1); + + currentResult = NoResult; + ambigResult = NoResult; + edit->clear(); + other1->clear(); + other2->clear(); + + QCOMPARE(qApp->focusWidget(), (QWidget *)other1); + sendKeyEvents(other1, Qt::ALT+Qt::Key_1); + QCOMPARE(currentResult, Slot1Triggered); + QCOMPARE(ambigResult, NoResult); + QCOMPARE(edit->toPlainText(), QString("")); + QCOMPARE(other1->toPlainText(), QString("")); + QCOMPARE(other2->toPlainText(), QString("")); + + // ..but not Focus context on 'other2'.. + currentResult = NoResult; + ambigResult = NoResult; + edit->clear(); + other1->clear(); + other2->clear(); + + sendKeyEvents(other1, Qt::ALT+Qt::Key_2); + QCOMPARE(currentResult, NoResult); + QCOMPARE(ambigResult, NoResult); + QCOMPARE(edit->toPlainText(), QString("")); + QCOMPARE(other1->toPlainText(), QString("<Alt+2>")); + QCOMPARE(other2->toPlainText(), QString("")); + + // ..however, application global context on 'edit' should.. + currentResult = NoResult; + ambigResult = NoResult; + edit->clear(); + other1->clear(); + other2->clear(); + + sendKeyEvents(other1, Qt::ALT+Qt::Key_3); + QCOMPARE(currentResult, Slot3Triggered); + QCOMPARE(ambigResult, NoResult); + QCOMPARE(edit->toPlainText(), QString("")); + QCOMPARE(other1->toPlainText(), QString("")); + QCOMPARE(other2->toPlainText(), QString("")); + + // Changing focus to 'other2' should make the Focus context there work + other2->activateWindow(); + other2->setFocus(); // ### + qApp->syncX(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(other2); +#endif + QTest::qWait(100); + QCOMPARE(qApp->activeWindow(), other2->window()); + QCOMPARE(qApp->focusWidget(), (QWidget *)other2); + + currentResult = NoResult; + ambigResult = NoResult; + edit->clear(); + other1->clear(); + other2->clear(); + + sendKeyEvents(other2, Qt::ALT+Qt::Key_2); + QCOMPARE(currentResult, Slot2Triggered); + QCOMPARE(ambigResult, NoResult); + QCOMPARE(edit->toPlainText(), QString("")); + QCOMPARE(other1->toPlainText(), QString("")); + QCOMPARE(other2->toPlainText(), QString("")); + + clearAllShortcuts(); + delete other1; + delete other2; + edit->activateWindow(); + qApp->syncX(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(edit); +#endif + QTest::qWait(100); +} + +// ------------------------------------------------------------------ +// Element Testing helper functions --------------------------------- +// ------------------------------------------------------------------ +void tst_QShortcut::clearAllShortcuts() +{ + QList<QShortcut *> shortcutsCpy = shortcuts; + qDeleteAll(shortcutsCpy); + shortcuts.clear(); +} + +QShortcut *tst_QShortcut::setupShortcut(int testWidget, const QKeySequence &ks) +{ + return setupShortcut(mainW, QTest::currentDataTag() ? QTest::currentDataTag() : "", testWidget, ks); +} + +QShortcut *tst_QShortcut::setupShortcut(int testWidget, const QString &txt, int k1, int k2, int k3, int k4) +{ + return setupShortcut(mainW, QTest::currentDataTag() ? QTest::currentDataTag() : "", testWidget, + (txt.isEmpty() ? QKeySequence(k1, k2, k3, k4) : QKeySequence(txt))); +} + +QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const char *name, int testWidget, const QString &txt, int k1, int k2, int k3, int k4) +{ + return setupShortcut(parent, name, testWidget, + (txt.isEmpty() ? QKeySequence(k1, k2, k3, k4) : QKeySequence(txt))); +} + +QShortcut *tst_QShortcut::setupShortcut(QWidget *parent, const char *name, int testWidget, + const QKeySequence &ks, Qt::ShortcutContext context) +{ + // Set up shortcut for next test + QShortcut *cut = new QShortcut(QKeySequence(), parent, 0, 0, context); + cut->setObjectName(name); + cut->setKey(ks); + + const char *normal = 0; + const char *ambig = 0; + switch(testWidget) + { + case TriggerSlot1: + normal = SLOT(slotTrig1()); + ambig = SLOT(ambigSlot1()); + break; + case TriggerSlot2: + normal = SLOT(slotTrig2()); + ambig = SLOT(ambigSlot2()); + break; + case TriggerSlot3: + normal = SLOT(slotTrig3()); + ambig = SLOT(ambigSlot3()); + break; + case TriggerSlot4: + normal = SLOT(slotTrig4()); + ambig = SLOT(ambigSlot4()); + break; + case TriggerSlot5: + normal = SLOT(slotTrig5()); + ambig = SLOT(ambigSlot5()); + break; + case TriggerSlot6: + normal = SLOT(slotTrig6()); + ambig = SLOT(ambigSlot6()); + break; + case TriggerSlot7: + normal = SLOT(slotTrig7()); + ambig = SLOT(ambigSlot7()); + break; + } + connect(cut, SIGNAL(activated()), this, normal); + connect(cut, SIGNAL(activatedAmbiguously()), this, ambig); + connect(cut, SIGNAL(destroyed(QObject*)), this, SLOT(shortcutDestroyed(QObject*))); + shortcuts.append(cut); + return cut; +} + +void tst_QShortcut::shortcutDestroyed(QObject* obj) +{ + shortcuts.removeAll(static_cast<QShortcut *>(obj)); +} + +void tst_QShortcut::sendKeyEvents(int k1, QChar c1, int k2, QChar c2, int k3, QChar c3, int k4, QChar c4) +{ + sendKeyEvents(mainW, k1, c1, k2, c2, k3, c3, k4, c4); +} + +void tst_QShortcut::sendKeyEvents(QWidget *w, int k1, QChar c1, int k2, QChar c2, int k3, QChar c3, int k4, QChar c4) +{ + Qt::KeyboardModifiers b1 = toButtons( k1 ); + Qt::KeyboardModifiers b2 = toButtons( k2 ); + Qt::KeyboardModifiers b3 = toButtons( k3 ); + Qt::KeyboardModifiers b4 = toButtons( k4 ); + k1 &= ~Qt::MODIFIER_MASK; + k2 &= ~Qt::MODIFIER_MASK; + k3 &= ~Qt::MODIFIER_MASK; + k4 &= ~Qt::MODIFIER_MASK; + + + if (k1 || c1.toAscii()) { + QString c(c1.unicode() == QChar::Null ? QString() : QString(c1)); + QTest::sendKeyEvent(QTest::Press, w, static_cast<Qt::Key>(k1), c, b1); + QTest::sendKeyEvent(QTest::Release, w, static_cast<Qt::Key>(k1), c, b1); + } + + if (k2 || c2.toAscii()) { + QString c(c2.unicode() == QChar::Null ? QString() : QString(c2)); + QTest::sendKeyEvent(QTest::Press, w, static_cast<Qt::Key>(k2), c, b2); + QTest::sendKeyEvent(QTest::Release, w, static_cast<Qt::Key>(k2), c, b2); + } + + if (k3 || c3.toAscii()) { + QString c(c3.unicode() == QChar::Null ? QString() : QString(c3)); + QTest::sendKeyEvent(QTest::Press, w, static_cast<Qt::Key>(k3), c, b3); + QTest::sendKeyEvent(QTest::Release, w, static_cast<Qt::Key>(k3), c, b3); + } + + if (k4 || c4.toAscii()) { + QString c(c4.unicode() == QChar::Null ? QString() : QString(c4)); + QTest::sendKeyEvent(QTest::Press, w, static_cast<Qt::Key>(k4), c, b4); + QTest::sendKeyEvent(QTest::Release, w, static_cast<Qt::Key>(k4), c, b4); + } +} + +void tst_QShortcut::testElement() +{ + currentResult = NoResult; + QFETCH(int, action); + QFETCH(int, testWidget); + QFETCH(QString, txt); + QFETCH(int, k1); + QFETCH(int, c1); + QFETCH(int, k2); + QFETCH(int, c2); + QFETCH(int, k3); + QFETCH(int, c3); + QFETCH(int, k4); + QFETCH(int, c4); + QFETCH(int, result); + + if (action == ClearAll) { + clearAllShortcuts(); + QCOMPARE(TRUE, TRUE); + } else if (action == SetupAccel) { + setupShortcut(testWidget, txt, k1, k2, k3, k4); + QCOMPARE(TRUE, TRUE); + } else { + sendKeyEvents(k1, c1, k2, c2, k3, c3, k4, c4); + QCOMPARE(int(currentResult), result); + } +} + +QTEST_MAIN(tst_QShortcut) +#include "tst_qshortcut.moc" diff --git a/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro b/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro new file mode 100644 index 0000000000..55f99b6cdd --- /dev/null +++ b/tests/auto/gui/kernel/qtouchevent/qtouchevent.pro @@ -0,0 +1,3 @@ +SOURCES=tst_qtouchevent.cpp +TARGET=tst_qtouchevent +QT += testlib widgets diff --git a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp new file mode 100644 index 0000000000..401f79cbc2 --- /dev/null +++ b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp @@ -0,0 +1,1398 @@ +/**************************************************************************** +** +** 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 $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui> +#include <QtTest> + +class tst_QTouchEventWidget : public QWidget +{ +public: + QList<QTouchEvent::TouchPoint> touchBeginPoints, touchUpdatePoints, touchEndPoints; + bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; + bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; + bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; + + tst_QTouchEventWidget() + : QWidget() + { + reset(); + } + + void reset() + { + touchBeginPoints.clear(); + touchUpdatePoints.clear(); + touchEndPoints.clear(); + seenTouchBegin = seenTouchUpdate = seenTouchEnd = false; + acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true; + deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; + } + + bool event(QEvent *event) + { + switch (event->type()) { + case QEvent::TouchBegin: + if (seenTouchBegin) qWarning("TouchBegin: already seen a TouchBegin"); + if (seenTouchUpdate) qWarning("TouchBegin: TouchUpdate cannot happen before TouchBegin"); + if (seenTouchEnd) qWarning("TouchBegin: TouchEnd cannot happen before TouchBegin"); + seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; + touchBeginPoints = static_cast<QTouchEvent *>(event)->touchPoints(); + event->setAccepted(acceptTouchBegin); + if (deleteInTouchBegin) + delete this; + break; + case QEvent::TouchUpdate: + if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); + if (seenTouchEnd) qWarning("TouchUpdate: TouchEnd cannot happen before TouchUpdate"); + seenTouchUpdate = seenTouchBegin && !seenTouchEnd; + touchUpdatePoints = static_cast<QTouchEvent *>(event)->touchPoints(); + event->setAccepted(acceptTouchUpdate); + if (deleteInTouchUpdate) + delete this; + break; + case QEvent::TouchEnd: + if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); + if (seenTouchEnd) qWarning("TouchEnd: already seen a TouchEnd"); + seenTouchEnd = seenTouchBegin && !seenTouchEnd; + touchEndPoints = static_cast<QTouchEvent *>(event)->touchPoints(); + event->setAccepted(acceptTouchEnd); + if (deleteInTouchEnd) + delete this; + break; + default: + return QWidget::event(event); + } + return true; + } +}; + +class tst_QTouchEventGraphicsItem : public QGraphicsItem +{ +public: + QList<QTouchEvent::TouchPoint> touchBeginPoints, touchUpdatePoints, touchEndPoints; + bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; + int touchBeginCounter, touchUpdateCounter, touchEndCounter; + bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; + bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; + tst_QTouchEventGraphicsItem **weakpointer; + + tst_QTouchEventGraphicsItem() + : QGraphicsItem(), weakpointer(0) + { + reset(); + } + + ~tst_QTouchEventGraphicsItem() + { + if (weakpointer) + *weakpointer = 0; + } + + void reset() + { + touchBeginPoints.clear(); + touchUpdatePoints.clear(); + touchEndPoints.clear(); + seenTouchBegin = seenTouchUpdate = seenTouchEnd = false; + touchBeginCounter = touchUpdateCounter = touchEndCounter = 0; + acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true; + deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; + } + + QRectF boundingRect() const { return QRectF(0, 0, 10, 10); } + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) { } + + bool sceneEvent(QEvent *event) + { + switch (event->type()) { + case QEvent::TouchBegin: + if (seenTouchBegin) qWarning("TouchBegin: already seen a TouchBegin"); + if (seenTouchUpdate) qWarning("TouchBegin: TouchUpdate cannot happen before TouchBegin"); + if (seenTouchEnd) qWarning("TouchBegin: TouchEnd cannot happen before TouchBegin"); + seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; + ++touchBeginCounter; + touchBeginPoints = static_cast<QTouchEvent *>(event)->touchPoints(); + event->setAccepted(acceptTouchBegin); + if (deleteInTouchBegin) + delete this; + break; + case QEvent::TouchUpdate: + if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); + if (seenTouchEnd) qWarning("TouchUpdate: TouchEnd cannot happen before TouchUpdate"); + seenTouchUpdate = seenTouchBegin && !seenTouchEnd; + ++touchUpdateCounter; + touchUpdatePoints = static_cast<QTouchEvent *>(event)->touchPoints(); + event->setAccepted(acceptTouchUpdate); + if (deleteInTouchUpdate) + delete this; + break; + case QEvent::TouchEnd: + if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); + if (seenTouchEnd) qWarning("TouchEnd: already seen a TouchEnd"); + seenTouchEnd = seenTouchBegin && !seenTouchEnd; + ++touchEndCounter; + touchEndPoints = static_cast<QTouchEvent *>(event)->touchPoints(); + event->setAccepted(acceptTouchEnd); + if (deleteInTouchEnd) + delete this; + break; + default: + return QGraphicsItem::sceneEvent(event); + } + return true; + } +}; + +class tst_QTouchEvent : public QObject +{ + Q_OBJECT +public: + tst_QTouchEvent() { } + ~tst_QTouchEvent() { } + +private slots: + void touchDisabledByDefault(); + void touchEventAcceptedByDefault(); + void touchBeginPropagatesWhenIgnored(); + void touchUpdateAndEndNeverPropagate(); + void basicRawEventTranslation(); + void multiPointRawEventTranslationOnTouchScreen(); + void multiPointRawEventTranslationOnTouchPad(); + void deleteInEventHandler(); + void deleteInRawEventTranslation(); + void crashInQGraphicsSceneAfterNotHandlingTouchBegin(); + void touchBeginWithGraphicsWidget(); +}; + +void tst_QTouchEvent::touchDisabledByDefault() +{ + // QWidget + { + // the widget attribute is not enabled by default + QWidget widget; + QVERIFY(!widget.testAttribute(Qt::WA_AcceptTouchEvents)); + + // events should not be accepted since they are not enabled + QList<QTouchEvent::TouchPoint> touchPoints; + touchPoints.append(QTouchEvent::TouchPoint(0)); + QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + bool res = QApplication::sendEvent(&widget, &touchEvent); + QVERIFY(!res); + QVERIFY(!touchEvent.isAccepted()); + } + + // QGraphicsView + { + QGraphicsScene scene; + tst_QTouchEventGraphicsItem item; + QGraphicsView view(&scene); + scene.addItem(&item); + item.setPos(100, 100); + view.resize(200, 200); + view.fitInView(scene.sceneRect()); + + // touch events are not accepted by default + QVERIFY(!item.acceptTouchEvents()); + + // compose an event to the scene that is over the item + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(item.mapToScene(item.boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setScenePos(view.mapToScene(touchPoint.pos().toPoint())); + QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + (QList<QTouchEvent::TouchPoint>() << touchPoint)); + bool res = QApplication::sendEvent(view.viewport(), &touchEvent); + QVERIFY(!res); + QVERIFY(!touchEvent.isAccepted()); + QVERIFY(!item.seenTouchBegin); + } +} + +void tst_QTouchEvent::touchEventAcceptedByDefault() +{ + // QWidget + { + // enabling touch events should automatically accept touch events + QWidget widget; + widget.setAttribute(Qt::WA_AcceptTouchEvents); + + // QWidget handles touch event by converting them into a mouse event, so the event is both + // accepted and handled (res == true) + QList<QTouchEvent::TouchPoint> touchPoints; + touchPoints.append(QTouchEvent::TouchPoint(0)); + QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + bool res = QApplication::sendEvent(&widget, &touchEvent); + QVERIFY(res); + QVERIFY(touchEvent.isAccepted()); + + // tst_QTouchEventWidget does handle, sending succeeds + tst_QTouchEventWidget touchWidget; + touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); + touchEvent.ignore(); + res = QApplication::sendEvent(&touchWidget, &touchEvent); + QVERIFY(res); + QVERIFY(touchEvent.isAccepted()); + } + + // QGraphicsView + { + QGraphicsScene scene; + tst_QTouchEventGraphicsItem item; + QGraphicsView view(&scene); + scene.addItem(&item); + item.setPos(100, 100); + view.resize(200, 200); + view.fitInView(scene.sceneRect()); + + // enabling touch events on the item also enables events on the viewport + item.setAcceptTouchEvents(true); + QVERIFY(view.viewport()->testAttribute(Qt::WA_AcceptTouchEvents)); + + // compose an event to the scene that is over the item + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(item.mapToScene(item.boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setScenePos(view.mapToScene(touchPoint.pos().toPoint())); + QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + (QList<QTouchEvent::TouchPoint>() << touchPoint)); + bool res = QApplication::sendEvent(view.viewport(), &touchEvent); + QVERIFY(res); + QVERIFY(touchEvent.isAccepted()); + QVERIFY(item.seenTouchBegin); + } +} + +void tst_QTouchEvent::touchBeginPropagatesWhenIgnored() +{ + // QWidget + { + tst_QTouchEventWidget window, child, grandchild; + child.setParent(&window); + grandchild.setParent(&child); + + // all widgets accept touch events, grandchild ignores, so child sees the event, but not window + window.setAttribute(Qt::WA_AcceptTouchEvents); + child.setAttribute(Qt::WA_AcceptTouchEvents); + grandchild.setAttribute(Qt::WA_AcceptTouchEvents); + grandchild.acceptTouchBegin = false; + + QList<QTouchEvent::TouchPoint> touchPoints; + touchPoints.append(QTouchEvent::TouchPoint(0)); + QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + bool res = QApplication::sendEvent(&grandchild, &touchEvent); + QVERIFY(res); + QVERIFY(touchEvent.isAccepted()); + QVERIFY(grandchild.seenTouchBegin); + QVERIFY(child.seenTouchBegin); + QVERIFY(!window.seenTouchBegin); + + // disable touch on grandchild. even though it doesn't accept it, child should still get the + // TouchBegin + grandchild.reset(); + child.reset(); + window.reset(); + grandchild.setAttribute(Qt::WA_AcceptTouchEvents, false); + + touchEvent.ignore(); + res = QApplication::sendEvent(&grandchild, &touchEvent); + QVERIFY(res); + QVERIFY(touchEvent.isAccepted()); + QVERIFY(!grandchild.seenTouchBegin); + QVERIFY(child.seenTouchBegin); + QVERIFY(!window.seenTouchBegin); + } + + // QGraphicsView + { + QGraphicsScene scene; + tst_QTouchEventGraphicsItem root, child, grandchild; + QGraphicsView view(&scene); + scene.addItem(&root); + root.setPos(100, 100); + child.setParentItem(&root); + grandchild.setParentItem(&child); + view.resize(200, 200); + view.fitInView(scene.sceneRect()); + + // all items accept touch events, grandchild ignores, so child sees the event, but not root + root.setAcceptTouchEvents(true); + child.setAcceptTouchEvents(true); + grandchild.setAcceptTouchEvents(true); + grandchild.acceptTouchBegin = false; + + // compose an event to the scene that is over the grandchild + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(grandchild.mapToScene(grandchild.boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setScenePos(view.mapToScene(touchPoint.pos().toPoint())); + QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + (QList<QTouchEvent::TouchPoint>() << touchPoint)); + bool res = QApplication::sendEvent(view.viewport(), &touchEvent); + QVERIFY(res); + QVERIFY(touchEvent.isAccepted()); + QVERIFY(grandchild.seenTouchBegin); + QVERIFY(child.seenTouchBegin); + QVERIFY(!root.seenTouchBegin); + } + + // QGraphicsView + { + QGraphicsScene scene; + tst_QTouchEventGraphicsItem root, child, grandchild; + QGraphicsView view(&scene); + scene.addItem(&root); + root.setPos(100, 100); + child.setParentItem(&root); + grandchild.setParentItem(&child); + view.resize(200, 200); + view.fitInView(scene.sceneRect()); + + // leave touch disabled on grandchild. even though it doesn't accept it, child should + // still get the TouchBegin + root.setAcceptTouchEvents(true); + child.setAcceptTouchEvents(true); + + // compose an event to the scene that is over the grandchild + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(grandchild.mapToScene(grandchild.boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setScenePos(view.mapToScene(touchPoint.pos().toPoint())); + QTouchEvent touchEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + (QList<QTouchEvent::TouchPoint>() << touchPoint)); + bool res = QApplication::sendEvent(view.viewport(), &touchEvent); + QVERIFY(res); + QVERIFY(touchEvent.isAccepted()); + QVERIFY(!grandchild.seenTouchBegin); + QVERIFY(child.seenTouchBegin); + QVERIFY(!root.seenTouchBegin); + } +} + +void tst_QTouchEvent::touchUpdateAndEndNeverPropagate() +{ + // QWidget + { + tst_QTouchEventWidget window, child; + child.setParent(&window); + + window.setAttribute(Qt::WA_AcceptTouchEvents); + child.setAttribute(Qt::WA_AcceptTouchEvents); + child.acceptTouchUpdate = false; + child.acceptTouchEnd = false; + + QList<QTouchEvent::TouchPoint> touchPoints; + touchPoints.append(QTouchEvent::TouchPoint(0)); + QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + bool res = QApplication::sendEvent(&child, &touchBeginEvent); + QVERIFY(res); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(child.seenTouchBegin); + QVERIFY(!window.seenTouchBegin); + + // send the touch update to the child, but ignore it, it doesn't propagate + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointMoved, + touchPoints); + res = QApplication::sendEvent(&child, &touchUpdateEvent); + QVERIFY(res); + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(child.seenTouchUpdate); + QVERIFY(!window.seenTouchUpdate); + + // send the touch end, same thing should happen as with touch update + QTouchEvent touchEndEvent(QEvent::TouchEnd, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + touchPoints); + res = QApplication::sendEvent(&child, &touchEndEvent); + QVERIFY(res); + QVERIFY(!touchEndEvent.isAccepted()); + QVERIFY(child.seenTouchEnd); + QVERIFY(!window.seenTouchEnd); + } + + // QGraphicsView + { + QGraphicsScene scene; + tst_QTouchEventGraphicsItem root, child, grandchild; + QGraphicsView view(&scene); + scene.addItem(&root); + root.setPos(100, 100); + child.setParentItem(&root); + grandchild.setParentItem(&child); + view.resize(200, 200); + view.fitInView(scene.sceneRect()); + + root.setAcceptTouchEvents(true); + child.setAcceptTouchEvents(true); + child.acceptTouchUpdate = false; + child.acceptTouchEnd = false; + + // compose an event to the scene that is over the child + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(grandchild.mapToScene(grandchild.boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setScenePos(view.mapToScene(touchPoint.pos().toPoint())); + QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + (QList<QTouchEvent::TouchPoint>() << touchPoint)); + bool res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res); + QVERIFY(touchBeginEvent.isAccepted()); + QVERIFY(child.seenTouchBegin); + QVERIFY(!root.seenTouchBegin); + + // send the touch update to the child, but ignore it, it doesn't propagate + touchPoint.setState(Qt::TouchPointMoved); + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointMoved, + (QList<QTouchEvent::TouchPoint>() << touchPoint)); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res); + // the scene accepts the event, since it found an item to send the event to + QVERIFY(!touchUpdateEvent.isAccepted()); + QVERIFY(child.seenTouchUpdate); + QVERIFY(!root.seenTouchUpdate); + + // send the touch end, same thing should happen as with touch update + touchPoint.setState(Qt::TouchPointReleased); + QTouchEvent touchEndEvent(QEvent::TouchEnd, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + (QList<QTouchEvent::TouchPoint>() << touchPoint)); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res); + // the scene accepts the event, since it found an item to send the event to + QVERIFY(!touchEndEvent.isAccepted()); + QVERIFY(child.seenTouchEnd); + QVERIFY(!root.seenTouchEnd); + } +} + +QPointF normalized(const QPointF &pos, const QRectF &rect) +{ + return QPointF(pos.x() / rect.width(), pos.y() / rect.height()); +} + +void tst_QTouchEvent::basicRawEventTranslation() +{ + tst_QTouchEventWidget touchWidget; + touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); + touchWidget.setGeometry(100, 100, 400, 300); + + QPointF pos = touchWidget.rect().center(); + QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint()); + QPointF delta(10, 10); + QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + + QTouchEvent::TouchPoint rawTouchPoint; + rawTouchPoint.setId(0); + + // this should be translated to a TouchBegin + rawTouchPoint.setState(Qt::TouchPointPressed); + rawTouchPoint.setScreenPos(screenPos); + rawTouchPoint.setNormalizedPos(normalized(rawTouchPoint.pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, + QTouchEvent::TouchScreen, + QList<QTouchEvent::TouchPoint>() << rawTouchPoint); + QVERIFY(touchWidget.seenTouchBegin); + QVERIFY(!touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QCOMPARE(touchWidget.touchBeginPoints.count(), 1); + QTouchEvent::TouchPoint touchBeginPoint = touchWidget.touchBeginPoints.first(); + QCOMPARE(touchBeginPoint.id(), rawTouchPoint.id()); + QCOMPARE(touchBeginPoint.state(), rawTouchPoint.state()); + QCOMPARE(touchBeginPoint.pos(), pos); + QCOMPARE(touchBeginPoint.startPos(), pos); + QCOMPARE(touchBeginPoint.lastPos(), pos); + QCOMPARE(touchBeginPoint.scenePos(), rawTouchPoint.screenPos()); + QCOMPARE(touchBeginPoint.startScenePos(), rawTouchPoint.screenPos()); + QCOMPARE(touchBeginPoint.lastScenePos(), rawTouchPoint.screenPos()); + QCOMPARE(touchBeginPoint.screenPos(), rawTouchPoint.screenPos()); + QCOMPARE(touchBeginPoint.startScreenPos(), rawTouchPoint.screenPos()); + QCOMPARE(touchBeginPoint.lastScreenPos(), rawTouchPoint.screenPos()); + QCOMPARE(touchBeginPoint.normalizedPos(), rawTouchPoint.normalizedPos()); + QCOMPARE(touchBeginPoint.startNormalizedPos(), touchBeginPoint.normalizedPos()); + QCOMPARE(touchBeginPoint.lastNormalizedPos(), touchBeginPoint.normalizedPos()); + QCOMPARE(touchBeginPoint.rect(), QRectF(pos, QSizeF(0, 0))); + QCOMPARE(touchBeginPoint.screenRect(), QRectF(rawTouchPoint.screenPos(), QSizeF(0, 0))); + QCOMPARE(touchBeginPoint.sceneRect(), touchBeginPoint.screenRect()); + QCOMPARE(touchBeginPoint.pressure(), qreal(1.)); + + // moving the point should translate to TouchUpdate + rawTouchPoint.setState(Qt::TouchPointMoved); + rawTouchPoint.setScreenPos(screenPos + delta); + rawTouchPoint.setNormalizedPos(normalized(rawTouchPoint.pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, + QTouchEvent::TouchScreen, + QList<QTouchEvent::TouchPoint>() << rawTouchPoint); + QVERIFY(touchWidget.seenTouchBegin); + QVERIFY(touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QCOMPARE(touchWidget.touchUpdatePoints.count(), 1); + QTouchEvent::TouchPoint touchUpdatePoint = touchWidget.touchUpdatePoints.first(); + QCOMPARE(touchUpdatePoint.id(), rawTouchPoint.id()); + QCOMPARE(touchUpdatePoint.state(), rawTouchPoint.state()); + QCOMPARE(touchUpdatePoint.pos(), pos + delta); + QCOMPARE(touchUpdatePoint.startPos(), pos); + QCOMPARE(touchUpdatePoint.lastPos(), pos); + QCOMPARE(touchUpdatePoint.scenePos(), rawTouchPoint.screenPos()); + QCOMPARE(touchUpdatePoint.startScenePos(), screenPos); + QCOMPARE(touchUpdatePoint.lastScenePos(), screenPos); + QCOMPARE(touchUpdatePoint.screenPos(), rawTouchPoint.screenPos()); + QCOMPARE(touchUpdatePoint.startScreenPos(), screenPos); + QCOMPARE(touchUpdatePoint.lastScreenPos(), screenPos); + QCOMPARE(touchUpdatePoint.normalizedPos(), rawTouchPoint.normalizedPos()); + QCOMPARE(touchUpdatePoint.startNormalizedPos(), touchBeginPoint.normalizedPos()); + QCOMPARE(touchUpdatePoint.lastNormalizedPos(), touchBeginPoint.normalizedPos()); + QCOMPARE(touchUpdatePoint.rect(), QRectF(pos + delta, QSizeF(0, 0))); + QCOMPARE(touchUpdatePoint.screenRect(), QRectF(rawTouchPoint.screenPos(), QSizeF(0, 0))); + QCOMPARE(touchUpdatePoint.sceneRect(), touchUpdatePoint.screenRect()); + QCOMPARE(touchUpdatePoint.pressure(), qreal(1.)); + + // releasing the point translates to TouchEnd + rawTouchPoint.setState(Qt::TouchPointReleased); + rawTouchPoint.setScreenPos(screenPos + delta + delta); + rawTouchPoint.setNormalizedPos(normalized(rawTouchPoint.pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, + QTouchEvent::TouchScreen, + QList<QTouchEvent::TouchPoint>() << rawTouchPoint); + QVERIFY(touchWidget.seenTouchBegin); + QVERIFY(touchWidget.seenTouchUpdate); + QVERIFY(touchWidget.seenTouchEnd); + QCOMPARE(touchWidget.touchEndPoints.count(), 1); + QTouchEvent::TouchPoint touchEndPoint = touchWidget.touchEndPoints.first(); + QCOMPARE(touchEndPoint.id(), rawTouchPoint.id()); + QCOMPARE(touchEndPoint.state(), rawTouchPoint.state()); + QCOMPARE(touchEndPoint.pos(), pos + delta + delta); + QCOMPARE(touchEndPoint.startPos(), pos); + QCOMPARE(touchEndPoint.lastPos(), pos + delta); + QCOMPARE(touchEndPoint.scenePos(), rawTouchPoint.screenPos()); + QCOMPARE(touchEndPoint.startScenePos(), screenPos); + QCOMPARE(touchEndPoint.lastScenePos(), screenPos + delta); + QCOMPARE(touchEndPoint.screenPos(), rawTouchPoint.screenPos()); + QCOMPARE(touchEndPoint.startScreenPos(), screenPos); + QCOMPARE(touchEndPoint.lastScreenPos(), screenPos + delta); + QCOMPARE(touchEndPoint.normalizedPos(), rawTouchPoint.normalizedPos()); + QCOMPARE(touchEndPoint.startNormalizedPos(), touchBeginPoint.normalizedPos()); + QCOMPARE(touchEndPoint.lastNormalizedPos(), touchUpdatePoint.normalizedPos()); + QCOMPARE(touchEndPoint.rect(), QRectF(pos + delta + delta, QSizeF(0, 0))); + QCOMPARE(touchEndPoint.screenRect(), QRectF(rawTouchPoint.screenPos(), QSizeF(0, 0))); + QCOMPARE(touchEndPoint.sceneRect(), touchEndPoint.screenRect()); + QCOMPARE(touchEndPoint.pressure(), qreal(0.)); +} + +void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen() +{ + tst_QTouchEventWidget touchWidget; + touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); + touchWidget.setGeometry(100, 100, 400, 300); + + tst_QTouchEventWidget leftWidget; + leftWidget.setParent(&touchWidget); + leftWidget.setAttribute(Qt::WA_AcceptTouchEvents); + leftWidget.setGeometry(0, 100, 100, 100); + leftWidget.show(); + + tst_QTouchEventWidget rightWidget; + rightWidget.setParent(&touchWidget); + rightWidget.setAttribute(Qt::WA_AcceptTouchEvents); + rightWidget.setGeometry(300, 100, 100, 100); + rightWidget.show(); + + QPointF leftPos = leftWidget.rect().center(); + QPointF rightPos = rightWidget.rect().center(); + QPointF centerPos = touchWidget.rect().center(); + QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint()); + QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint()); + QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint()); + QPointF delta(10, 10); + QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + + QList<QTouchEvent::TouchPoint> rawTouchPoints; + rawTouchPoints.append(QTouchEvent::TouchPoint(0)); + rawTouchPoints.append(QTouchEvent::TouchPoint(1)); + + // generate TouchBegins on both leftWidget and rightWidget + rawTouchPoints[0].setState(Qt::TouchPointPressed); + rawTouchPoints[0].setScreenPos(leftScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointPressed); + rawTouchPoints[1].setScreenPos(rightScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + QVERIFY(!touchWidget.seenTouchBegin); + QVERIFY(!touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QVERIFY(leftWidget.seenTouchBegin); + QVERIFY(!leftWidget.seenTouchUpdate); + QVERIFY(!leftWidget.seenTouchEnd); + QVERIFY(rightWidget.seenTouchBegin); + QVERIFY(!rightWidget.seenTouchUpdate); + QVERIFY(!rightWidget.seenTouchEnd); + QCOMPARE(leftWidget.touchBeginPoints.count(), 1); + QCOMPARE(rightWidget.touchBeginPoints.count(), 1); + { + QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchBeginPoints.first(); + QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); + QCOMPARE(leftTouchPoint.pos(), leftPos); + QCOMPARE(leftTouchPoint.startPos(), leftPos); + QCOMPARE(leftTouchPoint.lastPos(), leftPos); + QCOMPARE(leftTouchPoint.scenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.screenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.rect(), QRectF(leftPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.sceneRect(), QRectF(leftScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.screenRect(), QRectF(leftScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.pressure(), qreal(1.)); + + QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchBeginPoints.first(); + QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); + QCOMPARE(rightTouchPoint.pos(), rightPos); + QCOMPARE(rightTouchPoint.startPos(), rightPos); + QCOMPARE(rightTouchPoint.lastPos(), rightPos); + QCOMPARE(rightTouchPoint.scenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.screenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.rect(), QRectF(rightPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.sceneRect(), QRectF(rightScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.screenRect(), QRectF(rightScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.pressure(), qreal(1.)); + } + + // generate TouchUpdates on both leftWidget and rightWidget + rawTouchPoints[0].setState(Qt::TouchPointMoved); + rawTouchPoints[0].setScreenPos(centerScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointMoved); + rawTouchPoints[1].setScreenPos(centerScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + QVERIFY(!touchWidget.seenTouchBegin); + QVERIFY(!touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QVERIFY(leftWidget.seenTouchBegin); + QVERIFY(leftWidget.seenTouchUpdate); + QVERIFY(!leftWidget.seenTouchEnd); + QVERIFY(rightWidget.seenTouchBegin); + QVERIFY(rightWidget.seenTouchUpdate); + QVERIFY(!rightWidget.seenTouchEnd); + QCOMPARE(leftWidget.touchUpdatePoints.count(), 1); + QCOMPARE(rightWidget.touchUpdatePoints.count(), 1); + { + QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchUpdatePoints.first(); + QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); + QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint()))); + QCOMPARE(leftTouchPoint.startPos(), leftPos); + QCOMPARE(leftTouchPoint.lastPos(), leftPos); + QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos); + QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos); + QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.rect(), QRectF(leftWidget.mapFromParent(centerPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.sceneRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.screenRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.pressure(), qreal(1.)); + + QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchUpdatePoints.first(); + QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); + QCOMPARE(rightTouchPoint.pos(), QPointF(rightWidget.mapFromParent(centerPos.toPoint()))); + QCOMPARE(rightTouchPoint.startPos(), rightPos); + QCOMPARE(rightTouchPoint.lastPos(), rightPos); + QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos); + QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos); + QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.rect(), QRectF(rightWidget.mapFromParent(centerPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.sceneRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.screenRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.pressure(), qreal(1.)); + } + + // generate TouchEnds on both leftWidget and rightWidget + rawTouchPoints[0].setState(Qt::TouchPointReleased); + rawTouchPoints[0].setScreenPos(centerScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointReleased); + rawTouchPoints[1].setScreenPos(centerScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + QVERIFY(!touchWidget.seenTouchBegin); + QVERIFY(!touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QVERIFY(leftWidget.seenTouchBegin); + QVERIFY(leftWidget.seenTouchUpdate); + QVERIFY(leftWidget.seenTouchEnd); + QVERIFY(rightWidget.seenTouchBegin); + QVERIFY(rightWidget.seenTouchUpdate); + QVERIFY(rightWidget.seenTouchEnd); + QCOMPARE(leftWidget.touchEndPoints.count(), 1); + QCOMPARE(rightWidget.touchEndPoints.count(), 1); + { + QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchEndPoints.first(); + QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); + QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint()))); + QCOMPARE(leftTouchPoint.startPos(), leftPos); + QCOMPARE(leftTouchPoint.lastPos(), leftTouchPoint.pos()); + QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos); + QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScenePos(), leftTouchPoint.scenePos()); + QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos); + QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScreenPos(), leftTouchPoint.screenPos()); + QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.rect(), QRectF(leftWidget.mapFromParent(centerPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.sceneRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.screenRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.pressure(), qreal(0.)); + + QTouchEvent::TouchPoint rightTouchPoint = rightWidget.touchEndPoints.first(); + QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); + QCOMPARE(rightTouchPoint.pos(), QPointF(rightWidget.mapFromParent(centerPos.toPoint()))); + QCOMPARE(rightTouchPoint.startPos(), rightPos); + QCOMPARE(rightTouchPoint.lastPos(), rightTouchPoint.pos()); + QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos); + QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScenePos(), rightTouchPoint.scenePos()); + QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos); + QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScreenPos(), rightTouchPoint.screenPos()); + QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.rect(), QRectF(rightWidget.mapFromParent(centerPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.sceneRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.screenRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.pressure(), qreal(0.)); + } +} + +void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() +{ + tst_QTouchEventWidget touchWidget; + touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); + touchWidget.setGeometry(100, 100, 400, 300); + + tst_QTouchEventWidget leftWidget; + leftWidget.setParent(&touchWidget); + leftWidget.setAttribute(Qt::WA_AcceptTouchEvents); + leftWidget.setGeometry(0, 100, 100, 100); + leftWidget.show(); + + tst_QTouchEventWidget rightWidget; + rightWidget.setParent(&touchWidget); + rightWidget.setAttribute(Qt::WA_AcceptTouchEvents); + rightWidget.setGeometry(300, 100, 100, 100); + rightWidget.show(); + + QPointF leftPos = leftWidget.rect().center(); + QPointF rightPos = rightWidget.rect().center(); + QPointF centerPos = touchWidget.rect().center(); + QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint()); + QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint()); + QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint()); + QPointF delta(10, 10); + QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + + QList<QTouchEvent::TouchPoint> rawTouchPoints; + rawTouchPoints.append(QTouchEvent::TouchPoint(0)); + rawTouchPoints.append(QTouchEvent::TouchPoint(1)); + + // generate TouchBegin on leftWidget only + rawTouchPoints[0].setState(Qt::TouchPointPressed); + rawTouchPoints[0].setScreenPos(leftScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointPressed); + rawTouchPoints[1].setScreenPos(rightScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchPad, rawTouchPoints); + QVERIFY(!touchWidget.seenTouchBegin); + QVERIFY(!touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QVERIFY(leftWidget.seenTouchBegin); + QVERIFY(!leftWidget.seenTouchUpdate); + QVERIFY(!leftWidget.seenTouchEnd); + QVERIFY(!rightWidget.seenTouchBegin); + QVERIFY(!rightWidget.seenTouchUpdate); + QVERIFY(!rightWidget.seenTouchEnd); + QCOMPARE(leftWidget.touchBeginPoints.count(), 2); + QCOMPARE(rightWidget.touchBeginPoints.count(), 0); + { + QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchBeginPoints.at(0); + QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); + QCOMPARE(leftTouchPoint.pos(), leftPos); + QCOMPARE(leftTouchPoint.startPos(), leftPos); + QCOMPARE(leftTouchPoint.lastPos(), leftPos); + QCOMPARE(leftTouchPoint.scenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.screenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.rect(), QRectF(leftPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.sceneRect(), QRectF(leftScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.screenRect(), QRectF(leftScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.pressure(), qreal(1.)); + + QTouchEvent::TouchPoint rightTouchPoint = leftWidget.touchBeginPoints.at(1); + QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); + QCOMPARE(rightTouchPoint.pos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint()))); + QCOMPARE(rightTouchPoint.startPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint()))); + QCOMPARE(rightTouchPoint.lastPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint()))); + QCOMPARE(rightTouchPoint.scenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.screenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.rect(), QRectF(leftWidget.mapFromGlobal(rightScreenPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.sceneRect(), QRectF(rightScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.screenRect(), QRectF(rightScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.pressure(), qreal(1.)); + } + + // generate TouchUpdate on leftWidget + rawTouchPoints[0].setState(Qt::TouchPointMoved); + rawTouchPoints[0].setScreenPos(centerScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointMoved); + rawTouchPoints[1].setScreenPos(centerScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchPad, rawTouchPoints); + QVERIFY(!touchWidget.seenTouchBegin); + QVERIFY(!touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QVERIFY(leftWidget.seenTouchBegin); + QVERIFY(leftWidget.seenTouchUpdate); + QVERIFY(!leftWidget.seenTouchEnd); + QVERIFY(!rightWidget.seenTouchBegin); + QVERIFY(!rightWidget.seenTouchUpdate); + QVERIFY(!rightWidget.seenTouchEnd); + QCOMPARE(leftWidget.touchUpdatePoints.count(), 2); + QCOMPARE(rightWidget.touchUpdatePoints.count(), 0); + { + QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchUpdatePoints.at(0); + QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); + QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint()))); + QCOMPARE(leftTouchPoint.startPos(), leftPos); + QCOMPARE(leftTouchPoint.lastPos(), leftPos); + QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos); + QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos); + QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.rect(), QRectF(leftWidget.mapFromParent(centerPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.sceneRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.screenRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.pressure(), qreal(1.)); + + QTouchEvent::TouchPoint rightTouchPoint = leftWidget.touchUpdatePoints.at(1); + QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); + QCOMPARE(rightTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint()))); + QCOMPARE(rightTouchPoint.startPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint()))); + QCOMPARE(rightTouchPoint.lastPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint()))); + QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos); + QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos); + QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.rect(), QRectF(leftWidget.mapFromParent(centerPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.sceneRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.screenRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.pressure(), qreal(1.)); + } + + // generate TouchEnd on leftWidget + rawTouchPoints[0].setState(Qt::TouchPointReleased); + rawTouchPoints[0].setScreenPos(centerScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointReleased); + rawTouchPoints[1].setScreenPos(centerScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchPad, rawTouchPoints); + QVERIFY(!touchWidget.seenTouchBegin); + QVERIFY(!touchWidget.seenTouchUpdate); + QVERIFY(!touchWidget.seenTouchEnd); + QVERIFY(leftWidget.seenTouchBegin); + QVERIFY(leftWidget.seenTouchUpdate); + QVERIFY(leftWidget.seenTouchEnd); + QVERIFY(!rightWidget.seenTouchBegin); + QVERIFY(!rightWidget.seenTouchUpdate); + QVERIFY(!rightWidget.seenTouchEnd); + QCOMPARE(leftWidget.touchEndPoints.count(), 2); + QCOMPARE(rightWidget.touchEndPoints.count(), 0); + { + QTouchEvent::TouchPoint leftTouchPoint = leftWidget.touchEndPoints.at(0); + QCOMPARE(leftTouchPoint.id(), rawTouchPoints[0].id()); + QCOMPARE(leftTouchPoint.state(), rawTouchPoints[0].state()); + QCOMPARE(leftTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint()))); + QCOMPARE(leftTouchPoint.startPos(), leftPos); + QCOMPARE(leftTouchPoint.lastPos(), leftTouchPoint.pos()); + QCOMPARE(leftTouchPoint.scenePos(), centerScreenPos); + QCOMPARE(leftTouchPoint.startScenePos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScenePos(), leftTouchPoint.scenePos()); + QCOMPARE(leftTouchPoint.screenPos(), centerScreenPos); + QCOMPARE(leftTouchPoint.startScreenPos(), leftScreenPos); + QCOMPARE(leftTouchPoint.lastScreenPos(), leftTouchPoint.screenPos()); + QCOMPARE(leftTouchPoint.normalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.startNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.lastNormalizedPos(), rawTouchPoints[0].normalizedPos()); + QCOMPARE(leftTouchPoint.rect(), QRectF(leftWidget.mapFromParent(centerPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.sceneRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.screenRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(leftTouchPoint.pressure(), qreal(0.)); + + QTouchEvent::TouchPoint rightTouchPoint = leftWidget.touchEndPoints.at(1); + QCOMPARE(rightTouchPoint.id(), rawTouchPoints[1].id()); + QCOMPARE(rightTouchPoint.state(), rawTouchPoints[1].state()); + QCOMPARE(rightTouchPoint.pos(), QPointF(leftWidget.mapFromParent(centerPos.toPoint()))); + QCOMPARE(rightTouchPoint.startPos(), QPointF(leftWidget.mapFromGlobal(rightScreenPos.toPoint()))); + QCOMPARE(rightTouchPoint.lastPos(), rightTouchPoint.pos()); + QCOMPARE(rightTouchPoint.scenePos(), centerScreenPos); + QCOMPARE(rightTouchPoint.startScenePos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScenePos(), rightTouchPoint.scenePos()); + QCOMPARE(rightTouchPoint.screenPos(), centerScreenPos); + QCOMPARE(rightTouchPoint.startScreenPos(), rightScreenPos); + QCOMPARE(rightTouchPoint.lastScreenPos(), rightTouchPoint.screenPos()); + QCOMPARE(rightTouchPoint.normalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.startNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.lastNormalizedPos(), rawTouchPoints[1].normalizedPos()); + QCOMPARE(rightTouchPoint.rect(), QRectF(leftWidget.mapFromParent(centerPos.toPoint()), QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.sceneRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.screenRect(), QRectF(centerScreenPos, QSizeF(0, 0))); + QCOMPARE(rightTouchPoint.pressure(), qreal(0.)); + } +} + +void tst_QTouchEvent::deleteInEventHandler() +{ + // QWidget + { + QWidget window; + tst_QTouchEventWidget *child1, *child2, *child3; + child1 = new tst_QTouchEventWidget; + child2 = new tst_QTouchEventWidget; + child3 = new tst_QTouchEventWidget; + child1->setParent(&window); + child2->setParent(&window); + child3->setParent(&window); + child1->setAttribute(Qt::WA_AcceptTouchEvents); + child2->setAttribute(Qt::WA_AcceptTouchEvents); + child3->setAttribute(Qt::WA_AcceptTouchEvents); + child1->deleteInTouchBegin = true; + child2->deleteInTouchUpdate = true; + child3->deleteInTouchEnd = true; + + QList<QTouchEvent::TouchPoint> touchPoints; + touchPoints.append(QTouchEvent::TouchPoint(0)); + QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointStationary, + touchPoints); + QTouchEvent touchEndEvent(QEvent::TouchEnd, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + touchPoints); + QWeakPointer<QWidget> p; + bool res; + + touchBeginEvent.ignore(); + p = child1; + res = QApplication::sendEvent(child1, &touchBeginEvent); + // event is handled, but widget should be deleted + QVERIFY(res && touchBeginEvent.isAccepted() && p.isNull()); + + touchBeginEvent.ignore(); + p = child2; + res = QApplication::sendEvent(child2, &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(child2, &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && p.isNull()); + + touchBeginEvent.ignore(); + p = child3; + res = QApplication::sendEvent(child3, &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !p.isNull()); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(child3, &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !p.isNull()); + touchEndEvent.ignore(); + res = QApplication::sendEvent(child3, &touchEndEvent); + QVERIFY(res && touchEndEvent.isAccepted() && p.isNull()); + } + + // QGraphicsView + { + QGraphicsScene scene; + QGraphicsView view(&scene); + tst_QTouchEventGraphicsItem *root, *child1, *child2, *child3; + root = new tst_QTouchEventGraphicsItem; + child1 = new tst_QTouchEventGraphicsItem; + child2 = new tst_QTouchEventGraphicsItem; + child3 = new tst_QTouchEventGraphicsItem; + child1->setParentItem(root); + child2->setParentItem(root); + child3->setParentItem(root); + child1->setZValue(1.); + child2->setZValue(0.); + child3->setZValue(-1.); + child1->setAcceptTouchEvents(true); + child2->setAcceptTouchEvents(true); + child3->setAcceptTouchEvents(true); + child1->deleteInTouchBegin = true; + child2->deleteInTouchUpdate = true; + child3->deleteInTouchEnd = true; + + scene.addItem(root); + view.resize(200, 200); + view.fitInView(scene.sceneRect()); + + QTouchEvent::TouchPoint touchPoint(0); + touchPoint.setState(Qt::TouchPointPressed); + touchPoint.setPos(view.mapFromScene(child1->mapToScene(child1->boundingRect().center()))); + touchPoint.setScreenPos(view.mapToGlobal(touchPoint.pos().toPoint())); + touchPoint.setScenePos(view.mapToScene(touchPoint.pos().toPoint())); + QList<QTouchEvent::TouchPoint> touchPoints; + touchPoints.append(touchPoint); + QTouchEvent touchBeginEvent(QEvent::TouchBegin, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointPressed, + touchPoints); + touchPoints[0].setState(Qt::TouchPointMoved); + QTouchEvent touchUpdateEvent(QEvent::TouchUpdate, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointMoved, + touchPoints); + touchPoints[0].setState(Qt::TouchPointReleased); + QTouchEvent touchEndEvent(QEvent::TouchEnd, + QTouchEvent::TouchScreen, + Qt::NoModifier, + Qt::TouchPointReleased, + touchPoints); + bool res; + + child1->weakpointer = &child1; + touchBeginEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && !child1); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + touchEndEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && touchUpdateEvent.isAccepted() && !child1); + + child2->weakpointer = &child2; + touchBeginEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && child2); + touchUpdateEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + touchEndEvent.ignore(); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && !child2); + + child3->weakpointer = &child3; + res = QApplication::sendEvent(view.viewport(), &touchBeginEvent); + QVERIFY(res && touchBeginEvent.isAccepted() && child3); + res = QApplication::sendEvent(view.viewport(), &touchUpdateEvent); + QVERIFY(res && !touchUpdateEvent.isAccepted() && child3); + res = QApplication::sendEvent(view.viewport(), &touchEndEvent); + QVERIFY(res && !touchEndEvent.isAccepted() && !child3); + + delete root; + } +} + +void tst_QTouchEvent::deleteInRawEventTranslation() +{ + tst_QTouchEventWidget touchWidget; + touchWidget.setAttribute(Qt::WA_AcceptTouchEvents); + touchWidget.setGeometry(100, 100, 300, 300); + + tst_QTouchEventWidget *leftWidget = new tst_QTouchEventWidget; + leftWidget->setParent(&touchWidget); + leftWidget->setAttribute(Qt::WA_AcceptTouchEvents); + leftWidget->setGeometry(0, 100, 100, 100); + leftWidget->deleteInTouchBegin = true; + leftWidget->show(); + + tst_QTouchEventWidget *centerWidget = new tst_QTouchEventWidget; + centerWidget->setParent(&touchWidget); + centerWidget->setAttribute(Qt::WA_AcceptTouchEvents); + centerWidget->setGeometry(100, 100, 100, 100); + centerWidget->deleteInTouchUpdate = true; + centerWidget->show(); + + tst_QTouchEventWidget *rightWidget = new tst_QTouchEventWidget; + rightWidget->setParent(&touchWidget); + rightWidget->setAttribute(Qt::WA_AcceptTouchEvents); + rightWidget->setGeometry(200, 100, 100, 100); + rightWidget->deleteInTouchEnd = true; + rightWidget->show(); + + QPointF leftPos = leftWidget->rect().center(); + QPointF centerPos = centerWidget->rect().center(); + QPointF rightPos = rightWidget->rect().center(); + QPointF leftScreenPos = leftWidget->mapToGlobal(leftPos.toPoint()); + QPointF centerScreenPos = centerWidget->mapToGlobal(centerPos.toPoint()); + QPointF rightScreenPos = rightWidget->mapToGlobal(rightPos.toPoint()); + QRectF screenGeometry = qApp->desktop()->screenGeometry(&touchWidget); + + QWeakPointer<QWidget> pl = leftWidget, pc = centerWidget, pr = rightWidget; + + QList<QTouchEvent::TouchPoint> rawTouchPoints; + rawTouchPoints.append(QTouchEvent::TouchPoint(0)); + rawTouchPoints.append(QTouchEvent::TouchPoint(1)); + rawTouchPoints.append(QTouchEvent::TouchPoint(2)); + rawTouchPoints[0].setState(Qt::TouchPointPressed); + rawTouchPoints[0].setScreenPos(leftScreenPos); + rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry)); + rawTouchPoints[1].setState(Qt::TouchPointPressed); + rawTouchPoints[1].setScreenPos(centerScreenPos); + rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry)); + rawTouchPoints[2].setState(Qt::TouchPointPressed); + rawTouchPoints[2].setScreenPos(rightScreenPos); + rawTouchPoints[2].setNormalizedPos(normalized(rawTouchPoints[2].pos(), screenGeometry)); + + // generate begin events on all widgets, the left widget should die + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + QVERIFY(pl.isNull() && !pc.isNull() && !pr.isNull()); + + // generate update events on all widget, the center widget should die + rawTouchPoints[0].setState(Qt::TouchPointMoved); + rawTouchPoints[1].setState(Qt::TouchPointMoved); + rawTouchPoints[2].setState(Qt::TouchPointMoved); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); + + // generate end events on all widget, the right widget should die + rawTouchPoints[0].setState(Qt::TouchPointReleased); + rawTouchPoints[1].setState(Qt::TouchPointReleased); + rawTouchPoints[2].setState(Qt::TouchPointReleased); + qt_translateRawTouchEvent(&touchWidget, QTouchEvent::TouchScreen, rawTouchPoints); +} + +void tst_QTouchEvent::crashInQGraphicsSceneAfterNotHandlingTouchBegin() +{ + QGraphicsRectItem *rect = new QGraphicsRectItem(0, 0, 100, 100); + rect->setAcceptTouchEvents(true); + + QGraphicsRectItem *mainRect = new QGraphicsRectItem(0, 0, 100, 100, rect); + mainRect->setBrush(Qt::lightGray); + + QGraphicsRectItem *button = new QGraphicsRectItem(-20, -20, 40, 40, mainRect); + button->setPos(50, 50); + button->setBrush(Qt::darkGreen); + + QGraphicsView view; + QGraphicsScene scene; + scene.addItem(rect); + scene.setSceneRect(0,0,100,100); + view.setScene(&scene); + + view.show(); + QTest::qWaitForWindowShown(&view); + + QPoint centerPos = view.mapFromScene(rect->boundingRect().center()); + // Touch the button + QTest::touchEvent(view.viewport()).press(0, centerPos, static_cast<QWindow *>(0)); + QTest::touchEvent(view.viewport()).release(0, centerPos, static_cast<QWindow *>(0)); + // Touch outside of the button + QTest::touchEvent(view.viewport()).press(0, view.mapFromScene(QPoint(10, 10)), static_cast<QWindow *>(0)); + QTest::touchEvent(view.viewport()).release(0, view.mapFromScene(QPoint(10, 10)), static_cast<QWindow *>(0)); +} + +void tst_QTouchEvent::touchBeginWithGraphicsWidget() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + tst_QTouchEventGraphicsItem *root; + root = new tst_QTouchEventGraphicsItem; + root->setAcceptTouchEvents(true); + scene.addItem(root); + + QGraphicsWidget *glassWidget = new QGraphicsWidget; + glassWidget->setMinimumSize(100, 100); + scene.addItem(glassWidget); + + view.resize(200, 200); + view.show(); + QTest::qWaitForWindowShown(&view); + view.fitInView(scene.sceneRect()); + + QTest::touchEvent(static_cast<QWindow *>(0)) + .press(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()); + QTest::touchEvent(static_cast<QWindow *>(0)) + .stationary(0) + .press(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + QTest::touchEvent(static_cast<QWindow *>(0)) + .release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()) + .release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + + QCOMPARE(root->touchBeginCounter, 1); + QCOMPARE(root->touchUpdateCounter, 1); + QCOMPARE(root->touchEndCounter, 1); + QCOMPARE(root->touchUpdatePoints.size(), 2); + + root->reset(); + glassWidget->setWindowFlags(Qt::Window); // make the glassWidget a panel + + QTest::touchEvent(static_cast<QWindow *>(0)) + .press(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()); + QTest::touchEvent(static_cast<QWindow *>(0)) + .stationary(0) + .press(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + QTest::touchEvent(static_cast<QWindow *>(0)) + .release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()) + .release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + + QCOMPARE(root->touchBeginCounter, 0); + QCOMPARE(root->touchUpdateCounter, 0); + QCOMPARE(root->touchEndCounter, 0); + + + delete root; + delete glassWidget; +} + +QTEST_MAIN(tst_QTouchEvent) + +#include "tst_qtouchevent.moc" diff --git a/tests/auto/gui/math3d/math3d.pro b/tests/auto/gui/math3d/math3d.pro new file mode 100644 index 0000000000..d977afa6e0 --- /dev/null +++ b/tests/auto/gui/math3d/math3d.pro @@ -0,0 +1,6 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qquaternion \ + qvectornd \ + qmatrixnxn \ + diff --git a/tests/auto/gui/math3d/qmatrixnxn/qmatrixnxn.pro b/tests/auto/gui/math3d/qmatrixnxn/qmatrixnxn.pro new file mode 100644 index 0000000000..cf6e4a128e --- /dev/null +++ b/tests/auto/gui/math3d/qmatrixnxn/qmatrixnxn.pro @@ -0,0 +1,2 @@ +load(qttest_p4) +SOURCES += tst_qmatrixnxn.cpp diff --git a/tests/auto/gui/math3d/qmatrixnxn/tst_qmatrixnxn.cpp b/tests/auto/gui/math3d/qmatrixnxn/tst_qmatrixnxn.cpp new file mode 100644 index 0000000000..98a559af85 --- /dev/null +++ b/tests/auto/gui/math3d/qmatrixnxn/tst_qmatrixnxn.cpp @@ -0,0 +1,3385 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qmath.h> +#include <QtGui/qmatrix4x4.h> + +class tst_QMatrixNxN : public QObject +{ + Q_OBJECT +public: + tst_QMatrixNxN() {} + ~tst_QMatrixNxN() {} + +private slots: + void create2x2(); + void create3x3(); + void create4x4(); + void create4x3(); + + void isIdentity2x2(); + void isIdentity3x3(); + void isIdentity4x4(); + void isIdentity4x3(); + + void compare2x2(); + void compare3x3(); + void compare4x4(); + void compare4x3(); + + void transposed2x2(); + void transposed3x3(); + void transposed4x4(); + void transposed4x3(); + + void add2x2_data(); + void add2x2(); + void add3x3_data(); + void add3x3(); + void add4x4_data(); + void add4x4(); + void add4x3_data(); + void add4x3(); + + void subtract2x2_data(); + void subtract2x2(); + void subtract3x3_data(); + void subtract3x3(); + void subtract4x4_data(); + void subtract4x4(); + void subtract4x3_data(); + void subtract4x3(); + + void multiply2x2_data(); + void multiply2x2(); + void multiply3x3_data(); + void multiply3x3(); + void multiply4x4_data(); + void multiply4x4(); + void multiply4x3_data(); + void multiply4x3(); + + void multiplyFactor2x2_data(); + void multiplyFactor2x2(); + void multiplyFactor3x3_data(); + void multiplyFactor3x3(); + void multiplyFactor4x4_data(); + void multiplyFactor4x4(); + void multiplyFactor4x3_data(); + void multiplyFactor4x3(); + + void divideFactor2x2_data(); + void divideFactor2x2(); + void divideFactor3x3_data(); + void divideFactor3x3(); + void divideFactor4x4_data(); + void divideFactor4x4(); + void divideFactor4x3_data(); + void divideFactor4x3(); + + void negate2x2_data(); + void negate2x2(); + void negate3x3_data(); + void negate3x3(); + void negate4x4_data(); + void negate4x4(); + void negate4x3_data(); + void negate4x3(); + + void inverted4x4_data(); + void inverted4x4(); + + void orthonormalInverse4x4(); + + void scale4x4_data(); + void scale4x4(); + + void translate4x4_data(); + void translate4x4(); + + void rotate4x4_data(); + void rotate4x4(); + + void normalMatrix_data(); + void normalMatrix(); + + void optimizedTransforms(); + + void ortho(); + void frustum(); + void perspective(); + void flipCoordinates(); + + void convertGeneric(); + + void optimize_data(); + void optimize(); + + void columnsAndRows(); + + void convertQMatrix(); + void convertQTransform(); + + void fill(); + + void mapRect_data(); + void mapRect(); + + void mapVector_data(); + void mapVector(); + + void properties(); + void metaTypes(); + +private: + static void setMatrix(QMatrix2x2& m, const qreal *values); + static void setMatrixDirect(QMatrix2x2& m, const qreal *values); + static bool isSame(const QMatrix2x2& m, const qreal *values); + static bool isIdentity(const QMatrix2x2& m); + + static void setMatrix(QMatrix3x3& m, const qreal *values); + static void setMatrixDirect(QMatrix3x3& m, const qreal *values); + static bool isSame(const QMatrix3x3& m, const qreal *values); + static bool isIdentity(const QMatrix3x3& m); + + static void setMatrix(QMatrix4x4& m, const qreal *values); + static void setMatrixDirect(QMatrix4x4& m, const qreal *values); + static bool isSame(const QMatrix4x4& m, const qreal *values); + static bool isIdentity(const QMatrix4x4& m); + + static void setMatrix(QMatrix4x3& m, const qreal *values); + static void setMatrixDirect(QMatrix4x3& m, const qreal *values); + static bool isSame(const QMatrix4x3& m, const qreal *values); + static bool isIdentity(const QMatrix4x3& m); +}; + +static const qreal nullValues2[] = + {0.0f, 0.0f, + 0.0f, 0.0f}; + +static qreal const identityValues2[16] = + {1.0f, 0.0f, + 0.0f, 1.0f}; + +static const qreal doubleIdentity2[] = + {2.0f, 0.0f, + 0.0f, 2.0f}; + +static qreal const uniqueValues2[16] = + {1.0f, 2.0f, + 5.0f, 6.0f}; + +static qreal const transposedValues2[16] = + {1.0f, 5.0f, + 2.0f, 6.0f}; + +static const qreal nullValues3[] = + {0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f}; + +static qreal const identityValues3[16] = + {1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f}; + +static const qreal doubleIdentity3[] = + {2.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, + 0.0f, 0.0f, 2.0f}; + +static qreal const uniqueValues3[16] = + {1.0f, 2.0f, 3.0f, + 5.0f, 6.0f, 7.0f, + 9.0f, 10.0f, 11.0f}; + +static qreal const transposedValues3[16] = + {1.0f, 5.0f, 9.0f, + 2.0f, 6.0f, 10.0f, + 3.0f, 7.0f, 11.0f}; + +static const qreal nullValues4[] = + {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f}; + +static qreal const identityValues4[16] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + +static const qreal doubleIdentity4[] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 2.0f}; + +static qreal const uniqueValues4[16] = + {1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.0f, 14.0f, 15.0f, 16.0f}; + +static qreal const transposedValues4[16] = + {1.0f, 5.0f, 9.0f, 13.0f, + 2.0f, 6.0f, 10.0f, 14.0f, + 3.0f, 7.0f, 11.0f, 15.0f, + 4.0f, 8.0f, 12.0f, 16.0f}; + +static const qreal nullValues4x3[] = + {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f}; + +static qreal const identityValues4x3[12] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f}; + +static qreal const doubleIdentity4x3[12] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f, 0.0f}; + +static qreal const uniqueValues4x3[12] = + {1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f}; + +static qreal const transposedValues3x4[12] = + {1.0f, 5.0f, 9.0f, + 2.0f, 6.0f, 10.0f, + 3.0f, 7.0f, 11.0f, + 4.0f, 8.0f, 12.0f}; + +// Set a matrix to a specified array of values, which are assumed +// to be in row-major order. This sets the values using floating-point. +void tst_QMatrixNxN::setMatrix(QMatrix2x2& m, const qreal *values) +{ + for (int row = 0; row < 2; ++row) + for (int col = 0; col < 2; ++col) + m(row, col) = values[row * 2 + col]; +} +void tst_QMatrixNxN::setMatrix(QMatrix3x3& m, const qreal *values) +{ + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 3; ++col) + m(row, col) = values[row * 3 + col]; +} +void tst_QMatrixNxN::setMatrix(QMatrix4x4& m, const qreal *values) +{ + for (int row = 0; row < 4; ++row) + for (int col = 0; col < 4; ++col) + m(row, col) = values[row * 4 + col]; +} +void tst_QMatrixNxN::setMatrix(QMatrix4x3& m, const qreal *values) +{ + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 4; ++col) + m(row, col) = values[row * 4 + col]; +} + +// Set a matrix to a specified array of values, which are assumed +// to be in row-major order. This sets the values directly into +// the internal data() array. +void tst_QMatrixNxN::setMatrixDirect(QMatrix2x2& m, const qreal *values) +{ + qreal *data = m.data(); + for (int row = 0; row < 2; ++row) { + for (int col = 0; col < 2; ++col) { + data[row + col * 2] = values[row * 2 + col]; + } + } +} +void tst_QMatrixNxN::setMatrixDirect(QMatrix3x3& m, const qreal *values) +{ + qreal *data = m.data(); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + data[row + col * 3] = values[row * 3 + col]; + } + } +} +void tst_QMatrixNxN::setMatrixDirect(QMatrix4x4& m, const qreal *values) +{ + qreal *data = m.data(); + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + data[row + col * 4] = values[row * 4 + col]; + } + } +} +void tst_QMatrixNxN::setMatrixDirect(QMatrix4x3& m, const qreal *values) +{ + qreal *data = m.data(); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 4; ++col) { + data[row + col * 3] = values[row * 4 + col]; + } + } +} + +// QVector2/3/4D use float internally, which can sometimes lead +// to precision issues when converting to and from qreal during +// operations involving QMatrix4x4. This fuzzy compare is slightly +// "fuzzier" than the default qFuzzyCompare for qreal to compensate. +static bool fuzzyCompare(qreal x, qreal y) +{ + return qFuzzyIsNull((float)(x - y)); +} + +static bool fuzzyCompare(const QVector3D &v1, const QVector3D &v2) +{ + if (!fuzzyCompare(v1.x(), v2.x())) + return false; + if (!fuzzyCompare(v1.y(), v2.y())) + return false; + if (!fuzzyCompare(v1.z(), v2.z())) + return false; + return true; +} + +// Determine if a matrix is the same as a specified array of values. +// The values are assumed to be specified in row-major order. +bool tst_QMatrixNxN::isSame(const QMatrix2x2& m, const qreal *values) +{ + const qreal *mv = m.constData(); + for (int row = 0; row < 2; ++row) { + for (int col = 0; col < 2; ++col) { + // Check the values using the operator() function. + if (!fuzzyCompare(m(row, col), values[row * 2 + col])) { + qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 2 + col]; + return false; + } + + // Check the values using direct access, which verifies that the values + // are stored internally in column-major order. + if (!fuzzyCompare(mv[col * 2 + row], values[row * 2 + col])) { + qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 2 + row] << "expected =" << values[row * 2 + col]; + return false; + } + } + } + return true; +} +bool tst_QMatrixNxN::isSame(const QMatrix3x3& m, const qreal *values) +{ + const qreal *mv = m.constData(); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + // Check the values using the operator() access function. + if (!fuzzyCompare(m(row, col), values[row * 3 + col])) { + qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 3 + col]; + return false; + } + + // Check the values using direct access, which verifies that the values + // are stored internally in column-major order. + if (!fuzzyCompare(mv[col * 3 + row], values[row * 3 + col])) { + qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 3 + row] << "expected =" << values[row * 3 + col]; + return false; + } + } + } + return true; +} +bool tst_QMatrixNxN::isSame(const QMatrix4x4& m, const qreal *values) +{ + const qreal *mv = m.constData(); + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + // Check the values using the operator() access function. + if (!fuzzyCompare(m(row, col), values[row * 4 + col])) { + qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 4 + col]; + return false; + } + + // Check the values using direct access, which verifies that the values + // are stored internally in column-major order. + if (!fuzzyCompare(mv[col * 4 + row], values[row * 4 + col])) { + qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 4 + row] << "expected =" << values[row * 4 + col]; + return false; + } + } + } + return true; +} +bool tst_QMatrixNxN::isSame(const QMatrix4x3& m, const qreal *values) +{ + const qreal *mv = m.constData(); + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 4; ++col) { + // Check the values using the operator() access function. + if (!fuzzyCompare(m(row, col), values[row * 4 + col])) { + qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 4 + col]; + return false; + } + + // Check the values using direct access, which verifies that the values + // are stored internally in column-major order. + if (!fuzzyCompare(mv[col * 3 + row], values[row * 4 + col])) { + qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 3 + row] << "expected =" << values[row * 4 + col]; + return false; + } + } + } + return true; +} + +// Determine if a matrix is the identity. +bool tst_QMatrixNxN::isIdentity(const QMatrix2x2& m) +{ + return isSame(m, identityValues2); +} +bool tst_QMatrixNxN::isIdentity(const QMatrix3x3& m) +{ + return isSame(m, identityValues3); +} +bool tst_QMatrixNxN::isIdentity(const QMatrix4x4& m) +{ + return isSame(m, identityValues4); +} +bool tst_QMatrixNxN::isIdentity(const QMatrix4x3& m) +{ + return isSame(m, identityValues4x3); +} + +// Test the creation of QMatrix2x2 objects in various ways: +// construct, copy, and modify. +void tst_QMatrixNxN::create2x2() +{ + QMatrix2x2 m1; + QVERIFY(isIdentity(m1)); + QVERIFY(m1.isIdentity()); + + QMatrix2x2 m2; + setMatrix(m2, uniqueValues2); + QVERIFY(isSame(m2, uniqueValues2)); + QVERIFY(!m2.isIdentity()); + + QMatrix2x2 m3; + setMatrixDirect(m3, uniqueValues2); + QVERIFY(isSame(m3, uniqueValues2)); + + QMatrix2x2 m4(m3); + QVERIFY(isSame(m4, uniqueValues2)); + + QMatrix2x2 m5; + m5 = m3; + QVERIFY(isSame(m5, uniqueValues2)); + + m5.setToIdentity(); + QVERIFY(isIdentity(m5)); + + QMatrix2x2 m6(uniqueValues2); + QVERIFY(isSame(m6, uniqueValues2)); + qreal vals[4]; + m6.copyDataTo(vals); + for (int index = 0; index < 4; ++index) + QCOMPARE(vals[index], uniqueValues2[index]); +} + +// Test the creation of QMatrix3x3 objects in various ways: +// construct, copy, and modify. +void tst_QMatrixNxN::create3x3() +{ + QMatrix3x3 m1; + QVERIFY(isIdentity(m1)); + QVERIFY(m1.isIdentity()); + + QMatrix3x3 m2; + setMatrix(m2, uniqueValues3); + QVERIFY(isSame(m2, uniqueValues3)); + QVERIFY(!m2.isIdentity()); + + QMatrix3x3 m3; + setMatrixDirect(m3, uniqueValues3); + QVERIFY(isSame(m3, uniqueValues3)); + + QMatrix3x3 m4(m3); + QVERIFY(isSame(m4, uniqueValues3)); + + QMatrix3x3 m5; + m5 = m3; + QVERIFY(isSame(m5, uniqueValues3)); + + m5.setToIdentity(); + QVERIFY(isIdentity(m5)); + + QMatrix3x3 m6(uniqueValues3); + QVERIFY(isSame(m6, uniqueValues3)); + qreal vals[9]; + m6.copyDataTo(vals); + for (int index = 0; index < 9; ++index) + QCOMPARE(vals[index], uniqueValues3[index]); +} + +// Test the creation of QMatrix4x4 objects in various ways: +// construct, copy, and modify. +void tst_QMatrixNxN::create4x4() +{ + QMatrix4x4 m1; + QVERIFY(isIdentity(m1)); + QVERIFY(m1.isIdentity()); + + QMatrix4x4 m2; + setMatrix(m2, uniqueValues4); + QVERIFY(isSame(m2, uniqueValues4)); + QVERIFY(!m2.isIdentity()); + + QMatrix4x4 m3; + setMatrixDirect(m3, uniqueValues4); + QVERIFY(isSame(m3, uniqueValues4)); + + QMatrix4x4 m4(m3); + QVERIFY(isSame(m4, uniqueValues4)); + + QMatrix4x4 m5; + m5 = m3; + QVERIFY(isSame(m5, uniqueValues4)); + + m5.setToIdentity(); + QVERIFY(isIdentity(m5)); + + QMatrix4x4 m6(uniqueValues4); + QVERIFY(isSame(m6, uniqueValues4)); + qreal vals[16]; + m6.copyDataTo(vals); + for (int index = 0; index < 16; ++index) + QCOMPARE(vals[index], uniqueValues4[index]); + + QMatrix4x4 m8 + (uniqueValues4[0], uniqueValues4[1], uniqueValues4[2], uniqueValues4[3], + uniqueValues4[4], uniqueValues4[5], uniqueValues4[6], uniqueValues4[7], + uniqueValues4[8], uniqueValues4[9], uniqueValues4[10], uniqueValues4[11], + uniqueValues4[12], uniqueValues4[13], uniqueValues4[14], uniqueValues4[15]); + QVERIFY(isSame(m8, uniqueValues4)); +} + +// Test the creation of QMatrix4x3 objects in various ways: +// construct, copy, and modify. +void tst_QMatrixNxN::create4x3() +{ + QMatrix4x3 m1; + QVERIFY(isIdentity(m1)); + QVERIFY(m1.isIdentity()); + + QMatrix4x3 m2; + setMatrix(m2, uniqueValues4x3); + QVERIFY(isSame(m2, uniqueValues4x3)); + QVERIFY(!m2.isIdentity()); + + QMatrix4x3 m3; + setMatrixDirect(m3, uniqueValues4x3); + QVERIFY(isSame(m3, uniqueValues4x3)); + + QMatrix4x3 m4(m3); + QVERIFY(isSame(m4, uniqueValues4x3)); + + QMatrix4x3 m5; + m5 = m3; + QVERIFY(isSame(m5, uniqueValues4x3)); + + m5.setToIdentity(); + QVERIFY(isIdentity(m5)); + + QMatrix4x3 m6(uniqueValues4x3); + QVERIFY(isSame(m6, uniqueValues4x3)); + qreal vals[12]; + m6.copyDataTo(vals); + for (int index = 0; index < 12; ++index) + QCOMPARE(vals[index], uniqueValues4x3[index]); +} + +// Test isIdentity() for 2x2 matrices. +void tst_QMatrixNxN::isIdentity2x2() +{ + for (int i = 0; i < 2 * 2; ++i) { + QMatrix2x2 m; + QVERIFY(m.isIdentity()); + m.data()[i] = 42.0f; + QVERIFY(!m.isIdentity()); + } +} + +// Test isIdentity() for 3x3 matrices. +void tst_QMatrixNxN::isIdentity3x3() +{ + for (int i = 0; i < 3 * 3; ++i) { + QMatrix3x3 m; + QVERIFY(m.isIdentity()); + m.data()[i] = 42.0f; + QVERIFY(!m.isIdentity()); + } +} + +// Test isIdentity() for 4x4 matrices. +void tst_QMatrixNxN::isIdentity4x4() +{ + for (int i = 0; i < 4 * 4; ++i) { + QMatrix4x4 m; + QVERIFY(m.isIdentity()); + m.data()[i] = 42.0f; + QVERIFY(!m.isIdentity()); + } + + // Force the "Identity" flag bit to be lost and check again. + QMatrix4x4 m2; + m2.data()[0] = 1.0f; + QVERIFY(m2.isIdentity()); +} + +// Test isIdentity() for 4x3 matrices. +void tst_QMatrixNxN::isIdentity4x3() +{ + for (int i = 0; i < 4 * 3; ++i) { + QMatrix4x3 m; + QVERIFY(m.isIdentity()); + m.data()[i] = 42.0f; + QVERIFY(!m.isIdentity()); + } +} + +// Test 2x2 matrix comparisons. +void tst_QMatrixNxN::compare2x2() +{ + QMatrix2x2 m1(uniqueValues2); + QMatrix2x2 m2(uniqueValues2); + QMatrix2x2 m3(transposedValues2); + + QVERIFY(m1 == m2); + QVERIFY(!(m1 != m2)); + QVERIFY(m1 != m3); + QVERIFY(!(m1 == m3)); +} + +// Test 3x3 matrix comparisons. +void tst_QMatrixNxN::compare3x3() +{ + QMatrix3x3 m1(uniqueValues3); + QMatrix3x3 m2(uniqueValues3); + QMatrix3x3 m3(transposedValues3); + + QVERIFY(m1 == m2); + QVERIFY(!(m1 != m2)); + QVERIFY(m1 != m3); + QVERIFY(!(m1 == m3)); +} + +// Test 4x4 matrix comparisons. +void tst_QMatrixNxN::compare4x4() +{ + QMatrix4x4 m1(uniqueValues4); + QMatrix4x4 m2(uniqueValues4); + QMatrix4x4 m3(transposedValues4); + + QVERIFY(m1 == m2); + QVERIFY(!(m1 != m2)); + QVERIFY(m1 != m3); + QVERIFY(!(m1 == m3)); +} + +// Test 4x3 matrix comparisons. +void tst_QMatrixNxN::compare4x3() +{ + QMatrix4x3 m1(uniqueValues4x3); + QMatrix4x3 m2(uniqueValues4x3); + QMatrix4x3 m3(transposedValues3x4); + + QVERIFY(m1 == m2); + QVERIFY(!(m1 != m2)); + QVERIFY(m1 != m3); + QVERIFY(!(m1 == m3)); +} + +// Test matrix 2x2 transpose operations. +void tst_QMatrixNxN::transposed2x2() +{ + // Transposing the identity should result in the identity. + QMatrix2x2 m1; + QMatrix2x2 m2 = m1.transposed(); + QVERIFY(isIdentity(m2)); + + // Transpose a more interesting matrix that allows us to track + // exactly where each source element ends up. + QMatrix2x2 m3(uniqueValues2); + QMatrix2x2 m4 = m3.transposed(); + QVERIFY(isSame(m4, transposedValues2)); + + // Transpose in-place, just to check that the compiler is sane. + m3 = m3.transposed(); + QVERIFY(isSame(m3, transposedValues2)); +} + +// Test matrix 3x3 transpose operations. +void tst_QMatrixNxN::transposed3x3() +{ + // Transposing the identity should result in the identity. + QMatrix3x3 m1; + QMatrix3x3 m2 = m1.transposed(); + QVERIFY(isIdentity(m2)); + + // Transpose a more interesting matrix that allows us to track + // exactly where each source element ends up. + QMatrix3x3 m3(uniqueValues3); + QMatrix3x3 m4 = m3.transposed(); + QVERIFY(isSame(m4, transposedValues3)); + + // Transpose in-place, just to check that the compiler is sane. + m3 = m3.transposed(); + QVERIFY(isSame(m3, transposedValues3)); +} + +// Test matrix 4x4 transpose operations. +void tst_QMatrixNxN::transposed4x4() +{ + // Transposing the identity should result in the identity. + QMatrix4x4 m1; + QMatrix4x4 m2 = m1.transposed(); + QVERIFY(isIdentity(m2)); + + // Transpose a more interesting matrix that allows us to track + // exactly where each source element ends up. + QMatrix4x4 m3(uniqueValues4); + QMatrix4x4 m4 = m3.transposed(); + QVERIFY(isSame(m4, transposedValues4)); + + // Transpose in-place, just to check that the compiler is sane. + m3 = m3.transposed(); + QVERIFY(isSame(m3, transposedValues4)); +} + +// Test matrix 4x3 transpose operations. +void tst_QMatrixNxN::transposed4x3() +{ + QMatrix4x3 m3(uniqueValues4x3); + QMatrix3x4 m4 = m3.transposed(); + qreal values[12]; + m4.copyDataTo(values); + for (int index = 0; index < 12; ++index) + QCOMPARE(values[index], transposedValues3x4[index]); +} + +// Test matrix addition for 2x2 matrices. +void tst_QMatrixNxN::add2x2_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues2 << (void *)nullValues2 << (void *)nullValues2; + + QTest::newRow("identity/null") + << (void *)identityValues2 << (void *)nullValues2 << (void *)identityValues2; + + QTest::newRow("identity/identity") + << (void *)identityValues2 << (void *)identityValues2 << (void *)doubleIdentity2; + + static qreal const sumValues[16] = + {2.0f, 7.0f, + 7.0f, 12.0f}; + QTest::newRow("unique") + << (void *)uniqueValues2 << (void *)transposedValues2 << (void *)sumValues; +} +void tst_QMatrixNxN::add2x2() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix2x2 m1((const qreal *)m1Values); + QMatrix2x2 m2((const qreal *)m2Values); + + QMatrix2x2 m4(m1); + m4 += m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix2x2 m5; + m5 = m1 + m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix addition for 3x3 matrices. +void tst_QMatrixNxN::add3x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues3 << (void *)nullValues3 << (void *)nullValues3; + + QTest::newRow("identity/null") + << (void *)identityValues3 << (void *)nullValues3 << (void *)identityValues3; + + QTest::newRow("identity/identity") + << (void *)identityValues3 << (void *)identityValues3 << (void *)doubleIdentity3; + + static qreal const sumValues[16] = + {2.0f, 7.0f, 12.0f, + 7.0f, 12.0f, 17.0f, + 12.0f, 17.0f, 22.0f}; + QTest::newRow("unique") + << (void *)uniqueValues3 << (void *)transposedValues3 << (void *)sumValues; +} +void tst_QMatrixNxN::add3x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix3x3 m1((const qreal *)m1Values); + QMatrix3x3 m2((const qreal *)m2Values); + + QMatrix3x3 m4(m1); + m4 += m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix3x3 m5; + m5 = m1 + m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix addition for 4x4 matrices. +void tst_QMatrixNxN::add4x4_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues4 << (void *)nullValues4 << (void *)nullValues4; + + QTest::newRow("identity/null") + << (void *)identityValues4 << (void *)nullValues4 << (void *)identityValues4; + + QTest::newRow("identity/identity") + << (void *)identityValues4 << (void *)identityValues4 << (void *)doubleIdentity4; + + static qreal const sumValues[16] = + {2.0f, 7.0f, 12.0f, 17.0f, + 7.0f, 12.0f, 17.0f, 22.0f, + 12.0f, 17.0f, 22.0f, 27.0f, + 17.0f, 22.0f, 27.0f, 32.0f}; + QTest::newRow("unique") + << (void *)uniqueValues4 << (void *)transposedValues4 << (void *)sumValues; +} +void tst_QMatrixNxN::add4x4() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x4 m1((const qreal *)m1Values); + QMatrix4x4 m2((const qreal *)m2Values); + + QMatrix4x4 m4(m1); + m4 += m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix4x4 m5; + m5 = m1 + m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix addition for 4x3 matrices. +void tst_QMatrixNxN::add4x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues4x3 << (void *)nullValues4x3 << (void *)nullValues4x3; + + QTest::newRow("identity/null") + << (void *)identityValues4x3 << (void *)nullValues4x3 << (void *)identityValues4x3; + + QTest::newRow("identity/identity") + << (void *)identityValues4x3 << (void *)identityValues4x3 << (void *)doubleIdentity4x3; + + static qreal const sumValues[16] = + {2.0f, 7.0f, 12.0f, 6.0f, + 11.0f, 16.0f, 10.0f, 15.0f, + 20.0f, 14.0f, 19.0f, 24.0f}; + QTest::newRow("unique") + << (void *)uniqueValues4x3 << (void *)transposedValues3x4 << (void *)sumValues; +} +void tst_QMatrixNxN::add4x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x3 m1((const qreal *)m1Values); + QMatrix4x3 m2((const qreal *)m2Values); + + QMatrix4x3 m4(m1); + m4 += m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix4x3 m5; + m5 = m1 + m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix subtraction for 2x2 matrices. +void tst_QMatrixNxN::subtract2x2_data() +{ + // Use the same test cases as the add test. + add2x2_data(); +} +void tst_QMatrixNxN::subtract2x2() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix2x2 m1((const qreal *)m1Values); + QMatrix2x2 m2((const qreal *)m2Values); + QMatrix2x2 m3((const qreal *)m3Values); + + QMatrix2x2 m4(m3); + m4 -= m1; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix2x2 m5; + m5 = m3 - m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); + + QMatrix2x2 m6(m3); + m6 -= m2; + QVERIFY(isSame(m6, (const qreal *)m1Values)); + + QMatrix2x2 m7; + m7 = m3 - m2; + QVERIFY(isSame(m7, (const qreal *)m1Values)); +} + +// Test matrix subtraction for 3x3 matrices. +void tst_QMatrixNxN::subtract3x3_data() +{ + // Use the same test cases as the add test. + add3x3_data(); +} +void tst_QMatrixNxN::subtract3x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix3x3 m1((const qreal *)m1Values); + QMatrix3x3 m2((const qreal *)m2Values); + QMatrix3x3 m3((const qreal *)m3Values); + + QMatrix3x3 m4(m3); + m4 -= m1; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix3x3 m5; + m5 = m3 - m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); + + QMatrix3x3 m6(m3); + m6 -= m2; + QVERIFY(isSame(m6, (const qreal *)m1Values)); + + QMatrix3x3 m7; + m7 = m3 - m2; + QVERIFY(isSame(m7, (const qreal *)m1Values)); +} + +// Test matrix subtraction for 4x4 matrices. +void tst_QMatrixNxN::subtract4x4_data() +{ + // Use the same test cases as the add test. + add4x4_data(); +} +void tst_QMatrixNxN::subtract4x4() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x4 m1((const qreal *)m1Values); + QMatrix4x4 m2((const qreal *)m2Values); + QMatrix4x4 m3((const qreal *)m3Values); + + QMatrix4x4 m4(m3); + m4 -= m1; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix4x4 m5; + m5 = m3 - m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); + + QMatrix4x4 m6(m3); + m6 -= m2; + QVERIFY(isSame(m6, (const qreal *)m1Values)); + + QMatrix4x4 m7; + m7 = m3 - m2; + QVERIFY(isSame(m7, (const qreal *)m1Values)); +} + +// Test matrix subtraction for 4x3 matrices. +void tst_QMatrixNxN::subtract4x3_data() +{ + // Use the same test cases as the add test. + add4x3_data(); +} +void tst_QMatrixNxN::subtract4x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x3 m1((const qreal *)m1Values); + QMatrix4x3 m2((const qreal *)m2Values); + QMatrix4x3 m3((const qreal *)m3Values); + + QMatrix4x3 m4(m3); + m4 -= m1; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix4x3 m5; + m5 = m3 - m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); + + QMatrix4x3 m6(m3); + m6 -= m2; + QVERIFY(isSame(m6, (const qreal *)m1Values)); + + QMatrix4x3 m7; + m7 = m3 - m2; + QVERIFY(isSame(m7, (const qreal *)m1Values)); +} + +// Test matrix multiplication for 2x2 matrices. +void tst_QMatrixNxN::multiply2x2_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues2 << (void *)nullValues2 << (void *)nullValues2; + + QTest::newRow("null/unique") + << (void *)nullValues2 << (void *)uniqueValues2 << (void *)nullValues2; + + QTest::newRow("unique/null") + << (void *)uniqueValues2 << (void *)nullValues2 << (void *)nullValues2; + + QTest::newRow("unique/identity") + << (void *)uniqueValues2 << (void *)identityValues2 << (void *)uniqueValues2; + + QTest::newRow("identity/unique") + << (void *)identityValues2 << (void *)uniqueValues2 << (void *)uniqueValues2; + + static qreal uniqueResult[4]; + for (int row = 0; row < 2; ++row) { + for (int col = 0; col < 2; ++col) { + qreal sum = 0.0f; + for (int j = 0; j < 2; ++j) + sum += uniqueValues2[row * 2 + j] * transposedValues2[j * 2 + col]; + uniqueResult[row * 2 + col] = sum; + } + } + + QTest::newRow("unique/transposed") + << (void *)uniqueValues2 << (void *)transposedValues2 << (void *)uniqueResult; +} +void tst_QMatrixNxN::multiply2x2() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix2x2 m1((const qreal *)m1Values); + QMatrix2x2 m2((const qreal *)m2Values); + + QMatrix2x2 m5; + m5 = m1 * m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix multiplication for 3x3 matrices. +void tst_QMatrixNxN::multiply3x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues3 << (void *)nullValues3 << (void *)nullValues3; + + QTest::newRow("null/unique") + << (void *)nullValues3 << (void *)uniqueValues3 << (void *)nullValues3; + + QTest::newRow("unique/null") + << (void *)uniqueValues3 << (void *)nullValues3 << (void *)nullValues3; + + QTest::newRow("unique/identity") + << (void *)uniqueValues3 << (void *)identityValues3 << (void *)uniqueValues3; + + QTest::newRow("identity/unique") + << (void *)identityValues3 << (void *)uniqueValues3 << (void *)uniqueValues3; + + static qreal uniqueResult[9]; + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + qreal sum = 0.0f; + for (int j = 0; j < 3; ++j) + sum += uniqueValues3[row * 3 + j] * transposedValues3[j * 3 + col]; + uniqueResult[row * 3 + col] = sum; + } + } + + QTest::newRow("unique/transposed") + << (void *)uniqueValues3 << (void *)transposedValues3 << (void *)uniqueResult; +} +void tst_QMatrixNxN::multiply3x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix3x3 m1((const qreal *)m1Values); + QMatrix3x3 m2((const qreal *)m2Values); + + QMatrix3x3 m5; + m5 = m1 * m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix multiplication for 4x4 matrices. +void tst_QMatrixNxN::multiply4x4_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues4 << (void *)nullValues4 << (void *)nullValues4; + + QTest::newRow("null/unique") + << (void *)nullValues4 << (void *)uniqueValues4 << (void *)nullValues4; + + QTest::newRow("unique/null") + << (void *)uniqueValues4 << (void *)nullValues4 << (void *)nullValues4; + + QTest::newRow("unique/identity") + << (void *)uniqueValues4 << (void *)identityValues4 << (void *)uniqueValues4; + + QTest::newRow("identity/unique") + << (void *)identityValues4 << (void *)uniqueValues4 << (void *)uniqueValues4; + + static qreal uniqueResult[16]; + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + qreal sum = 0.0f; + for (int j = 0; j < 4; ++j) + sum += uniqueValues4[row * 4 + j] * transposedValues4[j * 4 + col]; + uniqueResult[row * 4 + col] = sum; + } + } + + QTest::newRow("unique/transposed") + << (void *)uniqueValues4 << (void *)transposedValues4 << (void *)uniqueResult; +} +void tst_QMatrixNxN::multiply4x4() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x4 m1((const qreal *)m1Values); + QMatrix4x4 m2((const qreal *)m2Values); + + QMatrix4x4 m4; + m4 = m1; + m4 *= m2; + QVERIFY(isSame(m4, (const qreal *)m3Values)); + + QMatrix4x4 m5; + m5 = m1 * m2; + QVERIFY(isSame(m5, (const qreal *)m3Values)); +} + +// Test matrix multiplication for 4x3 matrices. +void tst_QMatrixNxN::multiply4x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<void *>("m3Values"); + + QTest::newRow("null") + << (void *)nullValues4x3 << (void *)nullValues4x3 << (void *)nullValues3; + + QTest::newRow("null/unique") + << (void *)nullValues4x3 << (void *)uniqueValues4x3 << (void *)nullValues3; + + QTest::newRow("unique/null") + << (void *)uniqueValues4x3 << (void *)nullValues4x3 << (void *)nullValues3; + + static qreal uniqueResult[9]; + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + qreal sum = 0.0f; + for (int j = 0; j < 4; ++j) + sum += uniqueValues4x3[row * 4 + j] * transposedValues3x4[j * 3 + col]; + uniqueResult[row * 3 + col] = sum; + } + } + + QTest::newRow("unique/transposed") + << (void *)uniqueValues4x3 << (void *)transposedValues3x4 << (void *)uniqueResult; +} +void tst_QMatrixNxN::multiply4x3() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(void *, m3Values); + + QMatrix4x3 m1((const qreal *)m1Values); + QMatrix3x4 m2((const qreal *)m2Values); + + QGenericMatrix<3, 3, qreal> m4; + m4 = m1 * m2; + qreal values[9]; + m4.copyDataTo(values); + for (int index = 0; index < 9; ++index) + QCOMPARE(values[index], ((const qreal *)m3Values)[index]); +} + +// Test matrix multiplication by a factor for 2x2 matrices. +void tst_QMatrixNxN::multiplyFactor2x2_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<void *>("m2Values"); + + QTest::newRow("null") + << (void *)nullValues2 << (qreal)1.0f << (void *)nullValues2; + + QTest::newRow("double identity") + << (void *)identityValues2 << (qreal)2.0f << (void *)doubleIdentity2; + + static qreal const values[16] = + {1.0f, 2.0f, + 5.0f, 6.0f}; + static qreal const doubleValues[16] = + {2.0f, 4.0f, + 10.0f, 12.0f}; + static qreal const negDoubleValues[16] = + {-2.0f, -4.0f, + -10.0f, -12.0f}; + + QTest::newRow("unique") + << (void *)values << (qreal)2.0f << (void *)doubleValues; + + QTest::newRow("neg") + << (void *)values << (qreal)-2.0f << (void *)negDoubleValues; + + QTest::newRow("zero") + << (void *)values << (qreal)0.0f << (void *)nullValues4; +} +void tst_QMatrixNxN::multiplyFactor2x2() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + QMatrix2x2 m1((const qreal *)m1Values); + + QMatrix2x2 m3; + m3 = m1; + m3 *= factor; + QVERIFY(isSame(m3, (const qreal *)m2Values)); + + QMatrix2x2 m4; + m4 = m1 * factor; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix2x2 m5; + m5 = factor * m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); +} + +// Test matrix multiplication by a factor for 3x3 matrices. +void tst_QMatrixNxN::multiplyFactor3x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<void *>("m2Values"); + + QTest::newRow("null") + << (void *)nullValues3 << (qreal)1.0f << (void *)nullValues3; + + QTest::newRow("double identity") + << (void *)identityValues3 << (qreal)2.0f << (void *)doubleIdentity3; + + static qreal const values[16] = + {1.0f, 2.0f, 3.0f, + 5.0f, 6.0f, 7.0f, + 9.0f, 10.0f, 11.0f}; + static qreal const doubleValues[16] = + {2.0f, 4.0f, 6.0f, + 10.0f, 12.0f, 14.0f, + 18.0f, 20.0f, 22.0f}; + static qreal const negDoubleValues[16] = + {-2.0f, -4.0f, -6.0f, + -10.0f, -12.0f, -14.0f, + -18.0f, -20.0f, -22.0f}; + + QTest::newRow("unique") + << (void *)values << (qreal)2.0f << (void *)doubleValues; + + QTest::newRow("neg") + << (void *)values << (qreal)-2.0f << (void *)negDoubleValues; + + QTest::newRow("zero") + << (void *)values << (qreal)0.0f << (void *)nullValues4; +} +void tst_QMatrixNxN::multiplyFactor3x3() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + QMatrix3x3 m1((const qreal *)m1Values); + + QMatrix3x3 m3; + m3 = m1; + m3 *= factor; + QVERIFY(isSame(m3, (const qreal *)m2Values)); + + QMatrix3x3 m4; + m4 = m1 * factor; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix3x3 m5; + m5 = factor * m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); +} + +// Test matrix multiplication by a factor for 4x4 matrices. +void tst_QMatrixNxN::multiplyFactor4x4_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<void *>("m2Values"); + + QTest::newRow("null") + << (void *)nullValues4 << (qreal)1.0f << (void *)nullValues4; + + QTest::newRow("double identity") + << (void *)identityValues4 << (qreal)2.0f << (void *)doubleIdentity4; + + static qreal const values[16] = + {1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.0f, 14.0f, 15.0f, 16.0f}; + static qreal const doubleValues[16] = + {2.0f, 4.0f, 6.0f, 8.0f, + 10.0f, 12.0f, 14.0f, 16.0f, + 18.0f, 20.0f, 22.0f, 24.0f, + 26.0f, 28.0f, 30.0f, 32.0f}; + static qreal const negDoubleValues[16] = + {-2.0f, -4.0f, -6.0f, -8.0f, + -10.0f, -12.0f, -14.0f, -16.0f, + -18.0f, -20.0f, -22.0f, -24.0f, + -26.0f, -28.0f, -30.0f, -32.0f}; + + QTest::newRow("unique") + << (void *)values << (qreal)2.0f << (void *)doubleValues; + + QTest::newRow("neg") + << (void *)values << (qreal)-2.0f << (void *)negDoubleValues; + + QTest::newRow("zero") + << (void *)values << (qreal)0.0f << (void *)nullValues4; +} +void tst_QMatrixNxN::multiplyFactor4x4() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + QMatrix4x4 m1((const qreal *)m1Values); + + QMatrix4x4 m3; + m3 = m1; + m3 *= factor; + QVERIFY(isSame(m3, (const qreal *)m2Values)); + + QMatrix4x4 m4; + m4 = m1 * factor; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix4x4 m5; + m5 = factor * m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); +} + +// Test matrix multiplication by a factor for 4x3 matrices. +void tst_QMatrixNxN::multiplyFactor4x3_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<void *>("m2Values"); + + QTest::newRow("null") + << (void *)nullValues4x3 << (qreal)1.0f << (void *)nullValues4x3; + + QTest::newRow("double identity") + << (void *)identityValues4x3 << (qreal)2.0f << (void *)doubleIdentity4x3; + + static qreal const values[12] = + {1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f}; + static qreal const doubleValues[12] = + {2.0f, 4.0f, 6.0f, 8.0f, + 10.0f, 12.0f, 14.0f, 16.0f, + 18.0f, 20.0f, 22.0f, 24.0f}; + static qreal const negDoubleValues[12] = + {-2.0f, -4.0f, -6.0f, -8.0f, + -10.0f, -12.0f, -14.0f, -16.0f, + -18.0f, -20.0f, -22.0f, -24.0f}; + + QTest::newRow("unique") + << (void *)values << (qreal)2.0f << (void *)doubleValues; + + QTest::newRow("neg") + << (void *)values << (qreal)-2.0f << (void *)negDoubleValues; + + QTest::newRow("zero") + << (void *)values << (qreal)0.0f << (void *)nullValues4x3; +} +void tst_QMatrixNxN::multiplyFactor4x3() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + QMatrix4x3 m1((const qreal *)m1Values); + + QMatrix4x3 m3; + m3 = m1; + m3 *= factor; + QVERIFY(isSame(m3, (const qreal *)m2Values)); + + QMatrix4x3 m4; + m4 = m1 * factor; + QVERIFY(isSame(m4, (const qreal *)m2Values)); + + QMatrix4x3 m5; + m5 = factor * m1; + QVERIFY(isSame(m5, (const qreal *)m2Values)); +} + +// Test matrix division by a factor for 2x2 matrices. +void tst_QMatrixNxN::divideFactor2x2_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor2x2_data(); +} +void tst_QMatrixNxN::divideFactor2x2() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + if (factor == 0.0f) + return; + + QMatrix2x2 m2((const qreal *)m2Values); + + QMatrix2x2 m3; + m3 = m2; + m3 /= factor; + QVERIFY(isSame(m3, (const qreal *)m1Values)); + + QMatrix2x2 m4; + m4 = m2 / factor; + QVERIFY(isSame(m4, (const qreal *)m1Values)); +} + +// Test matrix division by a factor for 3x3 matrices. +void tst_QMatrixNxN::divideFactor3x3_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor3x3_data(); +} +void tst_QMatrixNxN::divideFactor3x3() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + if (factor == 0.0f) + return; + + QMatrix3x3 m2((const qreal *)m2Values); + + QMatrix3x3 m3; + m3 = m2; + m3 /= factor; + QVERIFY(isSame(m3, (const qreal *)m1Values)); + + QMatrix3x3 m4; + m4 = m2 / factor; + QVERIFY(isSame(m4, (const qreal *)m1Values)); +} + +// Test matrix division by a factor for 4x4 matrices. +void tst_QMatrixNxN::divideFactor4x4_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor4x4_data(); +} +void tst_QMatrixNxN::divideFactor4x4() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + if (factor == 0.0f) + return; + + QMatrix4x4 m2((const qreal *)m2Values); + + QMatrix4x4 m3; + m3 = m2; + m3 /= factor; + QVERIFY(isSame(m3, (const qreal *)m1Values)); + + QMatrix4x4 m4; + m4 = m2 / factor; + QVERIFY(isSame(m4, (const qreal *)m1Values)); +} + +// Test matrix division by a factor for 4x3 matrices. +void tst_QMatrixNxN::divideFactor4x3_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor4x3_data(); +} +void tst_QMatrixNxN::divideFactor4x3() +{ + QFETCH(void *, m1Values); + QFETCH(qreal, factor); + QFETCH(void *, m2Values); + + if (factor == 0.0f) + return; + + QMatrix4x3 m2((const qreal *)m2Values); + + QMatrix4x3 m3; + m3 = m2; + m3 /= factor; + QVERIFY(isSame(m3, (const qreal *)m1Values)); + + QMatrix4x3 m4; + m4 = m2 / factor; + QVERIFY(isSame(m4, (const qreal *)m1Values)); +} + +// Test matrix negation for 2x2 matrices. +void tst_QMatrixNxN::negate2x2_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor2x2_data(); +} +void tst_QMatrixNxN::negate2x2() +{ + QFETCH(void *, m1Values); + + const qreal *values = (const qreal *)m1Values; + + QMatrix2x2 m1(values); + + qreal negated[4]; + for (int index = 0; index < 4; ++index) + negated[index] = -values[index]; + + QMatrix2x2 m2; + m2 = -m1; + QVERIFY(isSame(m2, negated)); +} + +// Test matrix negation for 3x3 matrices. +void tst_QMatrixNxN::negate3x3_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor3x3_data(); +} +void tst_QMatrixNxN::negate3x3() +{ + QFETCH(void *, m1Values); + + const qreal *values = (const qreal *)m1Values; + + QMatrix3x3 m1(values); + + qreal negated[9]; + for (int index = 0; index < 9; ++index) + negated[index] = -values[index]; + + QMatrix3x3 m2; + m2 = -m1; + QVERIFY(isSame(m2, negated)); +} + +// Test matrix negation for 4x4 matrices. +void tst_QMatrixNxN::negate4x4_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor4x4_data(); +} +void tst_QMatrixNxN::negate4x4() +{ + QFETCH(void *, m1Values); + + const qreal *values = (const qreal *)m1Values; + + QMatrix4x4 m1(values); + + qreal negated[16]; + for (int index = 0; index < 16; ++index) + negated[index] = -values[index]; + + QMatrix4x4 m2; + m2 = -m1; + QVERIFY(isSame(m2, negated)); +} + +// Test matrix negation for 4x3 matrices. +void tst_QMatrixNxN::negate4x3_data() +{ + // Use the same test cases as the multiplyFactor test. + multiplyFactor4x3_data(); +} +void tst_QMatrixNxN::negate4x3() +{ + QFETCH(void *, m1Values); + + const qreal *values = (const qreal *)m1Values; + + QMatrix4x3 m1(values); + + qreal negated[12]; + for (int index = 0; index < 12; ++index) + negated[index] = -values[index]; + + QMatrix4x3 m2; + m2 = -m1; + QVERIFY(isSame(m2, negated)); +} + +// Matrix inverted. This is a more straight-forward implementation +// of the algorithm at http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24 +// than the optimized version in the QMatrix4x4 code. Hopefully it is +// easier to verify that this version is the same as the reference. + +struct Matrix3 +{ + qreal v[9]; +}; +struct Matrix4 +{ + qreal v[16]; +}; + +static qreal m3Determinant(const Matrix3& m) +{ + return m.v[0] * (m.v[4] * m.v[8] - m.v[7] * m.v[5]) - + m.v[1] * (m.v[3] * m.v[8] - m.v[6] * m.v[5]) + + m.v[2] * (m.v[3] * m.v[7] - m.v[6] * m.v[4]); +} + +static bool m3Inverse(const Matrix3& min, Matrix3& mout) +{ + qreal det = m3Determinant(min); + if (det == 0.0f) + return false; + mout.v[0] = (min.v[4] * min.v[8] - min.v[5] * min.v[7]) / det; + mout.v[1] = -(min.v[1] * min.v[8] - min.v[2] * min.v[7]) / det; + mout.v[2] = (min.v[1] * min.v[5] - min.v[4] * min.v[2]) / det; + mout.v[3] = -(min.v[3] * min.v[8] - min.v[5] * min.v[6]) / det; + mout.v[4] = (min.v[0] * min.v[8] - min.v[6] * min.v[2]) / det; + mout.v[5] = -(min.v[0] * min.v[5] - min.v[3] * min.v[2]) / det; + mout.v[6] = (min.v[3] * min.v[7] - min.v[6] * min.v[4]) / det; + mout.v[7] = -(min.v[0] * min.v[7] - min.v[6] * min.v[1]) / det; + mout.v[8] = (min.v[0] * min.v[4] - min.v[1] * min.v[3]) / det; + return true; +} + +static void m3Transpose(Matrix3& m) +{ + qSwap(m.v[1], m.v[3]); + qSwap(m.v[2], m.v[6]); + qSwap(m.v[5], m.v[7]); +} + +static void m4Submatrix(const Matrix4& min, Matrix3& mout, int i, int j) +{ + for (int di = 0; di < 3; ++di) { + for (int dj = 0; dj < 3; ++dj) { + int si = di + ((di >= i) ? 1 : 0); + int sj = dj + ((dj >= j) ? 1 : 0); + mout.v[di * 3 + dj] = min.v[si * 4 + sj]; + } + } +} + +static qreal m4Determinant(const Matrix4& m) +{ + qreal det; + qreal result = 0.0f; + qreal i = 1.0f; + Matrix3 msub; + for (int n = 0; n < 4; ++n, i *= -1.0f) { + m4Submatrix(m, msub, 0, n); + det = m3Determinant(msub); + result += m.v[n] * det * i; + } + return result; +} + +static void m4Inverse(const Matrix4& min, Matrix4& mout) +{ + qreal det = m4Determinant(min); + Matrix3 msub; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + qreal sign = 1.0f - ((i + j) % 2) * 2.0f; + m4Submatrix(min, msub, i, j); + mout.v[i + j * 4] = (m3Determinant(msub) * sign) / det; + } + } +} + +// Test matrix inverted for 4x4 matrices. +void tst_QMatrixNxN::inverted4x4_data() +{ + QTest::addColumn<void *>("m1Values"); + QTest::addColumn<void *>("m2Values"); + QTest::addColumn<bool>("invertible"); + + QTest::newRow("null") + << (void *)nullValues4 << (void *)identityValues4 << false; + + QTest::newRow("identity") + << (void *)identityValues4 << (void *)identityValues4 << true; + + QTest::newRow("unique") + << (void *)uniqueValues4 << (void *)identityValues4 << false; + + static Matrix4 const invertible = { + {5.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 6.0f, 0.0f, 3.0f, + 0.0f, 0.0f, 7.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f} + }; + static Matrix4 inverted; + m4Inverse(invertible, inverted); + + QTest::newRow("invertible") + << (void *)invertible.v << (void *)inverted.v << true; + + static Matrix4 const invertible2 = { + {1.0f, 2.0f, 4.0f, 2.0f, + 8.0f, 3.0f, 5.0f, 3.0f, + 6.0f, 7.0f, 9.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f} + }; + static Matrix4 inverted2; + m4Inverse(invertible2, inverted2); + + QTest::newRow("invertible2") + << (void *)invertible2.v << (void *)inverted2.v << true; + + static Matrix4 const translate = { + {1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 1.0f, 0.0f, 3.0f, + 0.0f, 0.0f, 1.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f} + }; + static Matrix4 const inverseTranslate = { + {1.0f, 0.0f, 0.0f, -2.0f, + 0.0f, 1.0f, 0.0f, -3.0f, + 0.0f, 0.0f, 1.0f, -4.0f, + 0.0f, 0.0f, 0.0f, 1.0f} + }; + + QTest::newRow("translate") + << (void *)translate.v << (void *)inverseTranslate.v << true; +} +void tst_QMatrixNxN::inverted4x4() +{ + QFETCH(void *, m1Values); + QFETCH(void *, m2Values); + QFETCH(bool, invertible); + + QMatrix4x4 m1((const qreal *)m1Values); + + if (invertible) + QVERIFY(m1.determinant() != 0.0f); + else + QVERIFY(m1.determinant() == 0.0f); + + Matrix4 m1alt; + memcpy(m1alt.v, (const qreal *)m1Values, sizeof(m1alt.v)); + + QCOMPARE(m1.determinant(), m4Determinant(m1alt)); + + QMatrix4x4 m2; + bool inv; + m2 = m1.inverted(&inv); + QVERIFY(isSame(m2, (const qreal *)m2Values)); + + if (invertible) { + QVERIFY(inv); + + Matrix4 m2alt; + m4Inverse(m1alt, m2alt); + QVERIFY(isSame(m2, m2alt.v)); + + QMatrix4x4 m3; + m3 = m1 * m2; + QVERIFY(isIdentity(m3)); + + QMatrix4x4 m4; + m4 = m2 * m1; + QVERIFY(isIdentity(m4)); + } else { + QVERIFY(!inv); + } + + // Test again, after inferring the special matrix type. + m1.optimize(); + m2 = m1.inverted(&inv); + QVERIFY(isSame(m2, (const qreal *)m2Values)); + QCOMPARE(inv, invertible); +} + +void tst_QMatrixNxN::orthonormalInverse4x4() +{ + QMatrix4x4 m1; + QVERIFY(qFuzzyCompare(m1.inverted(), m1)); + + QMatrix4x4 m2; + m2.rotate(45.0, 1.0, 0.0, 0.0); + m2.translate(10.0, 0.0, 0.0); + + // Use operator() to drop the internal flags that + // mark the matrix as orthonormal. This will force inverted() + // to compute m3.inverted() the long way. We can then compare + // the result to what the faster algorithm produces on m2. + QMatrix4x4 m3 = m2; + m3(0, 0); + bool invertible; + QVERIFY(qFuzzyCompare(m2.inverted(&invertible), m3.inverted())); + QVERIFY(invertible); + + QMatrix4x4 m4; + m4.rotate(45.0, 0.0, 1.0, 0.0); + QMatrix4x4 m5 = m4; + m5(0, 0); + QVERIFY(qFuzzyCompare(m4.inverted(), m5.inverted())); + + QMatrix4x4 m6; + m1.rotate(88, 0.0, 0.0, 1.0); + m1.translate(-20.0, 20.0, 15.0); + m1.rotate(25, 1.0, 0.0, 0.0); + QMatrix4x4 m7 = m6; + m7(0, 0); + QVERIFY(qFuzzyCompare(m6.inverted(), m7.inverted())); +} + +// Test the generation and use of 4x4 scale matrices. +void tst_QMatrixNxN::scale4x4_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<void *>("resultValues"); + + static const qreal nullScale[] = + {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (void *)nullScale; + + QTest::newRow("identity") + << (qreal)1.0f << (qreal)1.0f << (qreal)1.0f << (void *)identityValues4; + + static const qreal doubleScale[] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("double") + << (qreal)2.0f << (qreal)2.0f << (qreal)2.0f << (void *)doubleScale; + + static const qreal complexScale[] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 11.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -6.5f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("complex") + << (qreal)2.0f << (qreal)11.0f << (qreal)-6.5f << (void *)complexScale; + + static const qreal complexScale2D[] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -11.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("complex2D") + << (qreal)2.0f << (qreal)-11.0f << (qreal)1.0f << (void *)complexScale2D; +} +void tst_QMatrixNxN::scale4x4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(void *, resultValues); + + QMatrix4x4 result((const qreal *)resultValues); + + QMatrix4x4 m1; + m1.scale(QVector3D(x, y, z)); + QVERIFY(isSame(m1, (const qreal *)resultValues)); + + QMatrix4x4 m2; + m2.scale(x, y, z); + QVERIFY(isSame(m2, (const qreal *)resultValues)); + + if (z == 1.0f) { + QMatrix4x4 m2b; + m2b.scale(x, y); + QVERIFY(m2b == m2); + } + + QVector3D v1(2.0f, 3.0f, -4.0f); + QVector3D v2 = m1 * v1; + QCOMPARE(v2.x(), (qreal)(2.0f * x)); + QCOMPARE(v2.y(), (qreal)(3.0f * y)); + QCOMPARE(v2.z(), (qreal)(-4.0f * z)); + + v2 = v1 * m1; + QCOMPARE(v2.x(), (qreal)(2.0f * x)); + QCOMPARE(v2.y(), (qreal)(3.0f * y)); + QCOMPARE(v2.z(), (qreal)(-4.0f * z)); + + QVector4D v3(2.0f, 3.0f, -4.0f, 34.0f); + QVector4D v4 = m1 * v3; + QCOMPARE(v4.x(), (qreal)(2.0f * x)); + QCOMPARE(v4.y(), (qreal)(3.0f * y)); + QCOMPARE(v4.z(), (qreal)(-4.0f * z)); + QCOMPARE(v4.w(), (qreal)34.0f); + + v4 = v3 * m1; + QCOMPARE(v4.x(), (qreal)(2.0f * x)); + QCOMPARE(v4.y(), (qreal)(3.0f * y)); + QCOMPARE(v4.z(), (qreal)(-4.0f * z)); + QCOMPARE(v4.w(), (qreal)34.0f); + + QPoint p1(2, 3); + QPoint p2 = m1 * p1; + QCOMPARE(p2.x(), (int)(2.0f * x)); + QCOMPARE(p2.y(), (int)(3.0f * y)); + + p2 = p1 * m1; + QCOMPARE(p2.x(), (int)(2.0f * x)); + QCOMPARE(p2.y(), (int)(3.0f * y)); + + QPointF p3(2.0f, 3.0f); + QPointF p4 = m1 * p3; + QCOMPARE(p4.x(), (qreal)(2.0f * x)); + QCOMPARE(p4.y(), (qreal)(3.0f * y)); + + p4 = p3 * m1; + QCOMPARE(p4.x(), (qreal)(2.0f * x)); + QCOMPARE(p4.y(), (qreal)(3.0f * y)); + + QMatrix4x4 m3(uniqueValues4); + QMatrix4x4 m4(m3); + m4.scale(x, y, z); + QVERIFY(m4 == m3 * m1); + + if (x == y && y == z) { + QMatrix4x4 m5; + m5.scale(x); + QVERIFY(isSame(m5, (const qreal *)resultValues)); + } + + if (z == 1.0f) { + QMatrix4x4 m4b(m3); + m4b.scale(x, y); + QVERIFY(m4b == m4); + } + + // Test coverage when the special matrix type is unknown. + + QMatrix4x4 m6; + m6(0, 0) = 1.0f; + m6.scale(QVector3D(x, y, z)); + QVERIFY(isSame(m6, (const qreal *)resultValues)); + + QMatrix4x4 m7; + m7(0, 0) = 1.0f; + m7.scale(x, y, z); + QVERIFY(isSame(m7, (const qreal *)resultValues)); + + if (x == y && y == z) { + QMatrix4x4 m8; + m8(0, 0) = 1.0f; + m8.scale(x); + QVERIFY(isSame(m8, (const qreal *)resultValues)); + + m8.optimize(); + m8.scale(1.0f); + QVERIFY(isSame(m8, (const qreal *)resultValues)); + + QMatrix4x4 m9; + m9.translate(0.0f, 0.0f, 0.0f); + m9.scale(x); + QVERIFY(isSame(m9, (const qreal *)resultValues)); + } +} + +// Test the generation and use of 4x4 translation matrices. +void tst_QMatrixNxN::translate4x4_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<void *>("resultValues"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (void *)identityValues4; + + static const qreal identityTranslate[] = + {1.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 1.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("identity") + << (qreal)1.0f << (qreal)1.0f << (qreal)1.0f << (void *)identityTranslate; + + static const qreal complexTranslate[] = + {1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 1.0f, 0.0f, 11.0f, + 0.0f, 0.0f, 1.0f, -6.5f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("complex") + << (qreal)2.0f << (qreal)11.0f << (qreal)-6.5f << (void *)complexTranslate; + + static const qreal complexTranslate2D[] = + {1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 1.0f, 0.0f, -11.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("complex2D") + << (qreal)2.0f << (qreal)-11.0f << (qreal)0.0f << (void *)complexTranslate2D; +} +void tst_QMatrixNxN::translate4x4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(void *, resultValues); + + QMatrix4x4 result((const qreal *)resultValues); + + QMatrix4x4 m1; + m1.translate(QVector3D(x, y, z)); + QVERIFY(isSame(m1, (const qreal *)resultValues)); + + QMatrix4x4 m2; + m2.translate(x, y, z); + QVERIFY(isSame(m2, (const qreal *)resultValues)); + + if (z == 0.0f) { + QMatrix4x4 m2b; + m2b.translate(x, y); + QVERIFY(m2b == m2); + } + + QVector3D v1(2.0f, 3.0f, -4.0f); + QVector3D v2 = m1 * v1; + QCOMPARE(v2.x(), (qreal)(2.0f + x)); + QCOMPARE(v2.y(), (qreal)(3.0f + y)); + QCOMPARE(v2.z(), (qreal)(-4.0f + z)); + + QVector4D v3(2.0f, 3.0f, -4.0f, 1.0f); + QVector4D v4 = m1 * v3; + QCOMPARE(v4.x(), (qreal)(2.0f + x)); + QCOMPARE(v4.y(), (qreal)(3.0f + y)); + QCOMPARE(v4.z(), (qreal)(-4.0f + z)); + QCOMPARE(v4.w(), (qreal)1.0f); + + QVector4D v5(2.0f, 3.0f, -4.0f, 34.0f); + QVector4D v6 = m1 * v5; + QCOMPARE(v6.x(), (qreal)(2.0f + x * 34.0f)); + QCOMPARE(v6.y(), (qreal)(3.0f + y * 34.0f)); + QCOMPARE(v6.z(), (qreal)(-4.0f + z * 34.0f)); + QCOMPARE(v6.w(), (qreal)34.0f); + + QPoint p1(2, 3); + QPoint p2 = m1 * p1; + QCOMPARE(p2.x(), (int)(2.0f + x)); + QCOMPARE(p2.y(), (int)(3.0f + y)); + + QPointF p3(2.0f, 3.0f); + QPointF p4 = m1 * p3; + QCOMPARE(p4.x(), (qreal)(2.0f + x)); + QCOMPARE(p4.y(), (qreal)(3.0f + y)); + + QMatrix4x4 m3(uniqueValues4); + QMatrix4x4 m4(m3); + m4.translate(x, y, z); + QVERIFY(m4 == m3 * m1); + + if (z == 0.0f) { + QMatrix4x4 m4b(m3); + m4b.translate(x, y); + QVERIFY(m4b == m4); + } +} + +// Test the generation and use of 4x4 rotation matrices. +void tst_QMatrixNxN::rotate4x4_data() +{ + QTest::addColumn<qreal>("angle"); + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<void *>("resultValues"); + + static const qreal nullRotate[] = + {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("null") + << (qreal)90.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (void *)nullRotate; + + static const qreal noRotate[] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("zerodegrees") + << (qreal)0.0f + << (qreal)2.0f << (qreal)3.0f << (qreal)-4.0f + << (void *)noRotate; + + static const qreal xRotate[] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("xrotate") + << (qreal)90.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (void *)xRotate; + + static const qreal xRotateNeg[] = + {1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("-xrotate") + << (qreal)90.0f + << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f + << (void *)xRotateNeg; + + static const qreal yRotate[] = + {0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("yrotate") + << (qreal)90.0f + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (void *)yRotate; + + static const qreal yRotateNeg[] = + {0.0f, 0.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("-yrotate") + << (qreal)90.0f + << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f + << (void *)yRotateNeg; + + static const qreal zRotate[] = + {0.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("zrotate") + << (qreal)90.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (void *)zRotate; + + static const qreal zRotateNeg[] = + {0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("-zrotate") + << (qreal)90.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f + << (void *)zRotateNeg; + + // Algorithm from http://en.wikipedia.org/wiki/Rotation_matrix. + // Deliberately different from the one in the code for cross-checking. + static qreal complexRotate[16]; + qreal x = 1.0f; + qreal y = 2.0f; + qreal z = -6.0f; + qreal angle = -45.0f; + qreal c = qCos(angle * M_PI / 180.0f); + qreal s = qSin(angle * M_PI / 180.0f); + qreal len = qSqrt(x * x + y * y + z * z); + qreal xu = x / len; + qreal yu = y / len; + qreal zu = z / len; + complexRotate[0] = (qreal)((1 - xu * xu) * c + xu * xu); + complexRotate[1] = (qreal)(-zu * s - xu * yu * c + xu * yu); + complexRotate[2] = (qreal)(yu * s - xu * zu * c + xu * zu); + complexRotate[3] = 0; + complexRotate[4] = (qreal)(zu * s - xu * yu * c + xu * yu); + complexRotate[5] = (qreal)((1 - yu * yu) * c + yu * yu); + complexRotate[6] = (qreal)(-xu * s - yu * zu * c + yu * zu); + complexRotate[7] = 0; + complexRotate[8] = (qreal)(-yu * s - xu * zu * c + xu * zu); + complexRotate[9] = (qreal)(xu * s - yu * zu * c + yu * zu); + complexRotate[10] = (qreal)((1 - zu * zu) * c + zu * zu); + complexRotate[11] = 0; + complexRotate[12] = 0; + complexRotate[13] = 0; + complexRotate[14] = 0; + complexRotate[15] = 1; + + QTest::newRow("complex") + << (qreal)angle + << (qreal)x << (qreal)y << (qreal)z + << (void *)complexRotate; +} +void tst_QMatrixNxN::rotate4x4() +{ + QFETCH(qreal, angle); + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(void *, resultValues); + + QMatrix4x4 m1; + m1.rotate(angle, QVector3D(x, y, z)); + QVERIFY(isSame(m1, (const qreal *)resultValues)); + + QMatrix4x4 m2; + m2.rotate(angle, x, y, z); + QVERIFY(isSame(m2, (const qreal *)resultValues)); + + QMatrix4x4 m3(uniqueValues4); + QMatrix4x4 m4(m3); + m4.rotate(angle, x, y, z); + QVERIFY(qFuzzyCompare(m4, m3 * m1)); + + // Null vectors don't make sense for quaternion rotations. + if (x != 0 || y != 0 || z != 0) { + QMatrix4x4 m5; + m5.rotate(QQuaternion::fromAxisAndAngle(QVector3D(x, y, z), angle)); + QVERIFY(isSame(m5, (const qreal *)resultValues)); + } + +#define ROTATE4(xin,yin,zin,win,xout,yout,zout,wout) \ + do { \ + xout = ((const qreal *)resultValues)[0] * xin + \ + ((const qreal *)resultValues)[1] * yin + \ + ((const qreal *)resultValues)[2] * zin + \ + ((const qreal *)resultValues)[3] * win; \ + yout = ((const qreal *)resultValues)[4] * xin + \ + ((const qreal *)resultValues)[5] * yin + \ + ((const qreal *)resultValues)[6] * zin + \ + ((const qreal *)resultValues)[7] * win; \ + zout = ((const qreal *)resultValues)[8] * xin + \ + ((const qreal *)resultValues)[9] * yin + \ + ((const qreal *)resultValues)[10] * zin + \ + ((const qreal *)resultValues)[11] * win; \ + wout = ((const qreal *)resultValues)[12] * xin + \ + ((const qreal *)resultValues)[13] * yin + \ + ((const qreal *)resultValues)[14] * zin + \ + ((const qreal *)resultValues)[15] * win; \ + } while (0) + + // Rotate various test vectors using the straight-forward approach. + qreal v1x, v1y, v1z, v1w; + ROTATE4(2.0f, 3.0f, -4.0f, 1.0f, v1x, v1y, v1z, v1w); + v1x /= v1w; + v1y /= v1w; + v1z /= v1w; + qreal v3x, v3y, v3z, v3w; + ROTATE4(2.0f, 3.0f, -4.0f, 1.0f, v3x, v3y, v3z, v3w); + qreal v5x, v5y, v5z, v5w; + ROTATE4(2.0f, 3.0f, -4.0f, 34.0f, v5x, v5y, v5z, v5w); + qreal p1x, p1y, p1z, p1w; + ROTATE4(2.0f, 3.0f, 0.0f, 1.0f, p1x, p1y, p1z, p1w); + p1x /= p1w; + p1y /= p1w; + p1z /= p1w; + + QVector3D v1(2.0f, 3.0f, -4.0f); + QVector3D v2 = m1 * v1; + QVERIFY(fuzzyCompare(v2.x(), v1x)); + QVERIFY(fuzzyCompare(v2.y(), v1y)); + QVERIFY(fuzzyCompare(v2.z(), v1z)); + + QVector4D v3(2.0f, 3.0f, -4.0f, 1.0f); + QVector4D v4 = m1 * v3; + QVERIFY(fuzzyCompare(v4.x(), v3x)); + QVERIFY(fuzzyCompare(v4.y(), v3y)); + QVERIFY(fuzzyCompare(v4.z(), v3z)); + QVERIFY(fuzzyCompare(v4.w(), v3w)); + + QVector4D v5(2.0f, 3.0f, -4.0f, 34.0f); + QVector4D v6 = m1 * v5; + QVERIFY(fuzzyCompare(v6.x(), v5x)); + QVERIFY(fuzzyCompare(v6.y(), v5y)); + QVERIFY(fuzzyCompare(v6.z(), v5z)); + QVERIFY(fuzzyCompare(v6.w(), v5w)); + + QPoint p1(2, 3); + QPoint p2 = m1 * p1; + QCOMPARE(p2.x(), qRound(p1x)); + QCOMPARE(p2.y(), qRound(p1y)); + + QPointF p3(2.0f, 3.0f); + QPointF p4 = m1 * p3; + QVERIFY(fuzzyCompare(p4.x(), p1x)); + QVERIFY(fuzzyCompare(p4.y(), p1y)); + + if (x != 0 || y != 0 || z != 0) { + QQuaternion q = QQuaternion::fromAxisAndAngle(QVector3D(x, y, z), angle); + QVector3D vq = q.rotatedVector(v1); + QVERIFY(fuzzyCompare(vq.x(), v1x)); + QVERIFY(fuzzyCompare(vq.y(), v1y)); + QVERIFY(fuzzyCompare(vq.z(), v1z)); + } +} + +static bool isSame(const QMatrix3x3& m1, const Matrix3& m2) +{ + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + if (!fuzzyCompare(m1(row, col), m2.v[row * 3 + col])) + return false; + } + } + return true; +} + +// Test the computation of normal matrices from 4x4 transformation matrices. +void tst_QMatrixNxN::normalMatrix_data() +{ + QTest::addColumn<void *>("mValues"); + + QTest::newRow("identity") + << (void *)identityValues4; + QTest::newRow("unique") + << (void *)uniqueValues4; // Not invertible because determinant == 0. + + static qreal const translateValues[16] = + {1.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 1.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 1.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const scaleValues[16] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 7.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 9.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothValues[16] = + {2.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const rotateValues[16] = + {0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const nullScaleValues1[16] = + {0.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const nullScaleValues2[16] = + {2.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const nullScaleValues3[16] = + {2.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 0.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + + QTest::newRow("translate") << (void *)translateValues; + QTest::newRow("scale") << (void *)scaleValues; + QTest::newRow("both") << (void *)bothValues; + QTest::newRow("rotate") << (void *)rotateValues; + QTest::newRow("null scale 1") << (void *)nullScaleValues1; + QTest::newRow("null scale 2") << (void *)nullScaleValues2; + QTest::newRow("null scale 3") << (void *)nullScaleValues3; +} +void tst_QMatrixNxN::normalMatrix() +{ + QFETCH(void *, mValues); + const qreal *values = (const qreal *)mValues; + + // Compute the expected answer the long way. + Matrix3 min; + Matrix3 answer; + min.v[0] = values[0]; + min.v[1] = values[1]; + min.v[2] = values[2]; + min.v[3] = values[4]; + min.v[4] = values[5]; + min.v[5] = values[6]; + min.v[6] = values[8]; + min.v[7] = values[9]; + min.v[8] = values[10]; + bool invertible = m3Inverse(min, answer); + m3Transpose(answer); + + // Perform the test. + QMatrix4x4 m1(values); + QMatrix3x3 n1 = m1.normalMatrix(); + + if (invertible) + QVERIFY(::isSame(n1, answer)); + else + QVERIFY(isIdentity(n1)); + + // Perform the test again, after inferring special matrix types. + // This tests the optimized paths in the normalMatrix() function. + m1.optimize(); + n1 = m1.normalMatrix(); + + if (invertible) + QVERIFY(::isSame(n1, answer)); + else + QVERIFY(isIdentity(n1)); +} + +// Test optimized transformations on 4x4 matrices. +void tst_QMatrixNxN::optimizedTransforms() +{ + static qreal const translateValues[16] = + {1.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 1.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 1.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const translateDoubleValues[16] = + {1.0f, 0.0f, 0.0f, 8.0f, + 0.0f, 1.0f, 0.0f, 10.0f, + 0.0f, 0.0f, 1.0f, -6.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const scaleValues[16] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 7.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 9.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const scaleDoubleValues[16] = + {4.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 49.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 81.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothValues[16] = + {2.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothReverseValues[16] = + {2.0f, 0.0f, 0.0f, 4.0f * 2.0f, + 0.0f, 7.0f, 0.0f, 5.0f * 7.0f, + 0.0f, 0.0f, 9.0f, -3.0f * 9.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothThenTranslateValues[16] = + {2.0f, 0.0f, 0.0f, 4.0f + 2.0f * 4.0f, + 0.0f, 7.0f, 0.0f, 5.0f + 7.0f * 5.0f, + 0.0f, 0.0f, 9.0f, -3.0f + 9.0f * -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + static qreal const bothThenScaleValues[16] = + {4.0f, 0.0f, 0.0f, 4.0f, + 0.0f, 49.0f, 0.0f, 5.0f, + 0.0f, 0.0f, 81.0f, -3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + + QMatrix4x4 translate(translateValues); + QMatrix4x4 scale(scaleValues); + QMatrix4x4 both(bothValues); + + QMatrix4x4 m1; + m1.translate(4.0f, 5.0f, -3.0f); + QVERIFY(isSame(m1, translateValues)); + m1.translate(4.0f, 5.0f, -3.0f); + QVERIFY(isSame(m1, translateDoubleValues)); + + QMatrix4x4 m2; + m2.translate(QVector3D(4.0f, 5.0f, -3.0f)); + QVERIFY(isSame(m2, translateValues)); + m2.translate(QVector3D(4.0f, 5.0f, -3.0f)); + QVERIFY(isSame(m2, translateDoubleValues)); + + QMatrix4x4 m3; + m3.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m3, scaleValues)); + m3.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m3, scaleDoubleValues)); + + QMatrix4x4 m4; + m4.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m4, scaleValues)); + m4.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m4, scaleDoubleValues)); + + QMatrix4x4 m5; + m5.translate(4.0f, 5.0f, -3.0f); + m5.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m5, bothValues)); + m5.translate(4.0f, 5.0f, -3.0f); + QVERIFY(isSame(m5, bothThenTranslateValues)); + + QMatrix4x4 m6; + m6.translate(QVector3D(4.0f, 5.0f, -3.0f)); + m6.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m6, bothValues)); + m6.translate(QVector3D(4.0f, 5.0f, -3.0f)); + QVERIFY(isSame(m6, bothThenTranslateValues)); + + QMatrix4x4 m7; + m7.scale(2.0f, 7.0f, 9.0f); + m7.translate(4.0f, 5.0f, -3.0f); + QVERIFY(isSame(m7, bothReverseValues)); + + QMatrix4x4 m8; + m8.scale(QVector3D(2.0f, 7.0f, 9.0f)); + m8.translate(QVector3D(4.0f, 5.0f, -3.0f)); + QVERIFY(isSame(m8, bothReverseValues)); + + QMatrix4x4 m9; + m9.translate(4.0f, 5.0f, -3.0f); + m9.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m9, bothValues)); + m9.scale(2.0f, 7.0f, 9.0f); + QVERIFY(isSame(m9, bothThenScaleValues)); + + QMatrix4x4 m10; + m10.translate(QVector3D(4.0f, 5.0f, -3.0f)); + m10.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m10, bothValues)); + m10.scale(QVector3D(2.0f, 7.0f, 9.0f)); + QVERIFY(isSame(m10, bothThenScaleValues)); +} + +// Test orthographic projections. +void tst_QMatrixNxN::ortho() +{ + QMatrix4x4 m1; + m1.ortho(QRect(0, 0, 300, 150)); + QPointF p1 = m1 * QPointF(0, 0); + QPointF p2 = m1 * QPointF(300, 0); + QPointF p3 = m1 * QPointF(0, 150); + QPointF p4 = m1 * QPointF(300, 150); + QVector3D p5 = m1 * QVector3D(300, 150, 1); + QVERIFY(fuzzyCompare(p1.x(), -1.0)); + QVERIFY(fuzzyCompare(p1.y(), 1.0)); + QVERIFY(fuzzyCompare(p2.x(), 1.0)); + QVERIFY(fuzzyCompare(p2.y(), 1.0)); + QVERIFY(fuzzyCompare(p3.x(), -1.0)); + QVERIFY(fuzzyCompare(p3.y(), -1.0)); + QVERIFY(fuzzyCompare(p4.x(), 1.0)); + QVERIFY(fuzzyCompare(p4.y(), -1.0)); + QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0)); + QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0)); + QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0)); + + QMatrix4x4 m2; + m2.ortho(QRectF(0, 0, 300, 150)); + p1 = m2 * QPointF(0, 0); + p2 = m2 * QPointF(300, 0); + p3 = m2 * QPointF(0, 150); + p4 = m2 * QPointF(300, 150); + p5 = m2 * QVector3D(300, 150, 1); + QVERIFY(fuzzyCompare(p1.x(), -1.0)); + QVERIFY(fuzzyCompare(p1.y(), 1.0)); + QVERIFY(fuzzyCompare(p2.x(), 1.0)); + QVERIFY(fuzzyCompare(p2.y(), 1.0)); + QVERIFY(fuzzyCompare(p3.x(), -1.0)); + QVERIFY(fuzzyCompare(p3.y(), -1.0)); + QVERIFY(fuzzyCompare(p4.x(), 1.0)); + QVERIFY(fuzzyCompare(p4.y(), -1.0)); + QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0)); + QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0)); + QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0)); + + QMatrix4x4 m3; + m3.ortho(0, 300, 150, 0, -1, 1); + p1 = m3 * QPointF(0, 0); + p2 = m3 * QPointF(300, 0); + p3 = m3 * QPointF(0, 150); + p4 = m3 * QPointF(300, 150); + p5 = m3 * QVector3D(300, 150, 1); + QVERIFY(fuzzyCompare(p1.x(), -1.0)); + QVERIFY(fuzzyCompare(p1.y(), 1.0)); + QVERIFY(fuzzyCompare(p2.x(), 1.0)); + QVERIFY(fuzzyCompare(p2.y(), 1.0)); + QVERIFY(fuzzyCompare(p3.x(), -1.0)); + QVERIFY(fuzzyCompare(p3.y(), -1.0)); + QVERIFY(fuzzyCompare(p4.x(), 1.0)); + QVERIFY(fuzzyCompare(p4.y(), -1.0)); + QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0)); + QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0)); + QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0)); + + QMatrix4x4 m4; + m4.ortho(0, 300, 150, 0, -2, 3); + p1 = m4 * QPointF(0, 0); + p2 = m4 * QPointF(300, 0); + p3 = m4 * QPointF(0, 150); + p4 = m4 * QPointF(300, 150); + p5 = m4 * QVector3D(300, 150, 1); + QVERIFY(fuzzyCompare(p1.x(), -1.0)); + QVERIFY(fuzzyCompare(p1.y(), 1.0)); + QVERIFY(fuzzyCompare(p2.x(), 1.0)); + QVERIFY(fuzzyCompare(p2.y(), 1.0)); + QVERIFY(fuzzyCompare(p3.x(), -1.0)); + QVERIFY(fuzzyCompare(p3.y(), -1.0)); + QVERIFY(fuzzyCompare(p4.x(), 1.0)); + QVERIFY(fuzzyCompare(p4.y(), -1.0)); + QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0)); + QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0)); + QVERIFY(fuzzyCompare(p5.z(), (qreal)-0.6)); + + // An empty view volume should leave the matrix alone. + QMatrix4x4 m5; + m5.ortho(0, 0, 150, 0, -2, 3); + QVERIFY(m5.isIdentity()); + m5.ortho(0, 300, 150, 150, -2, 3); + QVERIFY(m5.isIdentity()); + m5.ortho(0, 300, 150, 0, 2, 2); + QVERIFY(m5.isIdentity()); +} + +// Test perspective frustum projections. +void tst_QMatrixNxN::frustum() +{ + QMatrix4x4 m1; + m1.frustum(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); + QVector3D p1 = m1 * QVector3D(-1.0f, -1.0f, 1.0f); + QVector3D p2 = m1 * QVector3D(1.0f, -1.0f, 1.0f); + QVector3D p3 = m1 * QVector3D(-1.0f, 1.0f, 1.0f); + QVector3D p4 = m1 * QVector3D(1.0f, 1.0f, 1.0f); + QVector3D p5 = m1 * QVector3D(0.0f, 0.0f, 2.0f); + QVERIFY(fuzzyCompare(p1.x(), -1.0f)); + QVERIFY(fuzzyCompare(p1.y(), -1.0f)); + QVERIFY(fuzzyCompare(p1.z(), -1.0f)); + QVERIFY(fuzzyCompare(p2.x(), 1.0f)); + QVERIFY(fuzzyCompare(p2.y(), -1.0f)); + QVERIFY(fuzzyCompare(p2.z(), -1.0f)); + QVERIFY(fuzzyCompare(p3.x(), -1.0f)); + QVERIFY(fuzzyCompare(p3.y(), 1.0f)); + QVERIFY(fuzzyCompare(p3.z(), -1.0f)); + QVERIFY(fuzzyCompare(p4.x(), 1.0f)); + QVERIFY(fuzzyCompare(p4.y(), 1.0f)); + QVERIFY(fuzzyCompare(p4.z(), -1.0f)); + QVERIFY(fuzzyCompare(p5.x(), 0.0f)); + QVERIFY(fuzzyCompare(p5.y(), 0.0f)); + QVERIFY(fuzzyCompare(p5.z(), -0.5f)); + + // An empty view volume should leave the matrix alone. + QMatrix4x4 m5; + m5.frustum(0, 0, 150, 0, -2, 3); + QVERIFY(m5.isIdentity()); + m5.frustum(0, 300, 150, 150, -2, 3); + QVERIFY(m5.isIdentity()); + m5.frustum(0, 300, 150, 0, 2, 2); + QVERIFY(m5.isIdentity()); +} + +// Test perspective field-of-view projections. +void tst_QMatrixNxN::perspective() +{ + QMatrix4x4 m1; + m1.perspective(45.0f, 1.0f, -1.0f, 1.0f); + QVector3D p1 = m1 * QVector3D(-1.0f, -1.0f, 1.0f); + QVector3D p2 = m1 * QVector3D(1.0f, -1.0f, 1.0f); + QVector3D p3 = m1 * QVector3D(-1.0f, 1.0f, 1.0f); + QVector3D p4 = m1 * QVector3D(1.0f, 1.0f, 1.0f); + QVector3D p5 = m1 * QVector3D(0.0f, 0.0f, 2.0f); + QVERIFY(fuzzyCompare(p1.x(), 2.41421)); + QVERIFY(fuzzyCompare(p1.y(), 2.41421)); + QVERIFY(fuzzyCompare(p1.z(), -1)); + QVERIFY(fuzzyCompare(p2.x(), -2.41421)); + QVERIFY(fuzzyCompare(p2.y(), 2.41421)); + QVERIFY(fuzzyCompare(p2.z(), -1.0f)); + QVERIFY(fuzzyCompare(p3.x(), 2.41421)); + QVERIFY(fuzzyCompare(p3.y(), -2.41421)); + QVERIFY(fuzzyCompare(p3.z(), -1.0f)); + QVERIFY(fuzzyCompare(p4.x(), -2.41421)); + QVERIFY(fuzzyCompare(p4.y(), -2.41421)); + QVERIFY(fuzzyCompare(p4.z(), -1.0f)); + QVERIFY(fuzzyCompare(p5.x(), 0.0f)); + QVERIFY(fuzzyCompare(p5.y(), 0.0f)); + QVERIFY(fuzzyCompare(p5.z(), -0.5f)); + + // An empty view volume should leave the matrix alone. + QMatrix4x4 m5; + m5.perspective(45.0f, 1.0f, 0.0f, 0.0f); + QVERIFY(m5.isIdentity()); + m5.perspective(45.0f, 0.0f, -1.0f, 1.0f); + QVERIFY(m5.isIdentity()); + m5.perspective(0.0f, 1.0f, -1.0f, 1.0f); + QVERIFY(m5.isIdentity()); +} + +// Test left-handed vs right-handed coordinate flipping. +void tst_QMatrixNxN::flipCoordinates() +{ + QMatrix4x4 m1; + m1.flipCoordinates(); + QVector3D p1 = m1 * QVector3D(2, 3, 4); + QVERIFY(p1 == QVector3D(2, -3, -4)); + + QMatrix4x4 m2; + m2.scale(2.0f, 3.0f, 1.0f); + m2.flipCoordinates(); + QVector3D p2 = m2 * QVector3D(2, 3, 4); + QVERIFY(p2 == QVector3D(4, -9, -4)); + + QMatrix4x4 m3; + m3.translate(2.0f, 3.0f, 1.0f); + m3.flipCoordinates(); + QVector3D p3 = m3 * QVector3D(2, 3, 4); + QVERIFY(p3 == QVector3D(4, 0, -3)); + + QMatrix4x4 m4; + m4.rotate(90.0f, 0.0f, 0.0f, 1.0f); + m4.flipCoordinates(); + QVector3D p4 = m4 * QVector3D(2, 3, 4); + QVERIFY(p4 == QVector3D(3, 2, -4)); +} + +// Test conversion of generic matrices to and from the non-generic types. +void tst_QMatrixNxN::convertGeneric() +{ + QMatrix4x3 m1(uniqueValues4x3); + + static qreal const unique4x4[16] = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QMatrix4x4 m4(m1); + QVERIFY(isSame(m4, unique4x4)); + + QMatrix4x4 m5 = qGenericMatrixToMatrix4x4(m1); + QVERIFY(isSame(m5, unique4x4)); + + static qreal const conv4x4[12] = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 10.0f, 11.0f, 12.0f + }; + QMatrix4x4 m9(uniqueValues4); + + QMatrix4x3 m10 = m9.toGenericMatrix<4, 3>(); + QVERIFY(isSame(m10, conv4x4)); + + QMatrix4x3 m11 = qGenericMatrixFromMatrix4x4<4, 3>(m9); + QVERIFY(isSame(m11, conv4x4)); +} + +// Copy of "flagBits" in qmatrix4x4.h. +enum { + Identity = 0x0000, // Identity matrix + Translation = 0x0001, // Contains a translation + Scale = 0x0002, // Contains a scale + Rotation2D = 0x0004, // Contains a rotation about the Z axis + Rotation = 0x0008, // Contains an arbitrary rotation + Perspective = 0x0010, // Last row is different from (0, 0, 0, 1) + General = 0x001f // General matrix, unknown contents +}; + +// Structure that allows direct access to "flagBits" for testing. +struct Matrix4x4 +{ + qreal m[4][4]; + int flagBits; +}; + +// Test the inferring of special matrix types. +void tst_QMatrixNxN::optimize_data() +{ + QTest::addColumn<void *>("mValues"); + QTest::addColumn<int>("flagBits"); + + QTest::newRow("null") + << (void *)nullValues4 << (int)General; + QTest::newRow("identity") + << (void *)identityValues4 << (int)Identity; + QTest::newRow("unique") + << (void *)uniqueValues4 << (int)General; + + static qreal scaleValues[16] = { + 2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 3.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 4.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("scale") + << (void *)scaleValues << (int)Scale; + + static qreal translateValues[16] = { + 1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 1.0f, 0.0f, 3.0f, + 0.0f, 0.0f, 1.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("translate") + << (void *)translateValues << (int)Translation; + + static qreal scaleTranslateValues[16] = { + 1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 2.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 4.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("scaleTranslate") + << (void *)scaleTranslateValues << (int)(Scale | Translation); + + static qreal rotateValues[16] = { + 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("rotate") + << (void *)rotateValues << (int)Rotation2D; + + // Left-handed system, not a simple rotation. + static qreal scaleRotateValues[16] = { + 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("scaleRotate") + << (void *)scaleRotateValues << (int)(Scale | Rotation2D); + + static qreal matrix2x2Values[16] = { + 1.0f, 2.0f, 0.0f, 0.0f, + 8.0f, 3.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 9.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("matrix2x2") + << (void *)matrix2x2Values << (int)(Scale | Rotation2D); + + static qreal matrix3x3Values[16] = { + 1.0f, 2.0f, 4.0f, 0.0f, + 8.0f, 3.0f, 5.0f, 0.0f, + 6.0f, 7.0f, 9.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("matrix3x3") + << (void *)matrix3x3Values << (int)(Scale | Rotation2D | Rotation); + + static qreal rotateTranslateValues[16] = { + 0.0f, 1.0f, 0.0f, 1.0f, + -1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 0.0f, 1.0f, 3.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("rotateTranslate") + << (void *)rotateTranslateValues << (int)(Translation | Rotation2D); + + // Left-handed system, not a simple rotation. + static qreal scaleRotateTranslateValues[16] = { + 0.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, 2.0f, + 0.0f, 0.0f, 1.0f, 3.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("scaleRotateTranslate") + << (void *)scaleRotateTranslateValues << (int)(Translation | Scale | Rotation2D); + + static qreal belowValues[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 4.0f, 0.0f, 0.0f, 1.0f + }; + QTest::newRow("below") + << (void *)belowValues << (int)General; +} +void tst_QMatrixNxN::optimize() +{ + QFETCH(void *, mValues); + QFETCH(int, flagBits); + + QMatrix4x4 m((const qreal *)mValues); + m.optimize(); + + QCOMPARE(reinterpret_cast<Matrix4x4 *>(&m)->flagBits, flagBits); +} + +void tst_QMatrixNxN::columnsAndRows() +{ + QMatrix4x4 m1(uniqueValues4); + + QVERIFY(m1.column(0) == QVector4D(1, 5, 9, 13)); + QVERIFY(m1.column(1) == QVector4D(2, 6, 10, 14)); + QVERIFY(m1.column(2) == QVector4D(3, 7, 11, 15)); + QVERIFY(m1.column(3) == QVector4D(4, 8, 12, 16)); + + QVERIFY(m1.row(0) == QVector4D(1, 2, 3, 4)); + QVERIFY(m1.row(1) == QVector4D(5, 6, 7, 8)); + QVERIFY(m1.row(2) == QVector4D(9, 10, 11, 12)); + QVERIFY(m1.row(3) == QVector4D(13, 14, 15, 16)); + + m1.setColumn(0, QVector4D(-1, -5, -9, -13)); + m1.setColumn(1, QVector4D(-2, -6, -10, -14)); + m1.setColumn(2, QVector4D(-3, -7, -11, -15)); + m1.setColumn(3, QVector4D(-4, -8, -12, -16)); + + QVERIFY(m1.column(0) == QVector4D(-1, -5, -9, -13)); + QVERIFY(m1.column(1) == QVector4D(-2, -6, -10, -14)); + QVERIFY(m1.column(2) == QVector4D(-3, -7, -11, -15)); + QVERIFY(m1.column(3) == QVector4D(-4, -8, -12, -16)); + + QVERIFY(m1.row(0) == QVector4D(-1, -2, -3, -4)); + QVERIFY(m1.row(1) == QVector4D(-5, -6, -7, -8)); + QVERIFY(m1.row(2) == QVector4D(-9, -10, -11, -12)); + QVERIFY(m1.row(3) == QVector4D(-13, -14, -15, -16)); + + m1.setRow(0, QVector4D(1, 5, 9, 13)); + m1.setRow(1, QVector4D(2, 6, 10, 14)); + m1.setRow(2, QVector4D(3, 7, 11, 15)); + m1.setRow(3, QVector4D(4, 8, 12, 16)); + + QVERIFY(m1.column(0) == QVector4D(1, 2, 3, 4)); + QVERIFY(m1.column(1) == QVector4D(5, 6, 7, 8)); + QVERIFY(m1.column(2) == QVector4D(9, 10, 11, 12)); + QVERIFY(m1.column(3) == QVector4D(13, 14, 15, 16)); + + QVERIFY(m1.row(0) == QVector4D(1, 5, 9, 13)); + QVERIFY(m1.row(1) == QVector4D(2, 6, 10, 14)); + QVERIFY(m1.row(2) == QVector4D(3, 7, 11, 15)); + QVERIFY(m1.row(3) == QVector4D(4, 8, 12, 16)); +} + +// Test converting QMatrix objects into QMatrix4x4 and then +// checking that transformations in the original perform the +// equivalent transformations in the new matrix. +void tst_QMatrixNxN::convertQMatrix() +{ + QMatrix m1; + m1.translate(-3.5, 2.0); + QPointF p1 = m1.map(QPointF(100.0, 150.0)); + QCOMPARE(p1.x(), 100.0 - 3.5); + QCOMPARE(p1.y(), 150.0 + 2.0); + + QMatrix4x4 m2(m1); + QPointF p2 = m2 * QPointF(100.0, 150.0); + QCOMPARE((double)p2.x(), 100.0 - 3.5); + QCOMPARE((double)p2.y(), 150.0 + 2.0); + QVERIFY(m1 == m2.toAffine()); + + QMatrix m3; + m3.scale(1.5, -2.0); + QPointF p3 = m3.map(QPointF(100.0, 150.0)); + QCOMPARE(p3.x(), 1.5 * 100.0); + QCOMPARE(p3.y(), -2.0 * 150.0); + + QMatrix4x4 m4(m3); + QPointF p4 = m4 * QPointF(100.0, 150.0); + QCOMPARE((double)p4.x(), 1.5 * 100.0); + QCOMPARE((double)p4.y(), -2.0 * 150.0); + QVERIFY(m3 == m4.toAffine()); + + QMatrix m5; + m5.rotate(45.0); + QPointF p5 = m5.map(QPointF(100.0, 150.0)); + + QMatrix4x4 m6(m5); + QPointF p6 = m6 * QPointF(100.0, 150.0); + QVERIFY(fuzzyCompare(p5.x(), p6.x())); + QVERIFY(fuzzyCompare(p5.y(), p6.y())); + + QMatrix m7 = m6.toAffine(); + QVERIFY(fuzzyCompare(m5.m11(), m7.m11())); + QVERIFY(fuzzyCompare(m5.m12(), m7.m12())); + QVERIFY(fuzzyCompare(m5.m21(), m7.m21())); + QVERIFY(fuzzyCompare(m5.m22(), m7.m22())); + QVERIFY(fuzzyCompare(m5.dx(), m7.dx())); + QVERIFY(fuzzyCompare(m5.dy(), m7.dy())); +} + +// Test converting QTransform objects into QMatrix4x4 and then +// checking that transformations in the original perform the +// equivalent transformations in the new matrix. +void tst_QMatrixNxN::convertQTransform() +{ + QTransform m1; + m1.translate(-3.5, 2.0); + QPointF p1 = m1.map(QPointF(100.0, 150.0)); + QCOMPARE(p1.x(), 100.0 - 3.5); + QCOMPARE(p1.y(), 150.0 + 2.0); + + QMatrix4x4 m2(m1); + QPointF p2 = m2 * QPointF(100.0, 150.0); + QCOMPARE((double)p2.x(), 100.0 - 3.5); + QCOMPARE((double)p2.y(), 150.0 + 2.0); + QVERIFY(m1 == m2.toTransform()); + + QTransform m3; + m3.scale(1.5, -2.0); + QPointF p3 = m3.map(QPointF(100.0, 150.0)); + QCOMPARE(p3.x(), 1.5 * 100.0); + QCOMPARE(p3.y(), -2.0 * 150.0); + + QMatrix4x4 m4(m3); + QPointF p4 = m4 * QPointF(100.0, 150.0); + QCOMPARE((double)p4.x(), 1.5 * 100.0); + QCOMPARE((double)p4.y(), -2.0 * 150.0); + QVERIFY(m3 == m4.toTransform()); + + QTransform m5; + m5.rotate(45.0); + QPointF p5 = m5.map(QPointF(100.0, 150.0)); + + QMatrix4x4 m6(m5); + QPointF p6 = m6 * QPointF(100.0, 150.0); + QVERIFY(fuzzyCompare(p5.x(), p6.x())); + QVERIFY(fuzzyCompare(p5.y(), p6.y())); + + QTransform m7 = m6.toTransform(); + QVERIFY(fuzzyCompare(m5.m11(), m7.m11())); + QVERIFY(fuzzyCompare(m5.m12(), m7.m12())); + QVERIFY(fuzzyCompare(m5.m21(), m7.m21())); + QVERIFY(fuzzyCompare(m5.m22(), m7.m22())); + QVERIFY(fuzzyCompare(m5.dx(), m7.dx())); + QVERIFY(fuzzyCompare(m5.dy(), m7.dy())); + QVERIFY(fuzzyCompare(m5.m13(), m7.m13())); + QVERIFY(fuzzyCompare(m5.m23(), m7.m23())); + QVERIFY(fuzzyCompare(m5.m33(), m7.m33())); +} + +// Test filling matrices with specific values. +void tst_QMatrixNxN::fill() +{ + QMatrix4x4 m1; + m1.fill(0.0f); + QVERIFY(isSame(m1, nullValues4)); + + static const qreal fillValues4[] = + {2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f}; + m1.fill(2.5f); + QVERIFY(isSame(m1, fillValues4)); + + QMatrix4x3 m2; + m2.fill(0.0f); + QVERIFY(isSame(m2, nullValues4x3)); + + static const qreal fillValues4x3[] = + {2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f, + 2.5f, 2.5f, 2.5f, 2.5f}; + m2.fill(2.5f); + QVERIFY(isSame(m2, fillValues4x3)); +} + +// Test the mapRect() function for QRect and QRectF. +void tst_QMatrixNxN::mapRect_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("width"); + QTest::addColumn<qreal>("height"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("rect") + << (qreal)1.0f << (qreal)-20.5f << (qreal)100.0f << (qreal)63.75f; +} +void tst_QMatrixNxN::mapRect() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, width); + QFETCH(qreal, height); + + QRectF rect(x, y, width, height); + QRect recti(qRound(x), qRound(y), qRound(width), qRound(height)); + + QMatrix4x4 m1; + QVERIFY(m1.mapRect(rect) == rect); + QVERIFY(m1.mapRect(recti) == recti); + + QMatrix4x4 m2; + m2.translate(-100.5f, 64.0f); + QRectF translated = rect.translated(-100.5f, 64.0f); + QRect translatedi = QRect(qRound(recti.x() - 100.5f), recti.y() + 64, + recti.width(), recti.height()); + QVERIFY(m2.mapRect(rect) == translated); + QVERIFY(m2.mapRect(recti) == translatedi); + + QMatrix4x4 m3; + m3.scale(-100.5f, 64.0f); + qreal scalex = x * -100.5f; + qreal scaley = y * 64.0f; + qreal scalewid = width * -100.5f; + qreal scaleht = height * 64.0f; + if (scalewid < 0.0f) { + scalewid = -scalewid; + scalex -= scalewid; + } + if (scaleht < 0.0f) { + scaleht = -scaleht; + scaley -= scaleht; + } + QRectF scaled(scalex, scaley, scalewid, scaleht); + QVERIFY(m3.mapRect(rect) == scaled); + scalex = recti.x() * -100.5f; + scaley = recti.y() * 64.0f; + scalewid = recti.width() * -100.5f; + scaleht = recti.height() * 64.0f; + if (scalewid < 0.0f) { + scalewid = -scalewid; + scalex -= scalewid; + } + if (scaleht < 0.0f) { + scaleht = -scaleht; + scaley -= scaleht; + } + QRect scaledi(qRound(scalex), qRound(scaley), + qRound(scalewid), qRound(scaleht)); + QVERIFY(m3.mapRect(recti) == scaledi); + + QMatrix4x4 m4; + m4.translate(-100.5f, 64.0f); + m4.scale(-2.5f, 4.0f); + qreal transx1 = x * -2.5f - 100.5f; + qreal transy1 = y * 4.0f + 64.0f; + qreal transx2 = (x + width) * -2.5f - 100.5f; + qreal transy2 = (y + height) * 4.0f + 64.0f; + if (transx1 > transx2) + qSwap(transx1, transx2); + if (transy1 > transy2) + qSwap(transy1, transy2); + QRectF trans(transx1, transy1, transx2 - transx1, transy2 - transy1); + QVERIFY(m4.mapRect(rect) == trans); + transx1 = recti.x() * -2.5f - 100.5f; + transy1 = recti.y() * 4.0f + 64.0f; + transx2 = (recti.x() + recti.width()) * -2.5f - 100.5f; + transy2 = (recti.y() + recti.height()) * 4.0f + 64.0f; + if (transx1 > transx2) + qSwap(transx1, transx2); + if (transy1 > transy2) + qSwap(transy1, transy2); + QRect transi(qRound(transx1), qRound(transy1), + qRound(transx2) - qRound(transx1), + qRound(transy2) - qRound(transy1)); + QVERIFY(m4.mapRect(recti) == transi); + + m4.rotate(45.0f, 0.0f, 0.0f, 1.0f); + + QTransform t4; + t4.translate(-100.5f, 64.0f); + t4.scale(-2.5f, 4.0f); + t4.rotate(45.0f); + QRectF mr = m4.mapRect(rect); + QRectF tr = t4.mapRect(rect); + QVERIFY(fuzzyCompare(mr.x(), tr.x())); + QVERIFY(fuzzyCompare(mr.y(), tr.y())); + QVERIFY(fuzzyCompare(mr.width(), tr.width())); + QVERIFY(fuzzyCompare(mr.height(), tr.height())); + + QRect mri = m4.mapRect(recti); + QRect tri = t4.mapRect(recti); + QVERIFY(mri == tri); +} + +void tst_QMatrixNxN::mapVector_data() +{ + QTest::addColumn<void *>("mValues"); + + QTest::newRow("null") + << (void *)nullValues4; + + QTest::newRow("identity") + << (void *)identityValues4; + + QTest::newRow("unique") + << (void *)uniqueValues4; + + static const qreal scale[] = + {2.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 11.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -6.5f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("scale") + << (void *)scale; + + static const qreal scaleTranslate[] = + {2.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 11.0f, 0.0f, 2.0f, + 0.0f, 0.0f, -6.5f, 3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("scaleTranslate") + << (void *)scaleTranslate; + + static const qreal translate[] = + {1.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 1.0f, 0.0f, 2.0f, + 0.0f, 0.0f, 1.0f, 3.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + QTest::newRow("translate") + << (void *)translate; +} +void tst_QMatrixNxN::mapVector() +{ + QFETCH(void *, mValues); + + QMatrix4x4 m1((const qreal *)mValues); + + QVector3D v(3.5f, -1.0f, 2.5f); + + QVector3D expected + (v.x() * m1(0, 0) + v.y() * m1(0, 1) + v.z() * m1(0, 2), + v.x() * m1(1, 0) + v.y() * m1(1, 1) + v.z() * m1(1, 2), + v.x() * m1(2, 0) + v.y() * m1(2, 1) + v.z() * m1(2, 2)); + + QVector3D actual = m1.mapVector(v); + m1.optimize(); + QVector3D actual2 = m1.mapVector(v); + + QVERIFY(fuzzyCompare(actual.x(), expected.x())); + QVERIFY(fuzzyCompare(actual.y(), expected.y())); + QVERIFY(fuzzyCompare(actual.z(), expected.z())); + QVERIFY(fuzzyCompare(actual2.x(), expected.x())); + QVERIFY(fuzzyCompare(actual2.y(), expected.y())); + QVERIFY(fuzzyCompare(actual2.z(), expected.z())); +} + +class tst_QMatrixNxN4x4Properties : public QObject +{ + Q_OBJECT + Q_PROPERTY(QMatrix4x4 matrix READ matrix WRITE setMatrix) +public: + tst_QMatrixNxN4x4Properties(QObject *parent = 0) : QObject(parent) {} + + QMatrix4x4 matrix() const { return m; } + void setMatrix(const QMatrix4x4& value) { m = value; } + +private: + QMatrix4x4 m; +}; + +// Test getting and setting matrix properties via the metaobject system. +void tst_QMatrixNxN::properties() +{ + tst_QMatrixNxN4x4Properties obj; + + QMatrix4x4 m1(uniqueValues4); + obj.setMatrix(m1); + + QMatrix4x4 m2 = qVariantValue<QMatrix4x4>(obj.property("matrix")); + QVERIFY(isSame(m2, uniqueValues4)); + + QMatrix4x4 m3(transposedValues4); + obj.setProperty("matrix", qVariantFromValue(m3)); + + m2 = qVariantValue<QMatrix4x4>(obj.property("matrix")); + QVERIFY(isSame(m2, transposedValues4)); +} + +void tst_QMatrixNxN::metaTypes() +{ + QVERIFY(QMetaType::type("QMatrix4x4") == QMetaType::QMatrix4x4); + + QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QMatrix4x4)), + QByteArray("QMatrix4x4")); + + QVERIFY(QMetaType::isRegistered(QMetaType::QMatrix4x4)); + + QVERIFY(qMetaTypeId<QMatrix4x4>() == QMetaType::QMatrix4x4); +} + +QTEST_APPLESS_MAIN(tst_QMatrixNxN) + +#include "tst_qmatrixnxn.moc" diff --git a/tests/auto/gui/math3d/qquaternion/qquaternion.pro b/tests/auto/gui/math3d/qquaternion/qquaternion.pro new file mode 100644 index 0000000000..6f740cfd42 --- /dev/null +++ b/tests/auto/gui/math3d/qquaternion/qquaternion.pro @@ -0,0 +1,2 @@ +load(qttest_p4) +SOURCES += tst_qquaternion.cpp diff --git a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp new file mode 100644 index 0000000000..7bc50efeeb --- /dev/null +++ b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp @@ -0,0 +1,888 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qmath.h> +#include <QtGui/qquaternion.h> + +class tst_QQuaternion : public QObject +{ + Q_OBJECT +public: + tst_QQuaternion() {} + ~tst_QQuaternion() {} + +private slots: + void create(); + + void length_data(); + void length(); + + void normalized_data(); + void normalized(); + + void normalize_data(); + void normalize(); + + void compare(); + + void add_data(); + void add(); + + void subtract_data(); + void subtract(); + + void multiply_data(); + void multiply(); + + void multiplyFactor_data(); + void multiplyFactor(); + + void divide_data(); + void divide(); + + void negate_data(); + void negate(); + + void conjugate_data(); + void conjugate(); + + void fromAxisAndAngle_data(); + void fromAxisAndAngle(); + + void slerp_data(); + void slerp(); + + void nlerp_data(); + void nlerp(); + + void properties(); + void metaTypes(); +}; + +// QVector3D uses float internally, which can lead to some precision +// issues when using it with the qreal-based QQuaternion. +static bool fuzzyCompare(qreal x, qreal y) +{ + return qFuzzyIsNull(float(x - y)); +} + +// Test the creation of QQuaternion objects in various ways: +// construct, copy, and modify. +void tst_QQuaternion::create() +{ + QQuaternion identity; + QCOMPARE(identity.x(), (qreal)0.0f); + QCOMPARE(identity.y(), (qreal)0.0f); + QCOMPARE(identity.z(), (qreal)0.0f); + QCOMPARE(identity.scalar(), (qreal)1.0f); + QVERIFY(identity.isIdentity()); + + QQuaternion v1(34.0f, 1.0f, 2.5f, -89.25f); + QCOMPARE(v1.x(), (qreal)1.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.scalar(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + QQuaternion v1i(34, 1, 2, -89); + QCOMPARE(v1i.x(), (qreal)1.0f); + QCOMPARE(v1i.y(), (qreal)2.0f); + QCOMPARE(v1i.z(), (qreal)-89.0f); + QCOMPARE(v1i.scalar(), (qreal)34.0f); + QVERIFY(!v1i.isNull()); + + QQuaternion v2(v1); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.5f); + QCOMPARE(v2.z(), (qreal)-89.25f); + QCOMPARE(v2.scalar(), (qreal)34.0f); + QVERIFY(!v2.isNull()); + + QQuaternion v4; + QCOMPARE(v4.x(), (qreal)0.0f); + QCOMPARE(v4.y(), (qreal)0.0f); + QCOMPARE(v4.z(), (qreal)0.0f); + QCOMPARE(v4.scalar(), (qreal)1.0f); + QVERIFY(v4.isIdentity()); + v4 = v1; + QCOMPARE(v4.x(), (qreal)1.0f); + QCOMPARE(v4.y(), (qreal)2.5f); + QCOMPARE(v4.z(), (qreal)-89.25f); + QCOMPARE(v4.scalar(), (qreal)34.0f); + QVERIFY(!v4.isNull()); + + QQuaternion v9(34, QVector3D(1.0f, 2.5f, -89.25f)); + QCOMPARE(v9.x(), (qreal)1.0f); + QCOMPARE(v9.y(), (qreal)2.5f); + QCOMPARE(v9.z(), (qreal)-89.25f); + QCOMPARE(v9.scalar(), (qreal)34.0f); + QVERIFY(!v9.isNull()); + + v1.setX(3.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.scalar(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setY(10.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.scalar(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setZ(15.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QCOMPARE(v1.scalar(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setScalar(6.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QCOMPARE(v1.scalar(), (qreal)6.0f); + QVERIFY(!v1.isNull()); + + v1.setVector(2.0f, 6.5f, -1.25f); + QCOMPARE(v1.x(), (qreal)2.0f); + QCOMPARE(v1.y(), (qreal)6.5f); + QCOMPARE(v1.z(), (qreal)-1.25f); + QCOMPARE(v1.scalar(), (qreal)6.0f); + QVERIFY(!v1.isNull()); + QVERIFY(v1.vector() == QVector3D(2.0f, 6.5f, -1.25f)); + + v1.setVector(QVector3D(-2.0f, -6.5f, 1.25f)); + QCOMPARE(v1.x(), (qreal)-2.0f); + QCOMPARE(v1.y(), (qreal)-6.5f); + QCOMPARE(v1.z(), (qreal)1.25f); + QCOMPARE(v1.scalar(), (qreal)6.0f); + QVERIFY(!v1.isNull()); + QVERIFY(v1.vector() == QVector3D(-2.0f, -6.5f, 1.25f)); + + v1.setX(0.0f); + v1.setY(0.0f); + v1.setZ(0.0f); + v1.setScalar(0.0f); + QCOMPARE(v1.x(), (qreal)0.0f); + QCOMPARE(v1.y(), (qreal)0.0f); + QCOMPARE(v1.z(), (qreal)0.0f); + QCOMPARE(v1.scalar(), (qreal)0.0f); + QVERIFY(v1.isNull()); + + QVector4D v10 = v9.toVector4D(); + QCOMPARE(v10.x(), (qreal)1.0f); + QCOMPARE(v10.y(), (qreal)2.5f); + QCOMPARE(v10.z(), (qreal)-89.25f); + QCOMPARE(v10.w(), (qreal)34.0f); +} + +// Test length computation for quaternions. +void tst_QQuaternion::length_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<qreal>("w"); + QTest::addColumn<qreal>("len"); + + QTest::newRow("null") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("1x") << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1y") << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1z") << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1w") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)1.0f; + QTest::newRow("-1x") << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1y") << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1z") << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1w") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)1.0f; + QTest::newRow("two") << (qreal)2.0f << (qreal)-2.0f << (qreal)2.0f << (qreal)2.0f << (qreal)qSqrt(16.0f); +} +void tst_QQuaternion::length() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + QFETCH(qreal, len); + + QQuaternion v(w, x, y, z); + QCOMPARE(v.length(), len); + QCOMPARE(v.lengthSquared(), x * x + y * y + z * z + w * w); +} + +// Test the unit vector conversion for quaternions. +void tst_QQuaternion::normalized_data() +{ + // Use the same test data as the length test. + length_data(); +} +void tst_QQuaternion::normalized() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + QFETCH(qreal, len); + + QQuaternion v(w, x, y, z); + QQuaternion u = v.normalized(); + if (v.isNull()) + QVERIFY(u.isNull()); + else + QCOMPARE(u.length(), qreal(1.0f)); + QCOMPARE(u.x() * len, v.x()); + QCOMPARE(u.y() * len, v.y()); + QCOMPARE(u.z() * len, v.z()); + QCOMPARE(u.scalar() * len, v.scalar()); +} + +// Test the unit vector conversion for quaternions. +void tst_QQuaternion::normalize_data() +{ + // Use the same test data as the length test. + length_data(); +} +void tst_QQuaternion::normalize() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + + QQuaternion v(w, x, y, z); + bool isNull = v.isNull(); + v.normalize(); + if (isNull) + QVERIFY(v.isNull()); + else + QCOMPARE(v.length(), qreal(1.0f)); +} + +// Test the comparison operators for quaternions. +void tst_QQuaternion::compare() +{ + QQuaternion v1(8, 1, 2, 4); + QQuaternion v2(8, 1, 2, 4); + QQuaternion v3(8, 3, 2, 4); + QQuaternion v4(8, 1, 3, 4); + QQuaternion v5(8, 1, 2, 3); + QQuaternion v6(3, 1, 2, 4); + + QVERIFY(v1 == v2); + QVERIFY(v1 != v3); + QVERIFY(v1 != v4); + QVERIFY(v1 != v5); + QVERIFY(v1 != v6); +} + +// Test addition for quaternions. +void tst_QQuaternion::add_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("w3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)8.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f << (qreal)9.0f + << (qreal)5.0f << (qreal)7.0f << (qreal)-3.0f << (qreal)17.0f; +} +void tst_QQuaternion::add() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w2, x2, y2, z2); + QQuaternion v3(w3, x3, y3, z3); + + QVERIFY((v1 + v2) == v3); + + QQuaternion v4(v1); + v4 += v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() + v2.x()); + QCOMPARE(v4.y(), v1.y() + v2.y()); + QCOMPARE(v4.z(), v1.z() + v2.z()); + QCOMPARE(v4.scalar(), v1.scalar() + v2.scalar()); +} + +// Test subtraction for quaternions. +void tst_QQuaternion::subtract_data() +{ + // Use the same test data as the add test. + add_data(); +} +void tst_QQuaternion::subtract() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w2, x2, y2, z2); + QQuaternion v3(w3, x3, y3, z3); + + QVERIFY((v3 - v1) == v2); + QVERIFY((v3 - v2) == v1); + + QQuaternion v4(v3); + v4 -= v1; + QVERIFY(v4 == v2); + + QCOMPARE(v4.x(), v3.x() - v1.x()); + QCOMPARE(v4.y(), v3.y() - v1.y()); + QCOMPARE(v4.z(), v3.z() - v1.z()); + QCOMPARE(v4.scalar(), v3.scalar() - v1.scalar()); + + QQuaternion v5(v3); + v5 -= v2; + QVERIFY(v5 == v1); + + QCOMPARE(v5.x(), v3.x() - v2.x()); + QCOMPARE(v5.y(), v3.y() - v2.y()); + QCOMPARE(v5.z(), v3.z() - v2.z()); + QCOMPARE(v5.scalar(), v3.scalar() - v2.scalar()); +} + +// Test quaternion multiplication. +void tst_QQuaternion::multiply_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("unitvec") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)7.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)6.0f << (qreal)8.0f; + + for (qreal w = -1.0f; w <= 1.0f; w += 0.5f) + for (qreal x = -1.0f; x <= 1.0f; x += 0.5f) + for (qreal y = -1.0f; y <= 1.0f; y += 0.5f) + for (qreal z = -1.0f; z <= 1.0f; z += 0.5f) { + QTest::newRow("exhaustive") + << x << y << z << w + << z << w << y << x; + } +} +void tst_QQuaternion::multiply() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QQuaternion q1(w1, x1, y1, z1); + QQuaternion q2(w2, x2, y2, z2); + + // Use the simple algorithm at: + // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q53 + // to calculate the answer we expect to get. + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + qreal scalar = w1 * w2 - QVector3D::dotProduct(v1, v2); + QVector3D vector = w1 * v2 + w2 * v1 + QVector3D::crossProduct(v1, v2); + QQuaternion result(scalar, vector); + + QVERIFY((q1 * q2) == result); +} + +// Test multiplication by a factor for quaternions. +void tst_QQuaternion::multiplyFactor_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)100.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)4.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)4.0f << (qreal)-6.0f << (qreal)8.0f; + + QTest::newRow("allzero") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)4.0f + << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; +} +void tst_QQuaternion::multiplyFactor() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w2, x2, y2, z2); + + QVERIFY((v1 * factor) == v2); + QVERIFY((factor * v1) == v2); + + QQuaternion v3(v1); + v3 *= factor; + QVERIFY(v3 == v2); + + QCOMPARE(v3.x(), v1.x() * factor); + QCOMPARE(v3.y(), v1.y() * factor); + QCOMPARE(v3.z(), v1.z() * factor); + QCOMPARE(v3.scalar(), v1.scalar() * factor); +} + +// Test division by a factor for quaternions. +void tst_QQuaternion::divide_data() +{ + // Use the same test data as the multiply test. + multiplyFactor_data(); +} +void tst_QQuaternion::divide() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w2, x2, y2, z2); + + if (factor == (qreal)0.0f) + return; + + QVERIFY((v2 / factor) == v1); + + QQuaternion v3(v2); + v3 /= factor; + QVERIFY(v3 == v1); + + QCOMPARE(v3.x(), v2.x() / factor); + QCOMPARE(v3.y(), v2.y() / factor); + QCOMPARE(v3.z(), v2.z() / factor); + QCOMPARE(v3.scalar(), v2.scalar() / factor); +} + +// Test negation for quaternions. +void tst_QQuaternion::negate_data() +{ + // Use the same test data as the add test. + add_data(); +} +void tst_QQuaternion::negate() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(-w1, -x1, -y1, -z1); + + QVERIFY(-v1 == v2); +} + +// Test quaternion conjugate calculations. +void tst_QQuaternion::conjugate_data() +{ + // Use the same test data as the add test. + add_data(); +} +void tst_QQuaternion::conjugate() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + + QQuaternion v1(w1, x1, y1, z1); + QQuaternion v2(w1, -x1, -y1, -z1); + + QVERIFY(v1.conjugate() == v2); +} + +// Test quaternion creation from an axis and an angle. +void tst_QQuaternion::fromAxisAndAngle_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("angle"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)90.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)180.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)270.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)45.0f; +} +void tst_QQuaternion::fromAxisAndAngle() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, angle); + + // Use a straight-forward implementation of the algorithm at: + // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56 + // to calculate the answer we expect to get. + QVector3D vector = QVector3D(x1, y1, z1).normalized(); + qreal sin_a = qSin((angle * M_PI / 180.0) / 2.0); + qreal cos_a = qCos((angle * M_PI / 180.0) / 2.0); + QQuaternion result((qreal)cos_a, + (qreal)(vector.x() * sin_a), + (qreal)(vector.y() * sin_a), + (qreal)(vector.z() * sin_a)); + result = result.normalized(); + + QQuaternion answer = QQuaternion::fromAxisAndAngle(QVector3D(x1, y1, z1), angle); + QVERIFY(fuzzyCompare(answer.x(), result.x())); + QVERIFY(fuzzyCompare(answer.y(), result.y())); + QVERIFY(fuzzyCompare(answer.z(), result.z())); + QVERIFY(fuzzyCompare(answer.scalar(), result.scalar())); + + answer = QQuaternion::fromAxisAndAngle(x1, y1, z1, angle); + QVERIFY(fuzzyCompare(answer.x(), result.x())); + QVERIFY(fuzzyCompare(answer.y(), result.y())); + QVERIFY(fuzzyCompare(answer.z(), result.z())); + QVERIFY(fuzzyCompare(answer.scalar(), result.scalar())); +} + +// Test spherical interpolation of quaternions. +void tst_QQuaternion::slerp_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("angle1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("angle2"); + QTest::addColumn<qreal>("t"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("angle3"); + + QTest::newRow("first") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)0.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f; + QTest::newRow("first2") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)-0.5f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f; + QTest::newRow("second") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)1.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f; + QTest::newRow("second2") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)1.5f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f; + QTest::newRow("middle") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)90.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)180.0f + << (qreal)0.5f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)135.0f; + QTest::newRow("wide angle") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)0.0f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)270.0f + << (qreal)0.5f + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)-45.0f; +} +void tst_QQuaternion::slerp() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, angle1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, angle2); + QFETCH(qreal, t); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, angle3); + + QQuaternion q1 = QQuaternion::fromAxisAndAngle(x1, y1, z1, angle1); + QQuaternion q2 = QQuaternion::fromAxisAndAngle(x2, y2, z2, angle2); + QQuaternion q3 = QQuaternion::fromAxisAndAngle(x3, y3, z3, angle3); + + QQuaternion result = QQuaternion::slerp(q1, q2, t); + + QVERIFY(fuzzyCompare(result.x(), q3.x())); + QVERIFY(fuzzyCompare(result.y(), q3.y())); + QVERIFY(fuzzyCompare(result.z(), q3.z())); + QVERIFY(fuzzyCompare(result.scalar(), q3.scalar())); +} + +// Test normalized linear interpolation of quaternions. +void tst_QQuaternion::nlerp_data() +{ + slerp_data(); +} +void tst_QQuaternion::nlerp() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, angle1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, angle2); + QFETCH(qreal, t); + + QQuaternion q1 = QQuaternion::fromAxisAndAngle(x1, y1, z1, angle1); + QQuaternion q2 = QQuaternion::fromAxisAndAngle(x2, y2, z2, angle2); + + QQuaternion result = QQuaternion::nlerp(q1, q2, t); + + qreal resultx, resulty, resultz, resultscalar; + if (t <= 0.0f) { + resultx = q1.x(); + resulty = q1.y(); + resultz = q1.z(); + resultscalar = q1.scalar(); + } else if (t >= 1.0f) { + resultx = q2.x(); + resulty = q2.y(); + resultz = q2.z(); + resultscalar = q2.scalar(); + } else if (qAbs(angle1 - angle2) <= 180.f) { + resultx = q1.x() * (1 - t) + q2.x() * t; + resulty = q1.y() * (1 - t) + q2.y() * t; + resultz = q1.z() * (1 - t) + q2.z() * t; + resultscalar = q1.scalar() * (1 - t) + q2.scalar() * t; + } else { + // Angle greater than 180 degrees: negate q2. + resultx = q1.x() * (1 - t) - q2.x() * t; + resulty = q1.y() * (1 - t) - q2.y() * t; + resultz = q1.z() * (1 - t) - q2.z() * t; + resultscalar = q1.scalar() * (1 - t) - q2.scalar() * t; + } + + QQuaternion q3 = QQuaternion(resultscalar, resultx, resulty, resultz).normalized(); + + QVERIFY(fuzzyCompare(result.x(), q3.x())); + QVERIFY(fuzzyCompare(result.y(), q3.y())); + QVERIFY(fuzzyCompare(result.z(), q3.z())); + QVERIFY(fuzzyCompare(result.scalar(), q3.scalar())); +} + +class tst_QQuaternionProperties : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQuaternion quaternion READ quaternion WRITE setQuaternion) +public: + tst_QQuaternionProperties(QObject *parent = 0) : QObject(parent) {} + + QQuaternion quaternion() const { return q; } + void setQuaternion(const QQuaternion& value) { q = value; } + +private: + QQuaternion q; +}; + +// Test getting and setting quaternion properties via the metaobject system. +void tst_QQuaternion::properties() +{ + tst_QQuaternionProperties obj; + + obj.setQuaternion(QQuaternion(6.0f, 7.0f, 8.0f, 9.0f)); + + QQuaternion q = qVariantValue<QQuaternion>(obj.property("quaternion")); + QCOMPARE(q.scalar(), (qreal)6.0f); + QCOMPARE(q.x(), (qreal)7.0f); + QCOMPARE(q.y(), (qreal)8.0f); + QCOMPARE(q.z(), (qreal)9.0f); + + obj.setProperty("quaternion", + qVariantFromValue(QQuaternion(-6.0f, -7.0f, -8.0f, -9.0f))); + + q = qVariantValue<QQuaternion>(obj.property("quaternion")); + QCOMPARE(q.scalar(), (qreal)-6.0f); + QCOMPARE(q.x(), (qreal)-7.0f); + QCOMPARE(q.y(), (qreal)-8.0f); + QCOMPARE(q.z(), (qreal)-9.0f); +} + +void tst_QQuaternion::metaTypes() +{ + QVERIFY(QMetaType::type("QQuaternion") == QMetaType::QQuaternion); + + QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QQuaternion)), + QByteArray("QQuaternion")); + + QVERIFY(QMetaType::isRegistered(QMetaType::QQuaternion)); + + QVERIFY(qMetaTypeId<QQuaternion>() == QMetaType::QQuaternion); +} + +QTEST_APPLESS_MAIN(tst_QQuaternion) + +#include "tst_qquaternion.moc" diff --git a/tests/auto/gui/math3d/qvectornd/qvectornd.pro b/tests/auto/gui/math3d/qvectornd/qvectornd.pro new file mode 100644 index 0000000000..6346199444 --- /dev/null +++ b/tests/auto/gui/math3d/qvectornd/qvectornd.pro @@ -0,0 +1,2 @@ +load(qttest_p4) +SOURCES += tst_qvectornd.cpp diff --git a/tests/auto/gui/math3d/qvectornd/tst_qvectornd.cpp b/tests/auto/gui/math3d/qvectornd/tst_qvectornd.cpp new file mode 100644 index 0000000000..37c1949dc2 --- /dev/null +++ b/tests/auto/gui/math3d/qvectornd/tst_qvectornd.cpp @@ -0,0 +1,2142 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qmath.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qvector4d.h> + +class tst_QVectorND : public QObject +{ + Q_OBJECT +public: + tst_QVectorND() {} + ~tst_QVectorND() {} + +private slots: + void create2(); + void create3(); + void create4(); + + void length2_data(); + void length2(); + void length3_data(); + void length3(); + void length4_data(); + void length4(); + + void normalized2_data(); + void normalized2(); + void normalized3_data(); + void normalized3(); + void normalized4_data(); + void normalized4(); + + void normalize2_data(); + void normalize2(); + void normalize3_data(); + void normalize3(); + void normalize4_data(); + void normalize4(); + + void compare2(); + void compare3(); + void compare4(); + + void add2_data(); + void add2(); + void add3_data(); + void add3(); + void add4_data(); + void add4(); + + void subtract2_data(); + void subtract2(); + void subtract3_data(); + void subtract3(); + void subtract4_data(); + void subtract4(); + + void multiply2_data(); + void multiply2(); + void multiply3_data(); + void multiply3(); + void multiply4_data(); + void multiply4(); + + void multiplyFactor2_data(); + void multiplyFactor2(); + void multiplyFactor3_data(); + void multiplyFactor3(); + void multiplyFactor4_data(); + void multiplyFactor4(); + + void divide2_data(); + void divide2(); + void divide3_data(); + void divide3(); + void divide4_data(); + void divide4(); + + void negate2_data(); + void negate2(); + void negate3_data(); + void negate3(); + void negate4_data(); + void negate4(); + + void crossProduct_data(); + void crossProduct(); + void normal_data(); + void normal(); + void distanceToPlane_data(); + void distanceToPlane(); + void distanceToLine_data(); + void distanceToLine(); + + void dotProduct2_data(); + void dotProduct2(); + void dotProduct3_data(); + void dotProduct3(); + void dotProduct4_data(); + void dotProduct4(); + + void properties(); + void metaTypes(); +}; + +// QVector2/3/4D use float internally, which can sometimes lead +// to precision issues when converting to and from qreal. +// This fuzzy compare is slightly "fuzzier" than the default +// qFuzzyCompare for qreal to compensate. +static bool fuzzyCompare(qreal x, qreal y) +{ + return qFuzzyIsNull((float)(x - y)); +} + +// Test the creation of QVector2D objects in various ways: +// construct, copy, and modify. +void tst_QVectorND::create2() +{ + QVector2D null; + QCOMPARE(null.x(), (qreal)0.0f); + QCOMPARE(null.y(), (qreal)0.0f); + QVERIFY(null.isNull()); + + QVector2D v1(1.0f, 2.5f); + QCOMPARE(v1.x(), (qreal)1.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QVERIFY(!v1.isNull()); + + QVector2D v1i(1, 2); + QCOMPARE(v1i.x(), (qreal)1.0f); + QCOMPARE(v1i.y(), (qreal)2.0f); + QVERIFY(!v1i.isNull()); + + QVector2D v2(v1); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.5f); + QVERIFY(!v2.isNull()); + + QVector2D v4; + QCOMPARE(v4.x(), (qreal)0.0f); + QCOMPARE(v4.y(), (qreal)0.0f); + QVERIFY(v4.isNull()); + v4 = v1; + QCOMPARE(v4.x(), (qreal)1.0f); + QCOMPARE(v4.y(), (qreal)2.5f); + QVERIFY(!v4.isNull()); + + QVector2D v5(QPoint(1, 2)); + QCOMPARE(v5.x(), (qreal)1.0f); + QCOMPARE(v5.y(), (qreal)2.0f); + QVERIFY(!v5.isNull()); + + QVector2D v6(QPointF(1, 2.5)); + QCOMPARE(v6.x(), (qreal)1.0f); + QCOMPARE(v6.y(), (qreal)2.5f); + QVERIFY(!v6.isNull()); + + QVector2D v7(QVector3D(1.0f, 2.5f, 54.25f)); + QCOMPARE(v7.x(), (qreal)1.0f); + QCOMPARE(v7.y(), (qreal)2.5f); + QVERIFY(!v6.isNull()); + + QVector2D v8(QVector4D(1.0f, 2.5f, 54.25f, 34.0f)); + QCOMPARE(v8.x(), (qreal)1.0f); + QCOMPARE(v8.y(), (qreal)2.5f); + QVERIFY(!v6.isNull()); + + v1.setX(3.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QVERIFY(!v1.isNull()); + + v1.setY(10.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QVERIFY(!v1.isNull()); + + v1.setX(0.0f); + v1.setY(0.0f); + QCOMPARE(v1.x(), (qreal)0.0f); + QCOMPARE(v1.y(), (qreal)0.0f); + QVERIFY(v1.isNull()); + + QPoint p1 = v8.toPoint(); + QCOMPARE(p1.x(), 1); + QCOMPARE(p1.y(), 3); + + QPointF p2 = v8.toPointF(); + QCOMPARE((qreal)p2.x(), (qreal)1.0f); + QCOMPARE((qreal)p2.y(), (qreal)2.5f); + + QVector3D v9 = v8.toVector3D(); + QCOMPARE(v9.x(), (qreal)1.0f); + QCOMPARE(v9.y(), (qreal)2.5f); + QCOMPARE(v9.z(), (qreal)0.0f); + + QVector4D v10 = v8.toVector4D(); + QCOMPARE(v10.x(), (qreal)1.0f); + QCOMPARE(v10.y(), (qreal)2.5f); + QCOMPARE(v10.z(), (qreal)0.0f); + QCOMPARE(v10.w(), (qreal)0.0f); +} + +// Test the creation of QVector3D objects in various ways: +// construct, copy, and modify. +void tst_QVectorND::create3() +{ + QVector3D null; + QCOMPARE(null.x(), (qreal)0.0f); + QCOMPARE(null.y(), (qreal)0.0f); + QCOMPARE(null.z(), (qreal)0.0f); + QVERIFY(null.isNull()); + + QVector3D v1(1.0f, 2.5f, -89.25f); + QCOMPARE(v1.x(), (qreal)1.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QVERIFY(!v1.isNull()); + + QVector3D v1i(1, 2, -89); + QCOMPARE(v1i.x(), (qreal)1.0f); + QCOMPARE(v1i.y(), (qreal)2.0f); + QCOMPARE(v1i.z(), (qreal)-89.0f); + QVERIFY(!v1i.isNull()); + + QVector3D v2(v1); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.5f); + QCOMPARE(v2.z(), (qreal)-89.25f); + QVERIFY(!v2.isNull()); + + QVector3D v3(1.0f, 2.5f, 0.0f); + QCOMPARE(v3.x(), (qreal)1.0f); + QCOMPARE(v3.y(), (qreal)2.5f); + QCOMPARE(v3.z(), (qreal)0.0f); + QVERIFY(!v3.isNull()); + + QVector3D v3i(1, 2, 0); + QCOMPARE(v3i.x(), (qreal)1.0f); + QCOMPARE(v3i.y(), (qreal)2.0f); + QCOMPARE(v3i.z(), (qreal)0.0f); + QVERIFY(!v3i.isNull()); + + QVector3D v4; + QCOMPARE(v4.x(), (qreal)0.0f); + QCOMPARE(v4.y(), (qreal)0.0f); + QCOMPARE(v4.z(), (qreal)0.0f); + QVERIFY(v4.isNull()); + v4 = v1; + QCOMPARE(v4.x(), (qreal)1.0f); + QCOMPARE(v4.y(), (qreal)2.5f); + QCOMPARE(v4.z(), (qreal)-89.25f); + QVERIFY(!v4.isNull()); + + QVector3D v5(QPoint(1, 2)); + QCOMPARE(v5.x(), (qreal)1.0f); + QCOMPARE(v5.y(), (qreal)2.0f); + QCOMPARE(v5.z(), (qreal)0.0f); + QVERIFY(!v5.isNull()); + + QVector3D v6(QPointF(1, 2.5)); + QCOMPARE(v6.x(), (qreal)1.0f); + QCOMPARE(v6.y(), (qreal)2.5f); + QCOMPARE(v6.z(), (qreal)0.0f); + QVERIFY(!v6.isNull()); + + QVector3D v7(QVector2D(1.0f, 2.5f)); + QCOMPARE(v7.x(), (qreal)1.0f); + QCOMPARE(v7.y(), (qreal)2.5f); + QCOMPARE(v7.z(), (qreal)0.0f); + QVERIFY(!v7.isNull()); + + QVector3D v8(QVector2D(1.0f, 2.5f), 54.25f); + QCOMPARE(v8.x(), (qreal)1.0f); + QCOMPARE(v8.y(), (qreal)2.5f); + QCOMPARE(v8.z(), (qreal)54.25f); + QVERIFY(!v8.isNull()); + + QVector3D v9(QVector4D(1.0f, 2.5f, 54.25f, 34.0f)); + QCOMPARE(v9.x(), (qreal)1.0f); + QCOMPARE(v9.y(), (qreal)2.5f); + QCOMPARE(v9.z(), (qreal)54.25f); + QVERIFY(!v9.isNull()); + + v1.setX(3.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QVERIFY(!v1.isNull()); + + v1.setY(10.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QVERIFY(!v1.isNull()); + + v1.setZ(15.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QVERIFY(!v1.isNull()); + + v1.setX(0.0f); + v1.setY(0.0f); + v1.setZ(0.0f); + QCOMPARE(v1.x(), (qreal)0.0f); + QCOMPARE(v1.y(), (qreal)0.0f); + QCOMPARE(v1.z(), (qreal)0.0f); + QVERIFY(v1.isNull()); + + QPoint p1 = v8.toPoint(); + QCOMPARE(p1.x(), 1); + QCOMPARE(p1.y(), 3); + + QPointF p2 = v8.toPointF(); + QCOMPARE((qreal)p2.x(), (qreal)1.0f); + QCOMPARE((qreal)p2.y(), (qreal)2.5f); + + QVector2D v10 = v8.toVector2D(); + QCOMPARE(v10.x(), (qreal)1.0f); + QCOMPARE(v10.y(), (qreal)2.5f); + + QVector4D v11 = v8.toVector4D(); + QCOMPARE(v11.x(), (qreal)1.0f); + QCOMPARE(v11.y(), (qreal)2.5f); + QCOMPARE(v11.z(), (qreal)54.25f); + QCOMPARE(v11.w(), (qreal)0.0f); +} + +// Test the creation of QVector4D objects in various ways: +// construct, copy, and modify. +void tst_QVectorND::create4() +{ + QVector4D null; + QCOMPARE(null.x(), (qreal)0.0f); + QCOMPARE(null.y(), (qreal)0.0f); + QCOMPARE(null.z(), (qreal)0.0f); + QCOMPARE(null.w(), (qreal)0.0f); + QVERIFY(null.isNull()); + + QVector4D v1(1.0f, 2.5f, -89.25f, 34.0f); + QCOMPARE(v1.x(), (qreal)1.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.w(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + QVector4D v1i(1, 2, -89, 34); + QCOMPARE(v1i.x(), (qreal)1.0f); + QCOMPARE(v1i.y(), (qreal)2.0f); + QCOMPARE(v1i.z(), (qreal)-89.0f); + QCOMPARE(v1i.w(), (qreal)34.0f); + QVERIFY(!v1i.isNull()); + + QVector4D v2(v1); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.5f); + QCOMPARE(v2.z(), (qreal)-89.25f); + QCOMPARE(v2.w(), (qreal)34.0f); + QVERIFY(!v2.isNull()); + + QVector4D v3(1.0f, 2.5f, 0.0f, 0.0f); + QCOMPARE(v3.x(), (qreal)1.0f); + QCOMPARE(v3.y(), (qreal)2.5f); + QCOMPARE(v3.z(), (qreal)0.0f); + QCOMPARE(v3.w(), (qreal)0.0f); + QVERIFY(!v3.isNull()); + + QVector4D v3i(1, 2, 0, 0); + QCOMPARE(v3i.x(), (qreal)1.0f); + QCOMPARE(v3i.y(), (qreal)2.0f); + QCOMPARE(v3i.z(), (qreal)0.0f); + QCOMPARE(v3i.w(), (qreal)0.0f); + QVERIFY(!v3i.isNull()); + + QVector4D v3b(1.0f, 2.5f, -89.25f, 0.0f); + QCOMPARE(v3b.x(), (qreal)1.0f); + QCOMPARE(v3b.y(), (qreal)2.5f); + QCOMPARE(v3b.z(), (qreal)-89.25f); + QCOMPARE(v3b.w(), (qreal)0.0f); + QVERIFY(!v3b.isNull()); + + QVector4D v3bi(1, 2, -89, 0); + QCOMPARE(v3bi.x(), (qreal)1.0f); + QCOMPARE(v3bi.y(), (qreal)2.0f); + QCOMPARE(v3bi.z(), (qreal)-89.0f); + QCOMPARE(v3bi.w(), (qreal)0.0f); + QVERIFY(!v3bi.isNull()); + + QVector4D v4; + QCOMPARE(v4.x(), (qreal)0.0f); + QCOMPARE(v4.y(), (qreal)0.0f); + QCOMPARE(v4.z(), (qreal)0.0f); + QCOMPARE(v4.w(), (qreal)0.0f); + QVERIFY(v4.isNull()); + v4 = v1; + QCOMPARE(v4.x(), (qreal)1.0f); + QCOMPARE(v4.y(), (qreal)2.5f); + QCOMPARE(v4.z(), (qreal)-89.25f); + QCOMPARE(v4.w(), (qreal)34.0f); + QVERIFY(!v4.isNull()); + + QVector4D v5(QPoint(1, 2)); + QCOMPARE(v5.x(), (qreal)1.0f); + QCOMPARE(v5.y(), (qreal)2.0f); + QCOMPARE(v5.z(), (qreal)0.0f); + QCOMPARE(v5.w(), (qreal)0.0f); + QVERIFY(!v5.isNull()); + + QVector4D v6(QPointF(1, 2.5)); + QCOMPARE(v6.x(), (qreal)1.0f); + QCOMPARE(v6.y(), (qreal)2.5f); + QCOMPARE(v6.z(), (qreal)0.0f); + QCOMPARE(v6.w(), (qreal)0.0f); + QVERIFY(!v6.isNull()); + + QVector4D v7(QVector2D(1.0f, 2.5f)); + QCOMPARE(v7.x(), (qreal)1.0f); + QCOMPARE(v7.y(), (qreal)2.5f); + QCOMPARE(v7.z(), (qreal)0.0f); + QCOMPARE(v7.w(), (qreal)0.0f); + QVERIFY(!v7.isNull()); + + QVector4D v8(QVector3D(1.0f, 2.5f, -89.25f)); + QCOMPARE(v8.x(), (qreal)1.0f); + QCOMPARE(v8.y(), (qreal)2.5f); + QCOMPARE(v8.z(), (qreal)-89.25f); + QCOMPARE(v8.w(), (qreal)0.0f); + QVERIFY(!v8.isNull()); + + QVector4D v9(QVector3D(1.0f, 2.5f, -89.25f), 34); + QCOMPARE(v9.x(), (qreal)1.0f); + QCOMPARE(v9.y(), (qreal)2.5f); + QCOMPARE(v9.z(), (qreal)-89.25f); + QCOMPARE(v9.w(), (qreal)34.0f); + QVERIFY(!v9.isNull()); + + QVector4D v10(QVector2D(1.0f, 2.5f), 23.5f, -8); + QCOMPARE(v10.x(), (qreal)1.0f); + QCOMPARE(v10.y(), (qreal)2.5f); + QCOMPARE(v10.z(), (qreal)23.5f); + QCOMPARE(v10.w(), (qreal)-8.0f); + QVERIFY(!v10.isNull()); + + v1.setX(3.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)2.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.w(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setY(10.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)-89.25f); + QCOMPARE(v1.w(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setZ(15.5f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QCOMPARE(v1.w(), (qreal)34.0f); + QVERIFY(!v1.isNull()); + + v1.setW(6.0f); + QCOMPARE(v1.x(), (qreal)3.0f); + QCOMPARE(v1.y(), (qreal)10.5f); + QCOMPARE(v1.z(), (qreal)15.5f); + QCOMPARE(v1.w(), (qreal)6.0f); + QVERIFY(!v1.isNull()); + + v1.setX(0.0f); + v1.setY(0.0f); + v1.setZ(0.0f); + v1.setW(0.0f); + QCOMPARE(v1.x(), (qreal)0.0f); + QCOMPARE(v1.y(), (qreal)0.0f); + QCOMPARE(v1.z(), (qreal)0.0f); + QCOMPARE(v1.w(), (qreal)0.0f); + QVERIFY(v1.isNull()); + + QPoint p1 = v8.toPoint(); + QCOMPARE(p1.x(), 1); + QCOMPARE(p1.y(), 3); + + QPointF p2 = v8.toPointF(); + QCOMPARE((qreal)p2.x(), (qreal)1.0f); + QCOMPARE((qreal)p2.y(), (qreal)2.5f); + + QVector2D v11 = v8.toVector2D(); + QCOMPARE(v11.x(), (qreal)1.0f); + QCOMPARE(v11.y(), (qreal)2.5f); + + QVector3D v12 = v8.toVector3D(); + QCOMPARE(v12.x(), (qreal)1.0f); + QCOMPARE(v12.y(), (qreal)2.5f); + QCOMPARE(v12.z(), (qreal)-89.25f); + + QVector2D v13 = v9.toVector2DAffine(); + QVERIFY(fuzzyCompare(v13.x(), (qreal)(1.0f / 34.0f))); + QVERIFY(fuzzyCompare(v13.y(), (qreal)(2.5f / 34.0f))); + + QVector4D zerow(1.0f, 2.0f, 3.0f, 0.0f); + v13 = zerow.toVector2DAffine(); + QVERIFY(v13.isNull()); + + QVector3D v14 = v9.toVector3DAffine(); + QVERIFY(fuzzyCompare(v14.x(), (qreal)(1.0f / 34.0f))); + QVERIFY(fuzzyCompare(v14.y(), (qreal)(2.5f / 34.0f))); + QVERIFY(fuzzyCompare(v14.z(), (qreal)(-89.25f / 34.0f))); + + v14 = zerow.toVector3DAffine(); + QVERIFY(v14.isNull()); +} + +// Test vector length computation for 2D vectors. +void tst_QVectorND::length2_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("len"); + + QTest::newRow("null") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("1x") << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1y") << (qreal)0.0f << (qreal)1.0f << (qreal)1.0f; + QTest::newRow("-1x") << (qreal)-1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1y") << (qreal)0.0f << (qreal)-1.0f << (qreal)1.0f; + QTest::newRow("two") << (qreal)2.0f << (qreal)-2.0f << (qreal)qSqrt(8.0f); +} +void tst_QVectorND::length2() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, len); + + QVector2D v(x, y); + QCOMPARE(v.length(), len); + QCOMPARE(v.lengthSquared(), x * x + y * y); +} + +// Test vector length computation for 3D vectors. +void tst_QVectorND::length3_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<qreal>("len"); + + QTest::newRow("null") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("1x") << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1y") << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1z") << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)1.0f; + QTest::newRow("-1x") << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1y") << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1z") << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)1.0f; + QTest::newRow("two") << (qreal)2.0f << (qreal)-2.0f << (qreal)2.0f << (qreal)qSqrt(12.0f); +} +void tst_QVectorND::length3() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, len); + + QVector3D v(x, y, z); + QCOMPARE(v.length(), len); + QCOMPARE(v.lengthSquared(), x * x + y * y + z * z); +} + +// Test vector length computation for 4D vectors. +void tst_QVectorND::length4_data() +{ + QTest::addColumn<qreal>("x"); + QTest::addColumn<qreal>("y"); + QTest::addColumn<qreal>("z"); + QTest::addColumn<qreal>("w"); + QTest::addColumn<qreal>("len"); + + QTest::newRow("null") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + QTest::newRow("1x") << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1y") << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1z") << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("1w") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)1.0f; + QTest::newRow("-1x") << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1y") << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1z") << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f << (qreal)1.0f; + QTest::newRow("-1w") << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f << (qreal)1.0f; + QTest::newRow("two") << (qreal)2.0f << (qreal)-2.0f << (qreal)2.0f << (qreal)2.0f << (qreal)qSqrt(16.0f); +} +void tst_QVectorND::length4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + QFETCH(qreal, len); + + QVector4D v(x, y, z, w); + QCOMPARE(v.length(), len); + QCOMPARE(v.lengthSquared(), x * x + y * y + z * z + w * w); +} + +// Test the unit vector conversion for 2D vectors. +void tst_QVectorND::normalized2_data() +{ + // Use the same test data as the length test. + length2_data(); +} +void tst_QVectorND::normalized2() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, len); + + QVector2D v(x, y); + QVector2D u = v.normalized(); + if (v.isNull()) + QVERIFY(u.isNull()); + else + QVERIFY(fuzzyCompare(u.length(), qreal(1.0f))); + QVERIFY(fuzzyCompare(u.x() * len, v.x())); + QVERIFY(fuzzyCompare(u.y() * len, v.y())); +} + +// Test the unit vector conversion for 3D vectors. +void tst_QVectorND::normalized3_data() +{ + // Use the same test data as the length test. + length3_data(); +} +void tst_QVectorND::normalized3() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, len); + + QVector3D v(x, y, z); + QVector3D u = v.normalized(); + if (v.isNull()) + QVERIFY(u.isNull()); + else + QVERIFY(fuzzyCompare(u.length(), qreal(1.0f))); + QVERIFY(fuzzyCompare(u.x() * len, v.x())); + QVERIFY(fuzzyCompare(u.y() * len, v.y())); + QVERIFY(fuzzyCompare(u.z() * len, v.z())); +} + +// Test the unit vector conversion for 4D vectors. +void tst_QVectorND::normalized4_data() +{ + // Use the same test data as the length test. + length4_data(); +} +void tst_QVectorND::normalized4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + QFETCH(qreal, len); + + QVector4D v(x, y, z, w); + QVector4D u = v.normalized(); + if (v.isNull()) + QVERIFY(u.isNull()); + else + QVERIFY(fuzzyCompare(u.length(), qreal(1.0f))); + QVERIFY(fuzzyCompare(u.x() * len, v.x())); + QVERIFY(fuzzyCompare(u.y() * len, v.y())); + QVERIFY(fuzzyCompare(u.z() * len, v.z())); + QVERIFY(fuzzyCompare(u.w() * len, v.w())); +} + +// Test the unit vector conversion for 2D vectors. +void tst_QVectorND::normalize2_data() +{ + // Use the same test data as the length test. + length2_data(); +} +void tst_QVectorND::normalize2() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + + QVector2D v(x, y); + bool isNull = v.isNull(); + v.normalize(); + if (isNull) + QVERIFY(v.isNull()); + else + QVERIFY(fuzzyCompare(v.length(), qreal(1.0f))); +} + +// Test the unit vector conversion for 3D vectors. +void tst_QVectorND::normalize3_data() +{ + // Use the same test data as the length test. + length3_data(); +} +void tst_QVectorND::normalize3() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + + QVector3D v(x, y, z); + bool isNull = v.isNull(); + v.normalize(); + if (isNull) + QVERIFY(v.isNull()); + else + QVERIFY(fuzzyCompare(v.length(), qreal(1.0f))); +} + +// Test the unit vector conversion for 4D vectors. +void tst_QVectorND::normalize4_data() +{ + // Use the same test data as the length test. + length4_data(); +} +void tst_QVectorND::normalize4() +{ + QFETCH(qreal, x); + QFETCH(qreal, y); + QFETCH(qreal, z); + QFETCH(qreal, w); + + QVector4D v(x, y, z, w); + bool isNull = v.isNull(); + v.normalize(); + if (isNull) + QVERIFY(v.isNull()); + else + QVERIFY(fuzzyCompare(v.length(), qreal(1.0f))); +} + +// Test the comparison operators for 2D vectors. +void tst_QVectorND::compare2() +{ + QVector2D v1(1, 2); + QVector2D v2(1, 2); + QVector2D v3(3, 2); + QVector2D v4(1, 3); + + QVERIFY(v1 == v2); + QVERIFY(v1 != v3); + QVERIFY(v1 != v4); +} + +// Test the comparison operators for 3D vectors. +void tst_QVectorND::compare3() +{ + QVector3D v1(1, 2, 4); + QVector3D v2(1, 2, 4); + QVector3D v3(3, 2, 4); + QVector3D v4(1, 3, 4); + QVector3D v5(1, 2, 3); + + QVERIFY(v1 == v2); + QVERIFY(v1 != v3); + QVERIFY(v1 != v4); + QVERIFY(v1 != v5); +} + +// Test the comparison operators for 4D vectors. +void tst_QVectorND::compare4() +{ + QVector4D v1(1, 2, 4, 8); + QVector4D v2(1, 2, 4, 8); + QVector4D v3(3, 2, 4, 8); + QVector4D v4(1, 3, 4, 8); + QVector4D v5(1, 2, 3, 8); + QVector4D v6(1, 2, 4, 3); + + QVERIFY(v1 == v2); + QVERIFY(v1 != v3); + QVERIFY(v1 != v4); + QVERIFY(v1 != v5); + QVERIFY(v1 != v6); +} + +// Test vector addition for 2D vectors. +void tst_QVectorND::add2_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f + << (qreal)3.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)3.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f + << (qreal)4.0f << (qreal)5.0f + << (qreal)5.0f << (qreal)7.0f; +} +void tst_QVectorND::add2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + QVector2D v3(x3, y3); + + QVERIFY((v1 + v2) == v3); + + QVector2D v4(v1); + v4 += v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() + v2.x()); + QCOMPARE(v4.y(), v1.y() + v2.y()); +} + +// Test vector addition for 3D vectors. +void tst_QVectorND::add3_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f + << (qreal)5.0f << (qreal)7.0f << (qreal)-3.0f; +} +void tst_QVectorND::add3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVERIFY((v1 + v2) == v3); + + QVector3D v4(v1); + v4 += v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() + v2.x()); + QCOMPARE(v4.y(), v1.y() + v2.y()); + QCOMPARE(v4.z(), v1.z() + v2.z()); +} + +// Test vector addition for 4D vectors. +void tst_QVectorND::add4_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("w3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)3.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)8.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f << (qreal)9.0f + << (qreal)5.0f << (qreal)7.0f << (qreal)-3.0f << (qreal)17.0f; +} +void tst_QVectorND::add4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + QVector4D v3(x3, y3, z3, w3); + + QVERIFY((v1 + v2) == v3); + + QVector4D v4(v1); + v4 += v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() + v2.x()); + QCOMPARE(v4.y(), v1.y() + v2.y()); + QCOMPARE(v4.z(), v1.z() + v2.z()); + QCOMPARE(v4.w(), v1.w() + v2.w()); +} + +// Test vector subtraction for 2D vectors. +void tst_QVectorND::subtract2_data() +{ + // Use the same test data as the add test. + add2_data(); +} +void tst_QVectorND::subtract2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + QVector2D v3(x3, y3); + + QVERIFY((v3 - v1) == v2); + QVERIFY((v3 - v2) == v1); + + QVector2D v4(v3); + v4 -= v1; + QVERIFY(v4 == v2); + + QCOMPARE(v4.x(), v3.x() - v1.x()); + QCOMPARE(v4.y(), v3.y() - v1.y()); + + QVector2D v5(v3); + v5 -= v2; + QVERIFY(v5 == v1); + + QCOMPARE(v5.x(), v3.x() - v2.x()); + QCOMPARE(v5.y(), v3.y() - v2.y()); +} + +// Test vector subtraction for 3D vectors. +void tst_QVectorND::subtract3_data() +{ + // Use the same test data as the add test. + add3_data(); +} +void tst_QVectorND::subtract3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVERIFY((v3 - v1) == v2); + QVERIFY((v3 - v2) == v1); + + QVector3D v4(v3); + v4 -= v1; + QVERIFY(v4 == v2); + + QCOMPARE(v4.x(), v3.x() - v1.x()); + QCOMPARE(v4.y(), v3.y() - v1.y()); + QCOMPARE(v4.z(), v3.z() - v1.z()); + + QVector3D v5(v3); + v5 -= v2; + QVERIFY(v5 == v1); + + QCOMPARE(v5.x(), v3.x() - v2.x()); + QCOMPARE(v5.y(), v3.y() - v2.y()); + QCOMPARE(v5.z(), v3.z() - v2.z()); +} + +// Test vector subtraction for 4D vectors. +void tst_QVectorND::subtract4_data() +{ + // Use the same test data as the add test. + add4_data(); +} +void tst_QVectorND::subtract4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + QVector4D v3(x3, y3, z3, w3); + + QVERIFY((v3 - v1) == v2); + QVERIFY((v3 - v2) == v1); + + QVector4D v4(v3); + v4 -= v1; + QVERIFY(v4 == v2); + + QCOMPARE(v4.x(), v3.x() - v1.x()); + QCOMPARE(v4.y(), v3.y() - v1.y()); + QCOMPARE(v4.z(), v3.z() - v1.z()); + QCOMPARE(v4.w(), v3.w() - v1.w()); + + QVector4D v5(v3); + v5 -= v2; + QVERIFY(v5 == v1); + + QCOMPARE(v5.x(), v3.x() - v2.x()); + QCOMPARE(v5.y(), v3.y() - v2.y()); + QCOMPARE(v5.z(), v3.z() - v2.z()); + QCOMPARE(v5.w(), v3.w() - v2.w()); +} + +// Test component-wise vector multiplication for 2D vectors. +void tst_QVectorND::multiply2_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f + << (qreal)4.0f << (qreal)5.0f + << (qreal)4.0f << (qreal)10.0f; +} +void tst_QVectorND::multiply2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + QVector2D v3(x3, y3); + + QVERIFY((v1 * v2) == v3); + + QVector2D v4(v1); + v4 *= v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() * v2.x()); + QCOMPARE(v4.y(), v1.y() * v2.y()); +} + +// Test component-wise vector multiplication for 3D vectors. +void tst_QVectorND::multiply3_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f + << (qreal)4.0f << (qreal)10.0f << (qreal)-18.0f; +} +void tst_QVectorND::multiply3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVERIFY((v1 * v2) == v3); + + QVector3D v4(v1); + v4 *= v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() * v2.x()); + QCOMPARE(v4.y(), v1.y() * v2.y()); + QCOMPARE(v4.z(), v1.z() * v2.z()); +} + +// Test component-wise vector multiplication for 4D vectors. +void tst_QVectorND::multiply4_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("w3"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)8.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)-6.0f << (qreal)9.0f + << (qreal)4.0f << (qreal)10.0f << (qreal)-18.0f << (qreal)72.0f; +} +void tst_QVectorND::multiply4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, w3); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + QVector4D v3(x3, y3, z3, w3); + + QVERIFY((v1 * v2) == v3); + + QVector4D v4(v1); + v4 *= v2; + QVERIFY(v4 == v3); + + QCOMPARE(v4.x(), v1.x() * v2.x()); + QCOMPARE(v4.y(), v1.y() * v2.y()); + QCOMPARE(v4.z(), v1.z() * v2.z()); + QCOMPARE(v4.w(), v1.w() * v2.w()); +} + +// Test vector multiplication by a factor for 2D vectors. +void tst_QVectorND::multiplyFactor2_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f + << (qreal)100.0f + << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)4.0f; + + QTest::newRow("allzero") + << (qreal)1.0f << (qreal)2.0f + << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f; +} +void tst_QVectorND::multiplyFactor2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + + QVERIFY((v1 * factor) == v2); + QVERIFY((factor * v1) == v2); + + QVector2D v3(v1); + v3 *= factor; + QVERIFY(v3 == v2); + + QCOMPARE(v3.x(), v1.x() * factor); + QCOMPARE(v3.y(), v1.y() * factor); +} + +// Test vector multiplication by a factor for 3D vectors. +void tst_QVectorND::multiplyFactor3_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)100.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)4.0f << (qreal)-6.0f; + + QTest::newRow("allzero") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f + << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; +} +void tst_QVectorND::multiplyFactor3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + + QVERIFY((v1 * factor) == v2); + QVERIFY((factor * v1) == v2); + + QVector3D v3(v1); + v3 *= factor; + QVERIFY(v3 == v2); + + QCOMPARE(v3.x(), v1.x() * factor); + QCOMPARE(v3.y(), v1.y() * factor); + QCOMPARE(v3.z(), v1.z() * factor); +} + +// Test vector multiplication by a factor for 4D vectors. +void tst_QVectorND::multiplyFactor4_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("factor"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)100.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("xonly") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("yonly") + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f << (qreal)0.0f; + + QTest::newRow("zonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f; + + QTest::newRow("wonly") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)2.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f; + + QTest::newRow("all") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)4.0f + << (qreal)2.0f + << (qreal)2.0f << (qreal)4.0f << (qreal)-6.0f << (qreal)8.0f; + + QTest::newRow("allzero") + << (qreal)1.0f << (qreal)2.0f << (qreal)-3.0f << (qreal)4.0f + << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f; +} +void tst_QVectorND::multiplyFactor4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + + QVERIFY((v1 * factor) == v2); + QVERIFY((factor * v1) == v2); + + QVector4D v3(v1); + v3 *= factor; + QVERIFY(v3 == v2); + + QCOMPARE(v3.x(), v1.x() * factor); + QCOMPARE(v3.y(), v1.y() * factor); + QCOMPARE(v3.z(), v1.z() * factor); + QCOMPARE(v3.w(), v1.w() * factor); +} + +// Test vector division by a factor for 2D vectors. +void tst_QVectorND::divide2_data() +{ + // Use the same test data as the multiply test. + multiplyFactor2_data(); +} +void tst_QVectorND::divide2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + + if (factor == (qreal)0.0f) + return; + + QVERIFY((v2 / factor) == v1); + + QVector2D v3(v2); + v3 /= factor; + QVERIFY(v3 == v1); + + QCOMPARE(v3.x(), v2.x() / factor); + QCOMPARE(v3.y(), v2.y() / factor); +} + +// Test vector division by a factor for 3D vectors. +void tst_QVectorND::divide3_data() +{ + // Use the same test data as the multiply test. + multiplyFactor3_data(); +} +void tst_QVectorND::divide3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + + if (factor == (qreal)0.0f) + return; + + QVERIFY((v2 / factor) == v1); + + QVector3D v3(v2); + v3 /= factor; + QVERIFY(v3 == v1); + + QCOMPARE(v3.x(), v2.x() / factor); + QCOMPARE(v3.y(), v2.y() / factor); + QCOMPARE(v3.z(), v2.z() / factor); +} + +// Test vector division by a factor for 4D vectors. +void tst_QVectorND::divide4_data() +{ + // Use the same test data as the multiply test. + multiplyFactor4_data(); +} +void tst_QVectorND::divide4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, factor); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + + if (factor == (qreal)0.0f) + return; + + QVERIFY((v2 / factor) == v1); + + QVector4D v3(v2); + v3 /= factor; + QVERIFY(v3 == v1); + + QCOMPARE(v3.x(), v2.x() / factor); + QCOMPARE(v3.y(), v2.y() / factor); + QCOMPARE(v3.z(), v2.z() / factor); + QCOMPARE(v3.w(), v2.w() / factor); +} + +// Test vector negation for 2D vectors. +void tst_QVectorND::negate2_data() +{ + // Use the same test data as the add test. + add2_data(); +} +void tst_QVectorND::negate2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + + QVector2D v1(x1, y1); + QVector2D v2(-x1, -y1); + + QVERIFY(-v1 == v2); +} + +// Test vector negation for 3D vectors. +void tst_QVectorND::negate3_data() +{ + // Use the same test data as the add test. + add3_data(); +} +void tst_QVectorND::negate3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + + QVector3D v1(x1, y1, z1); + QVector3D v2(-x1, -y1, -z1); + + QVERIFY(-v1 == v2); +} + +// Test vector negation for 4D vectors. +void tst_QVectorND::negate4_data() +{ + // Use the same test data as the add test. + add4_data(); +} +void tst_QVectorND::negate4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(-x1, -y1, -z1, -w1); + + QVERIFY(-v1 == v2); +} + +// Test the computation of vector cross-products. +void tst_QVectorND::crossProduct_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("dot"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("unitvec") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)6.0f + << (qreal)-3.0f << (qreal)6.0f << (qreal)-3.0f + << (qreal)32.0f; +} +void tst_QVectorND::crossProduct() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVector3D v4 = QVector3D::crossProduct(v1, v2); + QVERIFY(v4 == v3); + + // Compute the cross-product long-hand and check again. + qreal xres = y1 * z2 - z1 * y2; + qreal yres = z1 * x2 - x1 * z2; + qreal zres = x1 * y2 - y1 * x2; + + QCOMPARE(v4.x(), xres); + QCOMPARE(v4.y(), yres); + QCOMPARE(v4.z(), zres); +} + +// Test the computation of normals. +void tst_QVectorND::normal_data() +{ + // Use the same test data as the crossProduct test. + crossProduct_data(); +} +void tst_QVectorND::normal() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QVERIFY(QVector3D::normal(v1, v2) == v3.normalized()); + QVERIFY(QVector3D::normal(QVector3D(), v1, v2) == v3.normalized()); + + QVector3D point(1.0f, 2.0f, 3.0f); + QVERIFY(QVector3D::normal(point, v1 + point, v2 + point) == v3.normalized()); +} + +// Test distance to plane calculations. +void tst_QVectorND::distanceToPlane_data() +{ + QTest::addColumn<qreal>("x1"); // Point on plane + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); // Normal to plane + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); // Point to test for distance + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("x4"); // Second point on plane + QTest::addColumn<qreal>("y4"); + QTest::addColumn<qreal>("z4"); + QTest::addColumn<qreal>("x5"); // Third point on plane + QTest::addColumn<qreal>("y5"); + QTest::addColumn<qreal>("z5"); + QTest::addColumn<qreal>("distance"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("above") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)2.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)2.0f; + + QTest::newRow("below") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)-1.0f << (qreal)1.0f << (qreal)-2.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)2.0f << (qreal)0.0f + << (qreal)-2.0f; +} +void tst_QVectorND::distanceToPlane() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, x4); + QFETCH(qreal, y4); + QFETCH(qreal, z4); + QFETCH(qreal, x5); + QFETCH(qreal, y5); + QFETCH(qreal, z5); + QFETCH(qreal, distance); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + QVector3D v4(x4, y4, z4); + QVector3D v5(x5, y5, z5); + + QCOMPARE(v3.distanceToPlane(v1, v2), distance); + QCOMPARE(v3.distanceToPlane(v1, v4, v5), distance); +} + +// Test distance to line calculations. +void tst_QVectorND::distanceToLine_data() +{ + QTest::addColumn<qreal>("x1"); // Point on line + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("x2"); // Direction of the line + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("x3"); // Point to test for distance + QTest::addColumn<qreal>("y3"); + QTest::addColumn<qreal>("z3"); + QTest::addColumn<qreal>("distance"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("on line") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)5.0f + << (qreal)0.0f; + + QTest::newRow("off line") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)1.0f; + + QTest::newRow("off line 2") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f << (qreal)-2.0f << (qreal)0.0f + << (qreal)2.0f; + + QTest::newRow("points") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)5.0f << (qreal)0.0f + << (qreal)5.0f; +} +void tst_QVectorND::distanceToLine() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, distance); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + QVector3D v3(x3, y3, z3); + + QCOMPARE(v3.distanceToLine(v1, v2), distance); +} + +// Test the computation of dot products for 2D vectors. +void tst_QVectorND::dotProduct2_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("dot"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("unitvec") + << (qreal)1.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)1.0f + << (qreal)0.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f + << (qreal)4.0f << (qreal)5.0f + << (qreal)14.0f; +} +void tst_QVectorND::dotProduct2() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, dot); + + QVector2D v1(x1, y1); + QVector2D v2(x2, y2); + + QVERIFY(QVector2D::dotProduct(v1, v2) == dot); + + // Compute the dot-product long-hand and check again. + qreal d = x1 * x2 + y1 * y2; + + QCOMPARE(QVector2D::dotProduct(v1, v2), d); +} + +// Test the computation of dot products for 3D vectors. +void tst_QVectorND::dotProduct3_data() +{ + // Use the same test data as the crossProduct test. + crossProduct_data(); +} +void tst_QVectorND::dotProduct3() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, x3); + QFETCH(qreal, y3); + QFETCH(qreal, z3); + QFETCH(qreal, dot); + + Q_UNUSED(x3); + Q_UNUSED(y3); + Q_UNUSED(z3); + + QVector3D v1(x1, y1, z1); + QVector3D v2(x2, y2, z2); + + QVERIFY(QVector3D::dotProduct(v1, v2) == dot); + + // Compute the dot-product long-hand and check again. + qreal d = x1 * x2 + y1 * y2 + z1 * z2; + + QCOMPARE(QVector3D::dotProduct(v1, v2), d); +} + +// Test the computation of dot products for 4D vectors. +void tst_QVectorND::dotProduct4_data() +{ + QTest::addColumn<qreal>("x1"); + QTest::addColumn<qreal>("y1"); + QTest::addColumn<qreal>("z1"); + QTest::addColumn<qreal>("w1"); + QTest::addColumn<qreal>("x2"); + QTest::addColumn<qreal>("y2"); + QTest::addColumn<qreal>("z2"); + QTest::addColumn<qreal>("w2"); + QTest::addColumn<qreal>("dot"); + + QTest::newRow("null") + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("unitvec") + << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f + << (qreal)0.0f; + + QTest::newRow("complex") + << (qreal)1.0f << (qreal)2.0f << (qreal)3.0f << (qreal)4.0f + << (qreal)4.0f << (qreal)5.0f << (qreal)6.0f << (qreal)7.0f + << (qreal)60.0f; +} +void tst_QVectorND::dotProduct4() +{ + QFETCH(qreal, x1); + QFETCH(qreal, y1); + QFETCH(qreal, z1); + QFETCH(qreal, w1); + QFETCH(qreal, x2); + QFETCH(qreal, y2); + QFETCH(qreal, z2); + QFETCH(qreal, w2); + QFETCH(qreal, dot); + + QVector4D v1(x1, y1, z1, w1); + QVector4D v2(x2, y2, z2, w2); + + QVERIFY(QVector4D::dotProduct(v1, v2) == dot); + + // Compute the dot-product long-hand and check again. + qreal d = x1 * x2 + y1 * y2 + z1 * z2 + w1 * w2; + + QCOMPARE(QVector4D::dotProduct(v1, v2), d); +} + +class tst_QVectorNDProperties : public QObject +{ + Q_OBJECT + Q_PROPERTY(QVector2D vector2D READ vector2D WRITE setVector2D) + Q_PROPERTY(QVector3D vector3D READ vector3D WRITE setVector3D) + Q_PROPERTY(QVector4D vector4D READ vector4D WRITE setVector4D) +public: + tst_QVectorNDProperties(QObject *parent = 0) : QObject(parent) {} + + QVector2D vector2D() const { return v2; } + void setVector2D(const QVector2D& value) { v2 = value; } + + QVector3D vector3D() const { return v3; } + void setVector3D(const QVector3D& value) { v3 = value; } + + QVector4D vector4D() const { return v4; } + void setVector4D(const QVector4D& value) { v4 = value; } + +private: + QVector2D v2; + QVector3D v3; + QVector4D v4; +}; + +// Test getting and setting vector properties via the metaobject system. +void tst_QVectorND::properties() +{ + tst_QVectorNDProperties obj; + + obj.setVector2D(QVector2D(1.0f, 2.0f)); + obj.setVector3D(QVector3D(3.0f, 4.0f, 5.0f)); + obj.setVector4D(QVector4D(6.0f, 7.0f, 8.0f, 9.0f)); + + QVector2D v2 = qVariantValue<QVector2D>(obj.property("vector2D")); + QCOMPARE(v2.x(), (qreal)1.0f); + QCOMPARE(v2.y(), (qreal)2.0f); + + QVector3D v3 = qVariantValue<QVector3D>(obj.property("vector3D")); + QCOMPARE(v3.x(), (qreal)3.0f); + QCOMPARE(v3.y(), (qreal)4.0f); + QCOMPARE(v3.z(), (qreal)5.0f); + + QVector4D v4 = qVariantValue<QVector4D>(obj.property("vector4D")); + QCOMPARE(v4.x(), (qreal)6.0f); + QCOMPARE(v4.y(), (qreal)7.0f); + QCOMPARE(v4.z(), (qreal)8.0f); + QCOMPARE(v4.w(), (qreal)9.0f); + + obj.setProperty("vector2D", + qVariantFromValue(QVector2D(-1.0f, -2.0f))); + obj.setProperty("vector3D", + qVariantFromValue(QVector3D(-3.0f, -4.0f, -5.0f))); + obj.setProperty("vector4D", + qVariantFromValue(QVector4D(-6.0f, -7.0f, -8.0f, -9.0f))); + + v2 = qVariantValue<QVector2D>(obj.property("vector2D")); + QCOMPARE(v2.x(), (qreal)-1.0f); + QCOMPARE(v2.y(), (qreal)-2.0f); + + v3 = qVariantValue<QVector3D>(obj.property("vector3D")); + QCOMPARE(v3.x(), (qreal)-3.0f); + QCOMPARE(v3.y(), (qreal)-4.0f); + QCOMPARE(v3.z(), (qreal)-5.0f); + + v4 = qVariantValue<QVector4D>(obj.property("vector4D")); + QCOMPARE(v4.x(), (qreal)-6.0f); + QCOMPARE(v4.y(), (qreal)-7.0f); + QCOMPARE(v4.z(), (qreal)-8.0f); + QCOMPARE(v4.w(), (qreal)-9.0f); +} + +void tst_QVectorND::metaTypes() +{ + QVERIFY(QMetaType::type("QVector2D") == QMetaType::QVector2D); + QVERIFY(QMetaType::type("QVector3D") == QMetaType::QVector3D); + QVERIFY(QMetaType::type("QVector4D") == QMetaType::QVector4D); + + QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QVector2D)), + QByteArray("QVector2D")); + QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QVector3D)), + QByteArray("QVector3D")); + QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QVector4D)), + QByteArray("QVector4D")); + + QVERIFY(QMetaType::isRegistered(QMetaType::QVector2D)); + QVERIFY(QMetaType::isRegistered(QMetaType::QVector3D)); + QVERIFY(QMetaType::isRegistered(QMetaType::QVector4D)); + + QVERIFY(qMetaTypeId<QVector2D>() == QMetaType::QVector2D); + QVERIFY(qMetaTypeId<QVector3D>() == QMetaType::QVector3D); + QVERIFY(qMetaTypeId<QVector4D>() == QMetaType::QVector4D); +} + +QTEST_APPLESS_MAIN(tst_QVectorND) + +#include "tst_qvectornd.moc" diff --git a/tests/auto/gui/painting/painting.pro b/tests/auto/gui/painting/painting.pro new file mode 100644 index 0000000000..62230eeac7 --- /dev/null +++ b/tests/auto/gui/painting/painting.pro @@ -0,0 +1,21 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qpainterpath \ + qpainterpathstroker \ + qcolor \ + qbrush \ + qregion \ + qpainter \ + qpathclipper \ + qprinterinfo \ + qpen \ + qpaintengine \ + qtransform \ + qwmatrix \ + qprinter \ + qpolygon \ + +!contains(QT_CONFIG, private_tests): SUBDIRS -= \ + qpathclipper \ + + diff --git a/tests/auto/gui/painting/qbrush/.gitignore b/tests/auto/gui/painting/qbrush/.gitignore new file mode 100644 index 0000000000..e9321a18bd --- /dev/null +++ b/tests/auto/gui/painting/qbrush/.gitignore @@ -0,0 +1 @@ +tst_qbrush diff --git a/tests/auto/gui/painting/qbrush/qbrush.pro b/tests/auto/gui/painting/qbrush/qbrush.pro new file mode 100644 index 0000000000..1c3efd46be --- /dev/null +++ b/tests/auto/gui/painting/qbrush/qbrush.pro @@ -0,0 +1,3 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qbrush.cpp diff --git a/tests/auto/gui/painting/qbrush/tst_qbrush.cpp b/tests/auto/gui/painting/qbrush/tst_qbrush.cpp new file mode 100644 index 0000000000..9ee679e0f7 --- /dev/null +++ b/tests/auto/gui/painting/qbrush/tst_qbrush.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include "qbrush.h" +#include <QPainter> +#include <QBitmap> + +#include <qdebug.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QBrush : public QObject +{ + Q_OBJECT + +public: + tst_QBrush(); + +private slots: + void operator_eq_eq(); + void operator_eq_eq_data(); + + void stream(); + void stream_data(); + + void badStyles(); + + void testQLinearGradientSetters(); + void testQRadialGradientSetters(); + void testQConicalGradientSetters(); + void testQGradientCopyConstructor(); + + void gradientStops(); + + void textures(); + + void swap(); + void nullBrush(); + void isOpaque(); + void debug(); +}; + +Q_DECLARE_METATYPE(QBrush) + +tst_QBrush::tst_QBrush() +{ +} + +void tst_QBrush::operator_eq_eq_data() +{ + QTest::addColumn<QBrush>("brush1"); + QTest::addColumn<QBrush>("brush2"); + QTest::addColumn<bool>("isEqual"); + + QLinearGradient lg(10, 10, 100, 100); + lg.setColorAt(0, Qt::red); + lg.setColorAt(0.5, Qt::blue); + lg.setColorAt(1, Qt::green); + + QTest::newRow("black vs black") << QBrush(Qt::black) << QBrush(Qt::black) << true; + QTest::newRow("black vs blue") << QBrush(Qt::black) << QBrush(Qt::blue) << false; + + QTest::newRow("red vs no") << QBrush(Qt::red) << QBrush(Qt::NoBrush) << false; + QTest::newRow("no vs no") << QBrush(Qt::NoBrush) << QBrush(Qt::NoBrush) << true; + + QTest::newRow("lg vs same lg") << QBrush(lg) << QBrush(lg) << true; + QTest::newRow("lg vs diff lg") << QBrush(lg) << QBrush(QLinearGradient(QPoint(0, 0), QPoint(1, 1))) + << false; + + QTest::newRow("rad vs con") << QBrush(QRadialGradient(0, 0, 0, 0, 0)) << QBrush(QConicalGradient(0, 0, 0)) << false; + + QBrush b1(lg); + QBrush b2(lg); + b1.setTransform(QTransform().scale(2, 2)); + QTest::newRow("lg with transform vs same lg") << b1 << b2 << false; + + b2.setTransform(QTransform().scale(2, 2)); + QTest::newRow("lg w/transform vs same lg w/same transform") << b1 << b2 << true; + +} + +void tst_QBrush::operator_eq_eq() +{ + QFETCH(QBrush, brush1); + QFETCH(QBrush, brush2); + QFETCH(bool, isEqual); + QCOMPARE(brush1 == brush2, isEqual); +} + +void tst_QBrush::stream_data() +{ + QTest::addColumn<QBrush>("brush"); + + QLinearGradient lg(10, 10, 100, 100); + lg.setColorAt(0, Qt::red); + lg.setColorAt(0.5, Qt::blue); + lg.setColorAt(1, Qt::green); + + QTest::newRow("black") << QBrush(Qt::black); + QTest::newRow("red") << QBrush(Qt::red); + QTest::newRow("no") << QBrush(Qt::NoBrush); + QTest::newRow("lg") << QBrush(lg); + QTest::newRow("rad") << QBrush(QRadialGradient(0, 0, 0, 0, 0)); + QTest::newRow("con") << QBrush(QConicalGradient(0, 0, 0)); +} + +void tst_QBrush::stream() +{ + QFETCH(QBrush, brush); + + QByteArray data; + + { + QDataStream stream(&data, QIODevice::WriteOnly); + stream << brush; + } + + QBrush cmp; + { + QDataStream stream(&data, QIODevice::ReadOnly); + stream >> cmp; + } + + QCOMPARE(brush.style(), cmp.style()); + QCOMPARE(brush.color(), cmp.color()); + QCOMPARE(brush, cmp); +} + +void tst_QBrush::testQLinearGradientSetters() +{ + QLinearGradient lg; + + QCOMPARE(lg.start(), QPointF(0, 0)); + QCOMPARE(lg.finalStop(), QPointF(1, 1)); + + lg.setStart(101, 102); + QCOMPARE(lg.start(), QPointF(101, 102)); + + lg.setStart(QPointF(201, 202)); + QCOMPARE(lg.start(), QPointF(201, 202)); + + lg.setFinalStop(103, 104); + QCOMPARE(lg.finalStop(), QPointF(103, 104)); + + lg.setFinalStop(QPointF(203, 204)); + QCOMPARE(lg.finalStop(), QPointF(203, 204)); +} + +void tst_QBrush::testQRadialGradientSetters() +{ + QRadialGradient rg; + + QCOMPARE(rg.radius(), qreal(1.0)); + QCOMPARE(rg.center(), QPointF(0, 0)); + QCOMPARE(rg.focalPoint(), QPointF(0, 0)); + + rg.setRadius(100); + QCOMPARE(rg.radius(), qreal(100.0)); + + rg.setCenter(101, 102); + QCOMPARE(rg.center(), QPointF(101, 102)); + + rg.setCenter(QPointF(201, 202)); + QCOMPARE(rg.center(), QPointF(201, 202)); + + rg.setFocalPoint(103, 104); + QCOMPARE(rg.focalPoint(), QPointF(103, 104)); + + rg.setFocalPoint(QPointF(203, 204)); + QCOMPARE(rg.focalPoint(), QPointF(203, 204)); +} + +void tst_QBrush::testQConicalGradientSetters() +{ + QConicalGradient cg; + + QCOMPARE(cg.angle(), qreal(0.0)); + QCOMPARE(cg.center(), QPointF(0, 0)); + + cg.setAngle(100); + QCOMPARE(cg.angle(), qreal(100.0)); + + cg.setCenter(102, 103); + QCOMPARE(cg.center(), QPointF(102, 103)); + + cg.setCenter(QPointF(202, 203)); + QCOMPARE(cg.center(), QPointF(202, 203)); +} + +void tst_QBrush::testQGradientCopyConstructor() +{ + { + QLinearGradient lg1(101, 102, 103, 104); + + QLinearGradient lg2 = lg1; + QCOMPARE(lg1.start(), lg2.start()); + QCOMPARE(lg1.finalStop(), lg2.finalStop()); + + QGradient g = lg1; + QCOMPARE(((QLinearGradient *) &g)->start(), lg1.start()); + QCOMPARE(((QLinearGradient *) &g)->finalStop(), lg1.finalStop()); + } + + { + QRadialGradient rg1(101, 102, 103, 104, 105); + + QRadialGradient rg2 = rg1; + QCOMPARE(rg1.center(), rg2.center()); + QCOMPARE(rg1.focalPoint(), rg2.focalPoint()); + QCOMPARE(rg1.radius(), rg2.radius()); + + QGradient g = rg1; + QCOMPARE(((QRadialGradient *) &g)->center(), rg1.center()); + QCOMPARE(((QRadialGradient *) &g)->focalPoint(), rg1.focalPoint()); + QCOMPARE(((QRadialGradient *) &g)->radius(), rg1.radius()); + } + + { + QConicalGradient cg1(101, 102, 103); + + QConicalGradient cg2 = cg1; + QCOMPARE(cg1.center(), cg2.center()); + QCOMPARE(cg1.angle(), cg2.angle()); + + QGradient g = cg1; + QCOMPARE(((QConicalGradient *) &g)->center(), cg1.center()); + QCOMPARE(((QConicalGradient *) &g)->angle(), cg1.angle()); + } + +} + +void tst_QBrush::badStyles() +{ + // QBrush(Qt::BrushStyle) constructor + QCOMPARE(QBrush(Qt::LinearGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(Qt::RadialGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(Qt::ConicalGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(Qt::TexturePattern).style(), Qt::NoBrush); + + // QBrush(QColor, Qt::BrushStyle) constructor + QCOMPARE(QBrush(QColor(0, 0, 0), Qt::LinearGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(QColor(0, 0, 0), Qt::RadialGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(QColor(0, 0, 0), Qt::ConicalGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(QColor(0, 0, 0), Qt::TexturePattern).style(), Qt::NoBrush); + + // QBrush(Qt::GlobalColor, Qt::BrushStyle) constructor + QCOMPARE(QBrush(Qt::black, Qt::LinearGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(Qt::black, Qt::RadialGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(Qt::black, Qt::ConicalGradientPattern).style(), Qt::NoBrush); + QCOMPARE(QBrush(Qt::black, Qt::TexturePattern).style(), Qt::NoBrush); + + // Set style... + QBrush brush(Qt::red); + + brush.setStyle(Qt::LinearGradientPattern); + QCOMPARE(brush.style(), Qt::SolidPattern); + + brush.setStyle(Qt::RadialGradientPattern); + QCOMPARE(brush.style(), Qt::SolidPattern); + + brush.setStyle(Qt::ConicalGradientPattern); + QCOMPARE(brush.style(), Qt::SolidPattern); + + brush.setStyle(Qt::TexturePattern); + QCOMPARE(brush.style(), Qt::SolidPattern); + +} + +void tst_QBrush::gradientStops() +{ + QLinearGradient gradient; + gradient.setColorAt(0, Qt::red); + gradient.setColorAt(1, Qt::blue); + + QCOMPARE(gradient.stops().size(), 2); + + QCOMPARE(gradient.stops().at(0), QGradientStop(0, QColor(Qt::red))); + QCOMPARE(gradient.stops().at(1), QGradientStop(1, QColor(Qt::blue))); + + gradient.setColorAt(0, Qt::blue); + gradient.setColorAt(1, Qt::red); + + QCOMPARE(gradient.stops().size(), 2); + + QCOMPARE(gradient.stops().at(0), QGradientStop(0, QColor(Qt::blue))); + QCOMPARE(gradient.stops().at(1), QGradientStop(1, QColor(Qt::red))); + + gradient.setColorAt(0.5, Qt::green); + + QCOMPARE(gradient.stops().size(), 3); + QCOMPARE(gradient.stops().at(1), QGradientStop(0.5, QColor(Qt::green))); + + // A hack in parseStopNode() in qsvghandler.cpp depends on inserting stops at NaN. + gradient.setStops(QGradientStops() << QGradientStop(qQNaN(), QColor())); + QCOMPARE(gradient.stops().size(), 1); + QVERIFY(qIsNaN(gradient.stops().at(0).first)); + QCOMPARE(gradient.stops().at(0).second, QColor()); +} + +void fill(QPaintDevice *pd) { + QPainter p(pd); + + int w = pd->width(); + int h = pd->height(); + + p.fillRect(0, 0, w, h, Qt::white); + p.fillRect(0, 0, w/3, h/3, Qt::black); +} + +void tst_QBrush::textures() +{ + QPixmap pixmap_source(10, 10); + QImage image_source(10, 10, QImage::Format_RGB32); + + fill(&pixmap_source); + fill(&image_source); + + // Create a pixmap brush and compare its texture and textureImage + // to the expected image + QBrush pixmap_brush; + pixmap_brush.setTexture(pixmap_source); + QImage image = pixmap_brush.texture().toImage().convertToFormat(QImage::Format_RGB32); + QCOMPARE(image, image_source); + image = pixmap_brush.textureImage().convertToFormat(QImage::Format_RGB32); + QCOMPARE(image, image_source); + + pixmap_brush = QBrush(pixmap_source); + image = pixmap_brush.texture().toImage().convertToFormat(QImage::Format_RGB32); + QCOMPARE(image, image_source); + image = pixmap_brush.textureImage().convertToFormat(QImage::Format_RGB32); + QCOMPARE(image, image_source); + + // Create a image brush and compare its texture and textureImage + // to the expected image + QBrush image_brush; + image_brush.setTextureImage(image_source); + image = image_brush.texture().toImage().convertToFormat(QImage::Format_RGB32); + QCOMPARE(image, image_source); + QCOMPARE(image_brush.textureImage(), image_source); + + image_brush = QBrush(image_source); + image = image_brush.texture().toImage().convertToFormat(QImage::Format_RGB32); + QCOMPARE(image, image_source); + QCOMPARE(image_brush.textureImage(), image_source); +} + +void tst_QBrush::swap() +{ + QBrush b1(Qt::black), b2(Qt::white); + b1.swap(b2); + QCOMPARE(b1.color(), QColor(Qt::white)); + QCOMPARE(b2.color(), QColor(Qt::black)); +} + +void tst_QBrush::nullBrush() +{ + QBrush brush(QColor(100,0,0), Qt::NoBrush); + QCOMPARE(brush.color(), QColor(100,0,0)); +} + +void tst_QBrush::isOpaque() +{ + QBitmap bm(8, 8); + bm.fill(Qt::black); + + QBrush brush(bm); + QVERIFY(!brush.isOpaque()); +} + +void tst_QBrush::debug() +{ + QPixmap pixmap_source(10, 10); + fill(&pixmap_source); + QBrush pixmap_brush; + pixmap_brush.setTexture(pixmap_source); + QCOMPARE(pixmap_brush.style(), Qt::TexturePattern); + qDebug() << pixmap_brush; // don't crash +} + +QTEST_MAIN(tst_QBrush) +#include "tst_qbrush.moc" diff --git a/tests/auto/gui/painting/qcolor/.gitignore b/tests/auto/gui/painting/qcolor/.gitignore new file mode 100644 index 0000000000..92f91eb54e --- /dev/null +++ b/tests/auto/gui/painting/qcolor/.gitignore @@ -0,0 +1 @@ +tst_qcolor diff --git a/tests/auto/gui/painting/qcolor/qcolor.pro b/tests/auto/gui/painting/qcolor/qcolor.pro new file mode 100644 index 0000000000..b9d437ef7c --- /dev/null +++ b/tests/auto/gui/painting/qcolor/qcolor.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qcolor.cpp + + + diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp new file mode 100644 index 0000000000..2b6896ae5d --- /dev/null +++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp @@ -0,0 +1,1538 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <limits.h> + +#include <qcolor.h> +#include <qdebug.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QColor : public QObject +{ + Q_OBJECT + +public: + tst_QColor(); + +private slots: + void getSetCheck(); + void isValid_data(); + void isValid(); + + void name_data(); + void name(); + void setNamedColor(); + + void constructNamedColorWithSpace(); + + void colorNames(); + + void spec(); + + void globalColors_data(); + void globalColors(); + + void alpha(); + void setAlpha(); + + void red(); + void green(); + void blue(); + + void setRed(); + void setGreen(); + void setBlue(); + + void getRgb(); + void setRgb(); + + void rgba(); + void setRgba(); + + void rgb(); + + void hue(); + void saturation(); + void value(); + + void getHsv(); + void setHsv(); + + void cyan(); + void magenta(); + void yellow(); + void black(); + + void getCmyk(); + void setCmyk(); + + void hueHsl(); + void saturationHsl(); + void lightness(); + + void getHsl(); + void setHsl(); + + void toRgb_data(); + void toRgb(); + void toRgbNonDestructive(); + + void toHsv_data(); + void toHsv(); + void toHsvNonDestructive(); + + void toCmyk_data(); + void toCmyk(); + void toCmykNonDestructive(); + + void toHsl_data(); + void toHsl();; + void toHslNonDestructive(); + + void convertTo(); + + void fromRgb(); + void fromHsv(); + void fromCmyk(); + void fromHsl(); + + void light(); + void dark(); + + void assignmentOoperator(); + void equalityOperator(); + + void specConstructor_data(); + void specConstructor(); + + void achromaticHslHue(); + +#ifdef Q_WS_X11 + void allowX11ColorNames(); + void setallowX11ColorNames(); +#endif +}; + +// Testing get/set functions +void tst_QColor::getSetCheck() +{ + QColor obj1; + // int QColor::alpha() + // void QColor::setAlpha(int) + obj1.setAlpha(0); + QCOMPARE(obj1.alpha(), 0); + obj1.setAlpha(-1); + QCOMPARE(obj1.alpha(), 0); // range<0, 255> + obj1.setAlpha(INT_MIN); + QCOMPARE(obj1.alpha(), 0); // range<0, 255> + obj1.setAlpha(255); + QCOMPARE(obj1.alpha(), 255); // range<0, 255> + obj1.setAlpha(INT_MAX); + QCOMPARE(obj1.alpha(), 255); // range<0, 255> + + // qreal QColor::alphaF() + // void QColor::setAlphaF(qreal) + obj1.setAlphaF(0.0); + QCOMPARE(obj1.alphaF(), qreal(0.0)); // range<0.0, 1.0> + obj1.setAlphaF(-0.2); + QCOMPARE(obj1.alphaF(), qreal(0.0)); // range<0.0, 1.0> + obj1.setAlphaF(1.0); + QCOMPARE(obj1.alphaF(), qreal(1.0)); // range<0.0, 1.0> + obj1.setAlphaF(1.1); + QCOMPARE(obj1.alphaF(), qreal(1.0)); // range<0.0, 1.0> + + // int QColor::red() + // void QColor::setRed(int) + obj1.setRed(0); + QCOMPARE(obj1.red(), 0); + obj1.setRed(-1); + QCOMPARE(obj1.red(), 0); // range<0, 255> + obj1.setRed(INT_MIN); + QCOMPARE(obj1.red(), 0); // range<0, 255> + obj1.setRed(255); + QCOMPARE(obj1.red(), 255); // range<0, 255> + obj1.setRed(INT_MAX); + QCOMPARE(obj1.red(), 255); // range<0, 255> + + // int QColor::green() + // void QColor::setGreen(int) + obj1.setGreen(0); + QCOMPARE(obj1.green(), 0); + obj1.setGreen(-1); + QCOMPARE(obj1.green(), 0); // range<0, 255> + obj1.setGreen(INT_MIN); + QCOMPARE(obj1.green(), 0); // range<0, 255> + obj1.setGreen(255); + QCOMPARE(obj1.green(), 255); // range<0, 255> + obj1.setGreen(INT_MAX); + QCOMPARE(obj1.green(), 255); // range<0, 255> + + // int QColor::blue() + // void QColor::setBlue(int) + obj1.setBlue(0); + QCOMPARE(obj1.blue(), 0); + obj1.setBlue(-1); + QCOMPARE(obj1.blue(), 0); // range<0, 255> + obj1.setBlue(INT_MIN); + QCOMPARE(obj1.blue(), 0); // range<0, 255> + obj1.setBlue(255); + QCOMPARE(obj1.blue(), 255); // range<0, 255> + obj1.setBlue(INT_MAX); + QCOMPARE(obj1.blue(), 255); // range<0, 255> + + // qreal QColor::redF() + // void QColor::setRedF(qreal) + obj1.setRedF(0.0); + QCOMPARE(obj1.redF(), qreal(0.0)); + obj1.setRedF(-0.2); + QCOMPARE(obj1.redF(), qreal(0.0)); // range<0.0, 1.0 + obj1.setRedF(1.1); + QCOMPARE(obj1.redF(), qreal(1.0)); // range<0.0, 1.0 + + // qreal QColor::greenF() + // void QColor::setGreenF(qreal) + obj1.setGreenF(0.0); + QCOMPARE(obj1.greenF(), qreal(0.0)); + obj1.setGreenF(-0.2); + QCOMPARE(obj1.greenF(), qreal(0.0)); // range<0.0, 1.0 + obj1.setGreenF(1.1); + QCOMPARE(obj1.greenF(), qreal(1.0)); // range<0.0, 1.0 + + // qreal QColor::blueF() + // void QColor::setBlueF(qreal) + obj1.setBlueF(0.0); + QCOMPARE(obj1.blueF(), qreal(0.0)); + obj1.setBlueF(-0.2); + QCOMPARE(obj1.blueF(), qreal(0.0)); // range<0.0, 1.0 + obj1.setBlueF(1.1); + QCOMPARE(obj1.blueF(), qreal(1.0)); // range<0.0, 1.0 + + // QRgb QColor::rgba() + // void QColor::setRgba(QRgb) + QRgb var9(qRgba(10, 20, 30, 40)); + obj1.setRgba(var9); + QCOMPARE(obj1.rgba(), var9); + obj1.setRgba(QRgb(0)); + QCOMPARE(obj1.rgba(), QRgb(0)); + + // QRgb QColor::rgb() + // void QColor::setRgb(QRgb) + QRgb var10(qRgb(10, 20, 30)); + obj1.setRgb(var10); + QCOMPARE(obj1.rgb(), var10); + obj1.setRgb(QRgb(0)); + QCOMPARE(obj1.rgb(), qRgb(0, 0, 0)); +} + +Q_DECLARE_METATYPE(QColor) + + +tst_QColor::tst_QColor() + +{ } + +void tst_QColor::isValid_data() +{ + QTest::addColumn<QColor>("color"); + QTest::addColumn<bool>("isValid"); + + QTest::newRow("defaultConstructor") << QColor() << false; + QTest::newRow("rgbConstructor-valid") << QColor(2,5,7) << true; + QTest::newRow("rgbConstructor-invalid") << QColor(2,5,999) << false; + QTest::newRow("nameQStringConstructor-valid") << QColor(QString("#ffffff")) << true; + QTest::newRow("nameQStringConstructor-invalid") << QColor(QString("#ffffgg")) << false; + QTest::newRow("nameQStringConstructor-empty") << QColor(QString("")) << false; + QTest::newRow("nameQStringConstructor-named") << QColor(QString("red")) << true; + QTest::newRow("nameCharConstructor-valid") << QColor("#ffffff") << true; + QTest::newRow("nameCharConstructor-invalid") << QColor("#ffffgg") << false; + QTest::newRow("nameCharConstructor-invalid-2") << QColor("#fffffg") << false; +} + +void tst_QColor::isValid() +{ + QFETCH(QColor, color); + QFETCH(bool, isValid); + QVERIFY(color.isValid() == isValid); +} + +void tst_QColor::name_data() +{ + QTest::addColumn<QColor>("color"); + QTest::addColumn<QString>("name"); + + QTest::newRow("invalid") << QColor() << "#000000"; + QTest::newRow("global color black") << QColor(Qt::black) << "#000000"; + QTest::newRow("global color white") << QColor(Qt::white) << "#ffffff"; + QTest::newRow("global color darkGray") << QColor(Qt::darkGray) << "#808080"; + QTest::newRow("global color gray") << QColor(Qt::gray) << "#a0a0a4"; + QTest::newRow("global color lightGray") << QColor(Qt::lightGray) << "#c0c0c0"; + QTest::newRow("global color red") << QColor(Qt::red) << "#ff0000"; + QTest::newRow("global color green") << QColor(Qt::green) << "#00ff00"; + QTest::newRow("global color blue") << QColor(Qt::blue) << "#0000ff"; + QTest::newRow("global color cyan") << QColor(Qt::cyan) << "#00ffff"; + QTest::newRow("global color magenta") << QColor(Qt::magenta) << "#ff00ff"; + QTest::newRow("global color yellow") << QColor(Qt::yellow) << "#ffff00"; + QTest::newRow("global color darkRed") << QColor(Qt::darkRed) << "#800000"; + QTest::newRow("global color darkGreen") << QColor(Qt::darkGreen) << "#008000"; + QTest::newRow("global color darkBlue") << QColor(Qt::darkBlue) << "#000080"; + QTest::newRow("global color darkCyan") << QColor(Qt::darkCyan) << "#008080"; + QTest::newRow("global color darkMagenta") << QColor(Qt::darkMagenta) << "#800080"; + QTest::newRow("global color darkYellow") << QColor(Qt::darkYellow) << "#808000"; +} + +void tst_QColor::name() +{ + QFETCH(QColor, color); + QFETCH(QString, name); + QCOMPARE(color.name(), name); +} + +void tst_QColor::globalColors_data() +{ + QTest::addColumn<QColor>("color"); + QTest::addColumn<uint>("argb"); + + QTest::newRow("invalid") << QColor() << 0xff000000; + QTest::newRow("global color black") << QColor(Qt::black) << 0xff000000; + QTest::newRow("global color white") << QColor(Qt::white) << 0xffffffff; + QTest::newRow("global color darkGray") << QColor(Qt::darkGray) << 0xff808080; + QTest::newRow("global color gray") << QColor(Qt::gray) << 0xffa0a0a4; + QTest::newRow("global color lightGray") << QColor(Qt::lightGray) << 0xffc0c0c0; + QTest::newRow("global color red") << QColor(Qt::red) << 0xffff0000; + QTest::newRow("global color green") << QColor(Qt::green) << 0xff00ff00; + QTest::newRow("global color blue") << QColor(Qt::blue) << 0xff0000ff; + QTest::newRow("global color cyan") << QColor(Qt::cyan) << 0xff00ffff; + QTest::newRow("global color magenta") << QColor(Qt::magenta) << 0xffff00ff; + QTest::newRow("global color yellow") << QColor(Qt::yellow) << 0xffffff00; + QTest::newRow("global color darkRed") << QColor(Qt::darkRed) << 0xff800000; + QTest::newRow("global color darkGreen") << QColor(Qt::darkGreen) << 0xff008000; + QTest::newRow("global color darkBlue") << QColor(Qt::darkBlue) << 0xff000080; + QTest::newRow("global color darkCyan") << QColor(Qt::darkCyan) << 0xff008080; + QTest::newRow("global color darkMagenta") << QColor(Qt::darkMagenta) << 0xff800080; + QTest::newRow("global color darkYellow") << QColor(Qt::darkYellow) << 0xff808000; + QTest::newRow("global color transparent") << QColor(Qt::transparent) << 0x00000000u; +} + + +void tst_QColor::globalColors() +{ + QFETCH(QColor, color); + QFETCH(uint, argb); + QCOMPARE(color.rgba(), argb); +} + +/* + CSS color names = SVG 1.0 color names + transparent (rgba(0,0,0,0)) +*/ + +#ifdef rgb +# undef rgb +#endif +#define rgb(r,g,b) (0xff000000 | r << 16 | g << 8 | b) + +static const struct RGBData { + const char *name; + uint value; +} rgbTbl[] = { + { "aliceblue", rgb(240, 248, 255) }, + { "antiquewhite", rgb(250, 235, 215) }, + { "aqua", rgb( 0, 255, 255) }, + { "aquamarine", rgb(127, 255, 212) }, + { "azure", rgb(240, 255, 255) }, + { "beige", rgb(245, 245, 220) }, + { "bisque", rgb(255, 228, 196) }, + { "black", rgb( 0, 0, 0) }, + { "blanchedalmond", rgb(255, 235, 205) }, + { "blue", rgb( 0, 0, 255) }, + { "blueviolet", rgb(138, 43, 226) }, + { "brown", rgb(165, 42, 42) }, + { "burlywood", rgb(222, 184, 135) }, + { "cadetblue", rgb( 95, 158, 160) }, + { "chartreuse", rgb(127, 255, 0) }, + { "chocolate", rgb(210, 105, 30) }, + { "coral", rgb(255, 127, 80) }, + { "cornflowerblue", rgb(100, 149, 237) }, + { "cornsilk", rgb(255, 248, 220) }, + { "crimson", rgb(220, 20, 60) }, + { "cyan", rgb( 0, 255, 255) }, + { "darkblue", rgb( 0, 0, 139) }, + { "darkcyan", rgb( 0, 139, 139) }, + { "darkgoldenrod", rgb(184, 134, 11) }, + { "darkgray", rgb(169, 169, 169) }, + { "darkgreen", rgb( 0, 100, 0) }, + { "darkgrey", rgb(169, 169, 169) }, + { "darkkhaki", rgb(189, 183, 107) }, + { "darkmagenta", rgb(139, 0, 139) }, + { "darkolivegreen", rgb( 85, 107, 47) }, + { "darkorange", rgb(255, 140, 0) }, + { "darkorchid", rgb(153, 50, 204) }, + { "darkred", rgb(139, 0, 0) }, + { "darksalmon", rgb(233, 150, 122) }, + { "darkseagreen", rgb(143, 188, 143) }, + { "darkslateblue", rgb( 72, 61, 139) }, + { "darkslategray", rgb( 47, 79, 79) }, + { "darkslategrey", rgb( 47, 79, 79) }, + { "darkturquoise", rgb( 0, 206, 209) }, + { "darkviolet", rgb(148, 0, 211) }, + { "deeppink", rgb(255, 20, 147) }, + { "deepskyblue", rgb( 0, 191, 255) }, + { "dimgray", rgb(105, 105, 105) }, + { "dimgrey", rgb(105, 105, 105) }, + { "dodgerblue", rgb( 30, 144, 255) }, + { "firebrick", rgb(178, 34, 34) }, + { "floralwhite", rgb(255, 250, 240) }, + { "forestgreen", rgb( 34, 139, 34) }, + { "fuchsia", rgb(255, 0, 255) }, + { "gainsboro", rgb(220, 220, 220) }, + { "ghostwhite", rgb(248, 248, 255) }, + { "gold", rgb(255, 215, 0) }, + { "goldenrod", rgb(218, 165, 32) }, + { "gray", rgb(128, 128, 128) }, + { "green", rgb( 0, 128, 0) }, + { "greenyellow", rgb(173, 255, 47) }, + { "grey", rgb(128, 128, 128) }, + { "honeydew", rgb(240, 255, 240) }, + { "hotpink", rgb(255, 105, 180) }, + { "indianred", rgb(205, 92, 92) }, + { "indigo", rgb( 75, 0, 130) }, + { "ivory", rgb(255, 255, 240) }, + { "khaki", rgb(240, 230, 140) }, + { "lavender", rgb(230, 230, 250) }, + { "lavenderblush", rgb(255, 240, 245) }, + { "lawngreen", rgb(124, 252, 0) }, + { "lemonchiffon", rgb(255, 250, 205) }, + { "lightblue", rgb(173, 216, 230) }, + { "lightcoral", rgb(240, 128, 128) }, + { "lightcyan", rgb(224, 255, 255) }, + { "lightgoldenrodyellow", rgb(250, 250, 210) }, + { "lightgray", rgb(211, 211, 211) }, + { "lightgreen", rgb(144, 238, 144) }, + { "lightgrey", rgb(211, 211, 211) }, + { "lightpink", rgb(255, 182, 193) }, + { "lightsalmon", rgb(255, 160, 122) }, + { "lightseagreen", rgb( 32, 178, 170) }, + { "lightskyblue", rgb(135, 206, 250) }, + { "lightslategray", rgb(119, 136, 153) }, + { "lightslategrey", rgb(119, 136, 153) }, + { "lightsteelblue", rgb(176, 196, 222) }, + { "lightyellow", rgb(255, 255, 224) }, + { "lime", rgb( 0, 255, 0) }, + { "limegreen", rgb( 50, 205, 50) }, + { "linen", rgb(250, 240, 230) }, + { "magenta", rgb(255, 0, 255) }, + { "maroon", rgb(128, 0, 0) }, + { "mediumaquamarine", rgb(102, 205, 170) }, + { "mediumblue", rgb( 0, 0, 205) }, + { "mediumorchid", rgb(186, 85, 211) }, + { "mediumpurple", rgb(147, 112, 219) }, + { "mediumseagreen", rgb( 60, 179, 113) }, + { "mediumslateblue", rgb(123, 104, 238) }, + { "mediumspringgreen", rgb( 0, 250, 154) }, + { "mediumturquoise", rgb( 72, 209, 204) }, + { "mediumvioletred", rgb(199, 21, 133) }, + { "midnightblue", rgb( 25, 25, 112) }, + { "mintcream", rgb(245, 255, 250) }, + { "mistyrose", rgb(255, 228, 225) }, + { "moccasin", rgb(255, 228, 181) }, + { "navajowhite", rgb(255, 222, 173) }, + { "navy", rgb( 0, 0, 128) }, + { "oldlace", rgb(253, 245, 230) }, + { "olive", rgb(128, 128, 0) }, + { "olivedrab", rgb(107, 142, 35) }, + { "orange", rgb(255, 165, 0) }, + { "orangered", rgb(255, 69, 0) }, + { "orchid", rgb(218, 112, 214) }, + { "palegoldenrod", rgb(238, 232, 170) }, + { "palegreen", rgb(152, 251, 152) }, + { "paleturquoise", rgb(175, 238, 238) }, + { "palevioletred", rgb(219, 112, 147) }, + { "papayawhip", rgb(255, 239, 213) }, + { "peachpuff", rgb(255, 218, 185) }, + { "peru", rgb(205, 133, 63) }, + { "pink", rgb(255, 192, 203) }, + { "plum", rgb(221, 160, 221) }, + { "powderblue", rgb(176, 224, 230) }, + { "purple", rgb(128, 0, 128) }, + { "red", rgb(255, 0, 0) }, + { "rosybrown", rgb(188, 143, 143) }, + { "royalblue", rgb( 65, 105, 225) }, + { "saddlebrown", rgb(139, 69, 19) }, + { "salmon", rgb(250, 128, 114) }, + { "sandybrown", rgb(244, 164, 96) }, + { "seagreen", rgb( 46, 139, 87) }, + { "seashell", rgb(255, 245, 238) }, + { "sienna", rgb(160, 82, 45) }, + { "silver", rgb(192, 192, 192) }, + { "skyblue", rgb(135, 206, 235) }, + { "slateblue", rgb(106, 90, 205) }, + { "slategray", rgb(112, 128, 144) }, + { "slategrey", rgb(112, 128, 144) }, + { "snow", rgb(255, 250, 250) }, + { "springgreen", rgb( 0, 255, 127) }, + { "steelblue", rgb( 70, 130, 180) }, + { "tan", rgb(210, 180, 140) }, + { "teal", rgb( 0, 128, 128) }, + { "thistle", rgb(216, 191, 216) }, + { "tomato", rgb(255, 99, 71) }, + { "transparent", 0 }, + { "turquoise", rgb( 64, 224, 208) }, + { "violet", rgb(238, 130, 238) }, + { "wheat", rgb(245, 222, 179) }, + { "white", rgb(255, 255, 255) }, + { "whitesmoke", rgb(245, 245, 245) }, + { "yellow", rgb(255, 255, 0) }, + { "yellowgreen", rgb(154, 205, 50) } +}; +static const int rgbTblSize = sizeof(rgbTbl) / sizeof(RGBData); + +#undef rgb + +void tst_QColor::setNamedColor() +{ + for (int i = 0; i < rgbTblSize; ++i) { + QColor color; + color.setNamedColor(QLatin1String(rgbTbl[i].name)); + QColor expected; + expected.setRgba(rgbTbl[i].value); + QCOMPARE(color, expected); + } +} + +void tst_QColor::constructNamedColorWithSpace() +{ + QColor whiteSmoke("white smoke"); + QCOMPARE(whiteSmoke, QColor(245, 245, 245)); +} + +void tst_QColor::colorNames() +{ + DEPENDS_ON("setNamedColor()"); + + QStringList all = QColor::colorNames(); + QCOMPARE(all.size(), rgbTblSize); + for (int i = 0; i < all.size(); ++i) + QCOMPARE(all.at(i), QString::fromLatin1(rgbTbl[i].name)); +} + +void tst_QColor::spec() +{ + QColor invalid; + QCOMPARE(invalid.spec(), QColor::Invalid); + + QColor rgb = QColor::fromRgb(0, 0, 0); + QCOMPARE(rgb.spec(), QColor::Rgb); + + QColor hsv = QColor::fromHsv(0, 0, 0); + QCOMPARE(hsv.spec(), QColor::Hsv); + + QColor cmyk = QColor::fromCmyk(0, 0, 0, 0); + QCOMPARE(cmyk.spec(), QColor::Cmyk); + + QColor hsl = QColor::fromHsl(0, 0, 0, 0); + QCOMPARE(hsl.spec(), QColor::Hsl); + +} + +void tst_QColor::alpha() +{ DEPENDS_ON(setRgb()); } + +void tst_QColor::red() +{ DEPENDS_ON(setRgb()); } + +void tst_QColor::green() +{ DEPENDS_ON(setRgb()); } + +void tst_QColor::blue() +{ DEPENDS_ON(setRgb()); } + +void tst_QColor::getRgb() +{ DEPENDS_ON(setRgb()); } + +void tst_QColor::setAlpha() +{ DEPENDS_ON(setRgb()); } + +bool veryFuzzyCompare(double a, double b) +{ + return qAbs(a - b) < 0.01; +} + +void tst_QColor::setRed() +{ + DEPENDS_ON(setRgb()); + + QColor c = QColor(Qt::blue).toHsv(); + c.setRed(127); + QCOMPARE(c.red(), 127); + QCOMPARE(c.green(), 0); + QCOMPARE(c.blue(), 255); + + c = QColor(Qt::blue).toHsv(); + c.setRedF(0.5); + QVERIFY(veryFuzzyCompare(c.redF(), 0.5)); + QCOMPARE(c.greenF(), qreal(0.0)); + QCOMPARE(c.blueF(), qreal(1.0)); +} + +void tst_QColor::setGreen() +{ + DEPENDS_ON(setRgb()); + + QColor c = QColor(Qt::blue).toHsv(); + c.setGreen(127); + QCOMPARE(c.red(), 0); + QCOMPARE(c.green(), 127); + QCOMPARE(c.blue(), 255); + + c = QColor(Qt::blue).toHsv(); + c.setGreenF(0.5); + QCOMPARE(c.redF(), qreal(0.0)); + QVERIFY(veryFuzzyCompare(c.greenF(), 0.5)); + QCOMPARE(c.blueF(), qreal(1.0)); +} + +void tst_QColor::setBlue() +{ + DEPENDS_ON(setRgb()); + + QColor c = QColor(Qt::red).toHsv(); + c.setBlue(127); + QCOMPARE(c.red(), 255); + QCOMPARE(c.green(), 0); + QCOMPARE(c.blue(), 127); + + c = QColor(Qt::red).toHsv(); + c.setBlueF(0.5); + QCOMPARE(c.redF(), qreal(1.0)); + QCOMPARE(c.greenF(), qreal(0.0)); + QVERIFY(veryFuzzyCompare(c.blueF(), 0.5)); +} + + +void tst_QColor::setRgb() +{ + QColor color; + + for (int A = 0; A <= USHRT_MAX; ++A) { + { + // 0-255 + int a = A >> 8; + QRgb rgb = qRgba(0, 0, 0, a); + + color.setRgb(0, 0, 0, a); + QCOMPARE(color.alpha(), a); + QCOMPARE(color.rgb(), qRgb(0, 0, 0)); + + color.setRgb(rgb); + QCOMPARE(color.alpha(), 255); + QCOMPARE(color.rgb(), qRgb(0, 0, 0)); + + int r, g, b, a2; + color.setRgb(0, 0, 0, a); + color.getRgb(&r, &g, &b, &a2); + QCOMPARE(a2, a); + + QColor c(0, 0, 0); + c.setAlpha(a); + QCOMPARE(c.alpha(), a); + } + + { + // 0.0-1.0 + qreal a = A / qreal(USHRT_MAX); + color.setRgbF(0.0, 0.0, 0.0, a); + QCOMPARE(color.alphaF(), a); + + qreal r, g, b, a2; + color.getRgbF(&r, &g, &b, &a2); + QCOMPARE(a2, a); + + QColor c(0, 0, 0); + c.setAlphaF(a); + + QCOMPARE(c.alphaF(), a); + } + } + + for (int R = 0; R <= USHRT_MAX; ++R) { + { + // 0-255 + int r = R >> 8; + QRgb rgb = qRgb(r, 0, 0); + + color.setRgb(r, 0, 0); + QCOMPARE(color.red(), r); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.red(), r); + QCOMPARE(color.rgb(), rgb); + + int r2, g, b, a; + color.getRgb(&r2, &g, &b, &a); + QCOMPARE(r2, r); + } + + { + // 0.0-1.0 + qreal r = R / qreal(USHRT_MAX); + color.setRgbF(r, 0.0, 0.0); + QCOMPARE(color.redF(), r); + + qreal r2, g, b, a; + color.getRgbF(&r2, &g, &b, &a); + QCOMPARE(r2, r); + } + } + + for (int G = 0; G <= USHRT_MAX; ++G) { + { + // 0-255 + int g = G >> 8; + QRgb rgb = qRgb(0, g, 0); + + color.setRgb(0, g, 0); + QCOMPARE(color.green(), g); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.green(), g); + QCOMPARE(color.rgb(), rgb); + + int r, g2, b, a; + color.getRgb(&r, &g2, &b, &a); + QCOMPARE(g2, g); + } + + { + // 0.0-1.0 + qreal g = G / qreal(USHRT_MAX); + color.setRgbF(0.0, g, 0.0); + QCOMPARE(color.greenF(), g); + + qreal r, g2, b, a; + color.getRgbF(&r, &g2, &b, &a); + QCOMPARE(g2, g); + } + } + + for (int B = 0; B <= USHRT_MAX; ++B) { + { + // 0-255 + int b = B >> 8; + QRgb rgb = qRgb(0, 0, b); + + color.setRgb(0, 0, b); + QCOMPARE(color.blue(), b); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.blue(), b); + QCOMPARE(color.rgb(), rgb); + + int r, g, b2, a; + color.getRgb(&r, &g, &b2, &a); + QCOMPARE(b2, b); + } + + { + // 0.0-1.0 + qreal b = B / qreal(USHRT_MAX); + color.setRgbF(0.0, 0.0, b); + QCOMPARE(color.blueF(), b); + + qreal r, g, b2, a; + color.getRgbF(&r, &g, &b2, &a); + QCOMPARE(b2, b); + } + } +} + +void tst_QColor::rgba() +{ DEPENDS_ON("setRgba()"); } + +void tst_QColor::setRgba() +{ + for (int a = 0; a < 255; ++a) { + const QRgb rgba1 = qRgba(a, a, a, a); + QColor color; + color.setRgba(rgba1); + QCOMPARE(color.alpha(), a); + const QRgb rgba2 = color.rgba(); + QCOMPARE(rgba2, rgba1); + QCOMPARE(qAlpha(rgba2), a); + } +} + +void tst_QColor::rgb() +{ DEPENDS_ON(setRgb()); } + +void tst_QColor::hue() +{ DEPENDS_ON(setHsv()); } + +void tst_QColor::saturation() +{ DEPENDS_ON(setHsv()); } + +void tst_QColor::value() +{ DEPENDS_ON(setHsv()); } + +void tst_QColor::getHsv() +{ DEPENDS_ON(setHsv()); } + +void tst_QColor::setHsv() +{ + QColor color; + + for (int A = 0; A <= USHRT_MAX; ++A) { + { + // 0-255 + int a = A >> 8; + color.setHsv(0, 0, 0, a); + QCOMPARE(color.alpha(), a); + + int h, s, v, a2; + color.getHsv(&h, &s, &v, &a2); + QCOMPARE(a2, a); + } + + { + // 0.0-1.0 + qreal a = A / qreal(USHRT_MAX); + color.setHsvF(0.0, 0.0, 0.0, a); QCOMPARE(color.alphaF(), a); + + qreal h, s, v, a2; + color.getHsvF(&h, &s, &v, &a2); + QCOMPARE(a2, a); + } + } + + for (int H = 0; H < 36000; ++H) { + { + // 0-255 + int h = H / 100; + + color.setHsv(h, 0, 0, 0); + QCOMPARE(color.hue(), h); + + int h2, s, v, a; + color.getHsv(&h2, &s, &v, &a); + QCOMPARE(h2, h); + } + + { + // 0.0-1.0 + qreal h = H / 36000.0; + color.setHsvF(h, 0.0, 0.0, 0.0); + QCOMPARE(color.hueF(), h); + + qreal h2, s, v, a; + color.getHsvF(&h2, &s, &v, &a); + QCOMPARE(h2, h); + } + } + + for (int S = 0; S <= USHRT_MAX; ++S) { + { + // 0-255 + int s = S >> 8; + color.setHsv(0, s, 0, 0); + QCOMPARE(color.saturation(), s); + + int h, s2, v, a; + color.getHsv(&h, &s2, &v, &a); + QCOMPARE(s2, s); + } + + { + // 0.0-1.0 + qreal s = S / qreal(USHRT_MAX); + color.setHsvF(0.0, s, 0.0, 0.0); + QCOMPARE(color.saturationF(), s); + + qreal h, s2, v, a; + color.getHsvF(&h, &s2, &v, &a); + QCOMPARE(s2, s); + } + } + + for (int V = 0; V <= USHRT_MAX; ++V) { + { + // 0-255 + int v = V >> 8; + color.setHsv(0, 0, v, 0); + QCOMPARE(color.value(), v); + + int h, s, v2, a; + color.getHsv(&h, &s, &v2, &a); + QCOMPARE(v2, v); + } + + { + // 0.0-1.0 + qreal v = V / qreal(USHRT_MAX); + color.setHsvF(0.0, 0.0, v, 0.0); + QCOMPARE(color.valueF(), v); + + qreal h, s, v2, a; + color.getHsvF(&h, &s, &v2, &a); + QCOMPARE(v2, v); + } + } +} + +void tst_QColor::cyan() +{ DEPENDS_ON(setCmyk()); } + +void tst_QColor::magenta() +{ DEPENDS_ON(setCmyk()); } + +void tst_QColor::yellow() +{ DEPENDS_ON(setCmyk()); } + +void tst_QColor::black() +{ DEPENDS_ON(setCmyk()); } + +void tst_QColor::getCmyk() +{ DEPENDS_ON(setCmyk()); } + +void tst_QColor::setCmyk() +{ + QColor color; + + for (int A = 0; A <= USHRT_MAX; ++A) { + { + // 0-255 + int a = A >> 8; + color.setCmyk(0, 0, 0, 0, a); + QCOMPARE(color.alpha(), a); + + int c, m, y, k, a2; + color.getCmyk(&c, &m, &y, &k, &a2); + QCOMPARE(a2, a); + } + + { + // 0.0-1.0 + qreal a = A / qreal(USHRT_MAX); + color.setCmykF(0.0, 0.0, 0.0, 0.0, a); + QCOMPARE(color.alphaF(), a); + + qreal c, m, y, k, a2; + color.getCmykF(&c, &m, &y, &k, &a2); + QCOMPARE(a2, a); + } + } + + for (int C = 0; C <= USHRT_MAX; ++C) { + { + // 0-255 + int c = C >> 8; + color.setCmyk(c, 0, 0, 0, 0); + QCOMPARE(color.cyan(), c); + + int c2, m, y, k, a; + color.getCmyk(&c2, &m, &y, &k, &a); + QCOMPARE(c2, c); + } + + { + // 0.0-1.0 + qreal c = C / qreal(USHRT_MAX); + color.setCmykF(c, 0.0, 0.0, 0.0, 0.0); + QCOMPARE(color.cyanF(), c); + + qreal c2, m, y, k, a; + color.getCmykF(&c2, &m, &y, &k, &a); + QCOMPARE(c2, c); + } + } + + for (int M = 0; M <= USHRT_MAX; ++M) { + { + // 0-255 + int m = M >> 8; + color.setCmyk(0, m, 0, 0, 0); + QCOMPARE(color.magenta(), m); + + int c, m2, y, k, a; + color.getCmyk(&c, &m2, &y, &k, &a); + QCOMPARE(m2, m); + } + + { + // 0.0-1.0 + qreal m = M / qreal(USHRT_MAX); + color.setCmykF(0.0, m, 0.0, 0.0, 0.0); + QCOMPARE(color.magentaF(), m); + + qreal c, m2, y, k, a; + color.getCmykF(&c, &m2, &y, &k, &a); + QCOMPARE(m2, m); + } + } + + for (int Y = 0; Y <= USHRT_MAX; ++Y) { + { + // 0-255 + int y = Y >> 8; + color.setCmyk(0, 0, y, 0, 0); + QCOMPARE(color.yellow(), y); + + int c, m, y2, k, a; + color.getCmyk(&c, &m, &y2, &k, &a); + QCOMPARE(y2, y); + } + + { + // 0.0-1.0 + qreal y = Y / qreal(USHRT_MAX); + color.setCmykF(0.0, 0.0, y, 0.0, 0.0); + QCOMPARE(color.yellowF(), y); + + qreal c, m, y2, k, a; + color.getCmykF(&c, &m, &y2, &k, &a); + QCOMPARE(y2, y); + } + } + + for (int K = 0; K <= USHRT_MAX; ++K) { + { + // 0-255 + int k = K >> 8; + color.setCmyk(0, 0, 0, k, 0); + QCOMPARE(color.black(), k); + + int c, m, y, k2, a; + color.getCmyk(&c, &m, &y, &k2, &a); + QCOMPARE(k2, k); + } + + { + // 0.0-1.0 + qreal k = K / qreal(USHRT_MAX); + color.setCmykF(0.0, 0.0, 0.0, k, 0.0); + QCOMPARE(color.blackF(), k); + + qreal c, m, y, k2, a; + color.getCmykF(&c, &m, &y, &k2, &a); + QCOMPARE(k2, k); + } + } +} + +void tst_QColor::hueHsl() +{ DEPENDS_ON(setHsl()); } + +void tst_QColor::saturationHsl() +{ DEPENDS_ON(setHsl()); } + +void tst_QColor::lightness() +{ DEPENDS_ON(setHsl()); } + +void tst_QColor::getHsl() +{ DEPENDS_ON(setHsl()); } + +void tst_QColor::setHsl() +{ + QColor color; + + for (int A = 0; A <= USHRT_MAX; ++A) { + { + // 0-255 + int a = A >> 8; + color.setHsl(0, 0, 0, a); + QCOMPARE(color.alpha(), a); + + int h, s, l, a2; + color.getHsv(&h, &s, &l, &a2); + QCOMPARE(a2, a); + } + + { + // 0.0-1.0 + qreal a = A / qreal(USHRT_MAX); + color.setHslF(0.0, 0.0, 0.0, a); QCOMPARE(color.alphaF(), a); + + qreal h, s, l, a2; + color.getHslF(&h, &s, &l, &a2); + QCOMPARE(a2, a); + } + } + + for (int H = 0; H < 36000; ++H) { + { + // 0-255 + int h = H / 100; + + color.setHsl(h, 0, 0, 0); + QCOMPARE(color.hslHue(), h); + + int h2, s, l, a; + color.getHsl(&h2, &s, &l, &a); + QCOMPARE(h2, h); + } + + { + // 0.0-1.0 + qreal h = H / 36000.0; + color.setHslF(h, 0.0, 0.0, 0.0); + QCOMPARE(color.hslHueF(), h); + + qreal h2, s, l, a; + color.getHslF(&h2, &s, &l, &a); + QCOMPARE(h2, h); + } + } + + for (int S = 0; S <= USHRT_MAX; ++S) { + { + // 0-255 + int s = S >> 8; + color.setHsl(0, s, 0, 0); + QCOMPARE(color.hslSaturation(), s); + + int h, s2, l, a; + color.getHsl(&h, &s2, &l, &a); + QCOMPARE(s2, s); + } + + { + // 0.0-1.0 + qreal s = S / qreal(USHRT_MAX); + color.setHslF(0.0, s, 0.0, 0.0); + QCOMPARE(color.hslSaturationF(), s); + + qreal h, s2, l, a; + color.getHslF(&h, &s2, &l, &a); + QCOMPARE(s2, s); + } + } + + for (int L = 0; L <= USHRT_MAX; ++L) { + { + // 0-255 + int l = L >> 8; + color.setHsl(0, 0, l, 0); + QCOMPARE(color.lightness(), l); + + int h, s, l2, a; + color.getHsl(&h, &s, &l2, &a); + QCOMPARE(l2, l); + } + + { + // 0.0-1.0 + qreal l = L / qreal(USHRT_MAX); + color.setHslF(0.0, 0.0, l, 0.0); + QCOMPARE(color.lightnessF(), l); + + qreal h, s, l2, a; + color.getHslF(&h, &s, &l2, &a); + QCOMPARE(l2, l); + } + } +} + +void tst_QColor::toRgb_data() +{ + QTest::addColumn<QColor>("expectedColor"); + QTest::addColumn<QColor>("hsvColor"); + QTest::addColumn<QColor>("cmykColor"); + QTest::addColumn<QColor>("hslColor"); + + QTest::newRow("black") + << QColor::fromRgbF(0.0, 0.0, 0.0) + << QColor::fromHsvF(-1.0, 0.0, 0.0) + << QColor::fromCmykF(0.0, 0.0, 0.0, 1.0) + << QColor::fromHslF(-1.0, 0.0, 0.0); + + QTest::newRow("white") + << QColor::fromRgbF(1.0, 1.0, 1.0) + << QColor::fromHsvF(-1.0, 0.0, 1.0) + << QColor::fromCmykF(0.0, 0.0, 0.0, 0.0) + << QColor::fromHslF(-1.0, 0.0, 1.0); + + QTest::newRow("red") + << QColor::fromRgbF(1.0, 0.0, 0.0) + << QColor::fromHsvF(0.0, 1.0, 1.0) + << QColor::fromCmykF(0.0, 1.0, 1.0, 0.0) + << QColor::fromHslF(0.0, 1.0, 0.5, 1.0); + + QTest::newRow("green") + << QColor::fromRgbF(0.0, 1.0, 0.0) + << QColor::fromHsvF(0.33333, 1.0, 1.0) + << QColor::fromCmykF(1.0, 0.0, 1.0, 0.0) + << QColor::fromHslF(0.33333, 1.0, 0.5); + + QTest::newRow("blue") + << QColor::fromRgbF(0.0, 0.0, 1.0) + << QColor::fromHsvF(0.66667, 1.0, 1.0) + << QColor::fromCmykF(1.0, 1.0, 0.0, 0.0) + << QColor::fromHslF(0.66667, 1.0, 0.5); + + QTest::newRow("cyan") + << QColor::fromRgbF(0.0, 1.0, 1.0) + << QColor::fromHsvF(0.5, 1.0, 1.0) + << QColor::fromCmykF(1.0, 0.0, 0.0, 0.0) + << QColor::fromHslF(0.5, 1.0, 0.5); + + QTest::newRow("magenta") + << QColor::fromRgbF(1.0, 0.0, 1.0) + << QColor::fromHsvF(0.83333, 1.0, 1.0) + << QColor::fromCmykF(0.0, 1.0, 0.0, 0.0) + << QColor::fromHslF(0.83333, 1.0, 0.5); + + QTest::newRow("yellow") + << QColor::fromRgbF(1.0, 1.0, 0.0) + << QColor::fromHsvF(0.16667, 1.0, 1.0) + << QColor::fromCmykF(0.0, 0.0, 1.0, 0.0) + << QColor::fromHslF(0.16667, 1.0, 0.5); + + QTest::newRow("gray") + << QColor::fromRgbF(0.6431375, 0.6431375, 0.6431375) + << QColor::fromHsvF(-1.0, 0.0, 0.6431375) + << QColor::fromCmykF(0.0, 0.0, 0.0, 0.356863) + << QColor::fromHslF(-1.0, 0.0, 0.6431375); + + // ### add colors using the 0-255 functions +} + +void tst_QColor::toRgb() +{ + // invalid should remain invalid + QVERIFY(!QColor().toRgb().isValid()); + + QFETCH(QColor, expectedColor); + QFETCH(QColor, hsvColor); + QFETCH(QColor, cmykColor); + QFETCH(QColor, hslColor); + QCOMPARE(hsvColor.toRgb(), expectedColor); + QCOMPARE(cmykColor.toRgb(), expectedColor); + QCOMPARE(hslColor.toRgb(), expectedColor); + +} + +void tst_QColor::toHsv_data() +{ + QTest::addColumn<QColor>("expectedColor"); + QTest::addColumn<QColor>("rgbColor"); + QTest::addColumn<QColor>("cmykColor"); + QTest::addColumn<QColor>("hslColor"); + + QTest::newRow("data0") + << QColor::fromHsv(300, 255, 255) + << QColor(255, 0, 255) + << QColor::fromCmyk(0, 255, 0, 0) + << QColor::fromHslF(300./360., 1., 0.5, 1.0); + + QTest::newRow("data1") + << QColor::fromHsvF(1., 1., 1., 1.) + << QColor(255, 0, 0, 255) + << QColor::fromCmykF(0., 1., 1., 0.) + << QColor::fromHsvF(1., 1., 1., 1.); +} + +void tst_QColor::toRgbNonDestructive() +{ + QColor aColor = QColor::fromRgbF(0.11, 0.22, 0.33, 0.44); + QCOMPARE(aColor, aColor.toRgb()); +} + +void tst_QColor::toHsv() +{ + // invalid should remain invalid + QVERIFY(!QColor().toHsv().isValid()); + + QFETCH(QColor, expectedColor); + QFETCH(QColor, rgbColor); + QFETCH(QColor, cmykColor); + QFETCH(QColor, hslColor); + QCOMPARE(rgbColor.toHsv(), expectedColor); + QCOMPARE(cmykColor.toHsv(), expectedColor); + QCOMPARE(hslColor.toHsv(), expectedColor); +} + +void tst_QColor::toHsvNonDestructive() +{ + QColor aColor = QColor::fromHsvF(0.11, 0.22, 0.33, 0.44); + QCOMPARE(aColor, aColor.toHsv()); +} + +void tst_QColor::toCmyk_data() +{ + QTest::addColumn<QColor>("expectedColor"); + QTest::addColumn<QColor>("rgbColor"); + QTest::addColumn<QColor>("hsvColor"); + QTest::addColumn<QColor>("hslColor"); + + QTest::newRow("data0") + << QColor::fromCmykF(1.0, 0.0, 0.0, 0.0) + << QColor(0, 255, 255) + << QColor::fromHsv(180, 255, 255) + << QColor::fromHslF(180./360., 1., 0.5, 1.0); + + QTest::newRow("data1") + << QColor::fromCmyk(255, 255, 255, 255) + << QColor::fromRgb(0, 0, 0) + << QColor::fromRgb(0, 0, 0).toHsv() + << QColor::fromRgb(0, 0, 0).toHsl(); +} + +void tst_QColor::toCmyk() +{ + // invalid should remain invalid + QVERIFY(!QColor().toCmyk().isValid()); + + QFETCH(QColor, expectedColor); + QFETCH(QColor, rgbColor); + QFETCH(QColor, hsvColor); + QFETCH(QColor, hslColor); + QCOMPARE(rgbColor.toHsv().toCmyk(), expectedColor); + QCOMPARE(hsvColor.toCmyk(), expectedColor); + QCOMPARE(hslColor.toCmyk(), expectedColor); +} + +void tst_QColor::toCmykNonDestructive() +{ + QColor aColor = QColor::fromCmykF(0.11, 0.22, 0.33, 0.44); + QCOMPARE(aColor, aColor.toCmyk()); +} + +void tst_QColor::toHsl_data() +{ + QTest::addColumn<QColor>("expectedColor"); + QTest::addColumn<QColor>("hsvColor"); + QTest::addColumn<QColor>("rgbColor"); + QTest::addColumn<QColor>("cmykColor"); + + + QTest::newRow("data0") + << QColor::fromHslF(300./360., 1., 0.5, 1.0) + << QColor::fromHsv(300, 255, 255) + << QColor(255, 0, 255) + << QColor::fromCmyk(0, 255, 0, 0); + + QTest::newRow("data1") + << QColor::fromHslF(1., 1., 0.5, 1.0) + << QColor::fromHsvF(1., 1., 1., 1.) + << QColor(255, 0, 0, 255) + << QColor::fromCmykF(0., 1., 1., 0.); +} + +void tst_QColor::toHsl() +{ + // invalid should remain invalid + QVERIFY(!QColor().toHsl().isValid()); + + QFETCH(QColor, expectedColor); + QFETCH(QColor, rgbColor); + QFETCH(QColor, cmykColor); + QFETCH(QColor, hsvColor); + + QCOMPARE(rgbColor.toHsl(), expectedColor); + QCOMPARE(cmykColor.toHsl(), expectedColor); + QCOMPARE(hsvColor.toHsl(), expectedColor); + +} + + +void tst_QColor::toHslNonDestructive() +{ + QColor aColor = QColor::fromHslF(0.11, 0.22, 0.33, 0.44); + QCOMPARE(aColor, aColor.toHsl()); +} + + +void tst_QColor::convertTo() +{ + QColor color(Qt::black); + + QColor rgb = color.convertTo(QColor::Rgb); + QVERIFY(rgb.spec() == QColor::Rgb); + + QColor hsv = color.convertTo(QColor::Hsv); + QVERIFY(hsv.spec() == QColor::Hsv); + + QColor cmyk = color.convertTo(QColor::Cmyk); + QVERIFY(cmyk.spec() == QColor::Cmyk); + + QColor hsl = color.convertTo(QColor::Hsl); + QVERIFY(hsl.spec() == QColor::Hsl); + + QColor invalid = color.convertTo(QColor::Invalid); + QVERIFY(invalid.spec() == QColor::Invalid); + + DEPENDS_ON(toRgb()); + DEPENDS_ON(toHsv()); + DEPENDS_ON(toCmyk()); + DEPENDS_ON(toHsl()); +} + +void tst_QColor::fromRgb() +{ DEPENDS_ON(convertTo()); } + +void tst_QColor::fromHsv() +{ DEPENDS_ON(convertTo()); } + +void tst_QColor::fromCmyk() +{ DEPENDS_ON(convertTo()); } + +void tst_QColor::fromHsl() +{ DEPENDS_ON(convertTo()); } + +void tst_QColor::light() +{ + QColor gray(Qt::gray); + QColor lighter = gray.light(); + QVERIFY(lighter.value() > gray.value()); +} + +void tst_QColor::dark() +{ + QColor gray(Qt::gray); + QColor darker = gray.dark(); + QVERIFY(darker.value() < gray.value()); +} + +void tst_QColor::assignmentOoperator() +{ DEPENDS_ON(convertTo()); } + +void tst_QColor::equalityOperator() +{ DEPENDS_ON(convertTo()); } + +Q_DECLARE_METATYPE(QColor::Spec); + +void tst_QColor::specConstructor_data() +{ + QTest::addColumn<QColor::Spec>("spec"); + + QTest::newRow("Invalid") << QColor::Invalid; + QTest::newRow("Rgb") << QColor::Rgb; + QTest::newRow("Hsv") << QColor::Hsv; + QTest::newRow("Cmyk") << QColor::Cmyk; +} + +void tst_QColor::specConstructor() +{ + QFETCH(QColor::Spec, spec); + QColor color = spec; + QCOMPARE(color.spec(), spec); +} + +void tst_QColor::achromaticHslHue() +{ + QColor color = Qt::black; + + QColor hsl = color.toHsl(); + QCOMPARE(hsl.hslHue(), -1); +} + +#ifdef Q_WS_X11 +void tst_QColor::allowX11ColorNames() +{ + DEPENDS_ON(setallowX11ColorNames()); +} + +void tst_QColor::setallowX11ColorNames() +{ +#if defined(Q_OS_IRIX) + QSKIP("This fails due to the gamma settings in the SGI X server", SkipAll); +#else + RGBData x11RgbTbl[] = { + // a few standard X11 color names + { "DodgerBlue1", qRgb(30, 144, 255) }, + { "DodgerBlue2", qRgb(28, 134, 238) }, + { "DodgerBlue3", qRgb(24, 116, 205) }, + { "DodgerBlue4", qRgb(16, 78, 139) }, + { "SteelBlue1", qRgb(99, 184, 255) }, + { "SteelBlue2", qRgb(92, 172, 238) }, + { "SteelBlue3", qRgb(79, 148, 205) }, + { "SteelBlue4", qRgb(54, 100, 139) }, + { "DeepSkyBlue1", qRgb(0, 191, 255) }, + { "DeepSkyBlue2", qRgb(0, 178, 238) }, + { "DeepSkyBlue3", qRgb(0, 154, 205) }, + { "DeepSkyBlue4", qRgb(0, 104, 139) }, + { "SkyBlue1", qRgb(135, 206, 255) }, + { "SkyBlue2", qRgb(126, 192, 238) }, + { "SkyBlue3", qRgb(108, 166, 205) }, + { "SkyBlue4", qRgb(74, 112, 139) } + }; + static const int x11RgbTblSize = sizeof(x11RgbTbl) / sizeof(RGBData); + + // X11 color names should not work by default + QVERIFY(!QColor::allowX11ColorNames()); + for (int i = 0; i < x11RgbTblSize; ++i) { + QString colorName = QLatin1String(x11RgbTbl[i].name); + QColor color; + color.setNamedColor(colorName); + QVERIFY(!color.isValid()); + } + + // enable X11 color names + QColor::setAllowX11ColorNames(true); + QVERIFY(QColor::allowX11ColorNames()); + for (int i = 0; i < x11RgbTblSize; ++i) { + QString colorName = QLatin1String(x11RgbTbl[i].name); + QColor color; + color.setNamedColor(colorName); + QColor expected(x11RgbTbl[i].value); + QCOMPARE(color, expected); + } + + // should be able to turn off X11 color names + QColor::setAllowX11ColorNames(false); + QVERIFY(!QColor::allowX11ColorNames()); + for (int i = 0; i < x11RgbTblSize; ++i) { + QString colorName = QLatin1String(x11RgbTbl[i].name); + QColor color; + color.setNamedColor(colorName); + QVERIFY(!color.isValid()); + } +#endif // Q_OS_IRIX +} +#endif // Q_WS_X11 + +QTEST_MAIN(tst_QColor) +#include "tst_qcolor.moc" diff --git a/tests/auto/gui/painting/qpaintengine/.gitignore b/tests/auto/gui/painting/qpaintengine/.gitignore new file mode 100644 index 0000000000..e55942ea9f --- /dev/null +++ b/tests/auto/gui/painting/qpaintengine/.gitignore @@ -0,0 +1 @@ +tst_qpaintengine diff --git a/tests/auto/gui/painting/qpaintengine/qpaintengine.pro b/tests/auto/gui/painting/qpaintengine/qpaintengine.pro new file mode 100644 index 0000000000..e37c1668ac --- /dev/null +++ b/tests/auto/gui/painting/qpaintengine/qpaintengine.pro @@ -0,0 +1,9 @@ +############################################################ +# Project file for autotest for file qpaintengine.h +############################################################ + +load(qttest_p4) + +SOURCES += tst_qpaintengine.cpp + + diff --git a/tests/auto/gui/painting/qpaintengine/tst_qpaintengine.cpp b/tests/auto/gui/painting/qpaintengine/tst_qpaintengine.cpp new file mode 100644 index 0000000000..ba9cc62a3d --- /dev/null +++ b/tests/auto/gui/painting/qpaintengine/tst_qpaintengine.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qdebug.h> +#include <qpaintengine.h> +#include <qpixmap.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPaintEngine : public QObject +{ +Q_OBJECT + +public: + tst_QPaintEngine(); + virtual ~tst_QPaintEngine(); + +private slots: + void getSetCheck(); +}; + +tst_QPaintEngine::tst_QPaintEngine() +{ +} + +tst_QPaintEngine::~tst_QPaintEngine() +{ +} + +class MyPaintEngine : public QPaintEngine +{ +public: + MyPaintEngine() : QPaintEngine() {} + bool begin(QPaintDevice *) { return true; } + bool end() { return true; } + void updateState(const QPaintEngineState &) {} + void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {} + Type type() const { return Raster; } +}; + +// Testing get/set functions +void tst_QPaintEngine::getSetCheck() +{ + MyPaintEngine obj1; + // QPaintDevice * QPaintEngine::paintDevice() + // void QPaintEngine::setPaintDevice(QPaintDevice *) + QPixmap *var1 = new QPixmap; + obj1.setPaintDevice(var1); + QCOMPARE((QPaintDevice *)var1, obj1.paintDevice()); + obj1.setPaintDevice((QPaintDevice *)0); + QCOMPARE((QPaintDevice *)0, obj1.paintDevice()); + delete var1; +} + +QTEST_MAIN(tst_QPaintEngine) +#include "tst_qpaintengine.moc" diff --git a/tests/auto/gui/painting/qpainter/.gitignore b/tests/auto/gui/painting/qpainter/.gitignore new file mode 100644 index 0000000000..33e0dbe945 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/.gitignore @@ -0,0 +1,2 @@ +tst_qpainter +foo.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt0x0.png b/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt0x0.png Binary files differnew file mode 100644 index 0000000000..f2ab9a776d --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt0x0.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt100x100.png b/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt100x100.png Binary files differnew file mode 100644 index 0000000000..b1c755b5b0 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt100x100.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt200x200.png b/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt200x200.png Binary files differnew file mode 100644 index 0000000000..0e30498da5 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/10x10SizeAt200x200.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt0x0.png b/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt0x0.png Binary files differnew file mode 100644 index 0000000000..f00796a3ad --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt0x0.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt100x100.png b/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt100x100.png Binary files differnew file mode 100644 index 0000000000..a9a1a8a536 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt100x100.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt200x200.png b/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt200x200.png Binary files differnew file mode 100644 index 0000000000..0e30498da5 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/13x100SizeAt200x200.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt0x0.png b/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt0x0.png Binary files differnew file mode 100644 index 0000000000..67db116b90 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt0x0.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt100x100.png b/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt100x100.png Binary files differnew file mode 100644 index 0000000000..7d32afa4a8 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt100x100.png diff --git a/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt200x200.png b/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt200x200.png Binary files differnew file mode 100644 index 0000000000..0e30498da5 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawEllipse/200x200SizeAt200x200.png diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/dst.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/dst.xbm new file mode 100644 index 0000000000..e645a0b86b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/dst.xbm @@ -0,0 +1,6 @@ +#define dst_width 8 +#define dst_height 8 +static char dst_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0x30,0x00,0x30,0x00, + 0x11,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x10,0x00,0x00, + 0x00,0x11 }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_AndNotROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_AndNotROP.xbm new file mode 100644 index 0000000000..303c799264 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_AndNotROP.xbm @@ -0,0 +1,6 @@ +#define res_AndNotROP_width 8 +#define res_AndNotROP_height 8 +static char res_AndNotROP_bits[] = { + 0xf0,0xf0,0xcc,0xcc,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_AndROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_AndROP.xbm new file mode 100644 index 0000000000..31333de879 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_AndROP.xbm @@ -0,0 +1,6 @@ +#define res_AndROP_width 8 +#define res_AndROP_height 8 +static char res_AndROP_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_ClearROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_ClearROP.xbm new file mode 100644 index 0000000000..9cc25ea147 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_ClearROP.xbm @@ -0,0 +1,6 @@ +#define res_ClearROP_width 8 +#define res_ClearROP_height 8 +static char res_ClearROP_bits[] = { + 0xf0,0xf0,0xc0,0xc0,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_CopyROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_CopyROP.xbm new file mode 100644 index 0000000000..869844dcee --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_CopyROP.xbm @@ -0,0 +1,6 @@ +#define res_CopyROP_width 8 +#define res_CopyROP_height 8 +static char res_CopyROP_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0x35,0x00,0x5a,0x00, + 0x41,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xc0,0x5b,0x2f, + 0x2b,0x50 }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NandROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NandROP.xbm new file mode 100644 index 0000000000..d058484fa8 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NandROP.xbm @@ -0,0 +1,6 @@ +#define res_NandROP_width 8 +#define res_NandROP_height 8 +static char res_NandROP_bits[] = { + 0xf0,0xf0,0xcc,0xcc,0xfc,0xfc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NopROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NopROP.xbm new file mode 100644 index 0000000000..3a2bc23468 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NopROP.xbm @@ -0,0 +1,6 @@ +#define res_NopROP_width 8 +#define res_NopROP_height 8 +static char res_NopROP_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NorROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NorROP.xbm new file mode 100644 index 0000000000..c74be41bbd --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NorROP.xbm @@ -0,0 +1,6 @@ +#define res_NorROP_width 8 +#define res_NorROP_height 8 +static char res_NorROP_bits[] = { + 0xf0,0xf0,0xc0,0xc0,0xcc,0xcc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotAndROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotAndROP.xbm new file mode 100644 index 0000000000..0cf8c3a82c --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotAndROP.xbm @@ -0,0 +1,6 @@ +#define res_NotAndROP_width 8 +#define res_NotAndROP_height 8 +static char res_NotAndROP_bits[] = { + 0xf0,0xf0,0xc0,0xc0,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotCopyROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotCopyROP.xbm new file mode 100644 index 0000000000..65474e16c5 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotCopyROP.xbm @@ -0,0 +1,6 @@ +#define res_NotCopyROP_width 8 +#define res_NotCopyROP_height 8 +static char res_NotCopyROP_bits[] = { + 0xf0,0xf0,0xc0,0xc0,0xfc,0xfc,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotOrROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotOrROP.xbm new file mode 100644 index 0000000000..144d8995b6 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotOrROP.xbm @@ -0,0 +1,6 @@ +#define res_NotOrROP_width 8 +#define res_NotOrROP_height 8 +static char res_NotOrROP_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xfc,0xfc,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotROP.xbm new file mode 100644 index 0000000000..ccb3d36fb4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotROP.xbm @@ -0,0 +1,6 @@ +#define res_NotROP_width 8 +#define res_NotROP_height 8 +static char res_NotROP_bits[] = { + 0xf0,0xf0,0xcc,0xcc,0xcc,0xcc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotXorROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotXorROP.xbm new file mode 100644 index 0000000000..4be8f51a80 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_NotXorROP.xbm @@ -0,0 +1,6 @@ +#define res_NotXorROP_width 8 +#define res_NotXorROP_height 8 +static char res_NotXorROP_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xcc,0xcc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_OrNotROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_OrNotROP.xbm new file mode 100644 index 0000000000..d53fbe00e1 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_OrNotROP.xbm @@ -0,0 +1,6 @@ +#define res_OrNotROP_width 8 +#define res_OrNotROP_height 8 +static char res_OrNotROP_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xcc,0xcc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_OrROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_OrROP.xbm new file mode 100644 index 0000000000..06b51fcc68 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_OrROP.xbm @@ -0,0 +1,6 @@ +#define res_OrROP_width 8 +#define res_OrROP_height 8 +static char res_OrROP_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_SetROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_SetROP.xbm new file mode 100644 index 0000000000..ab42472bb0 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_SetROP.xbm @@ -0,0 +1,6 @@ +#define res_SetROP_width 8 +#define res_SetROP_height 8 +static char res_SetROP_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xfc,0xfc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_XorROP.xbm b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_XorROP.xbm new file mode 100644 index 0000000000..5ac892dd0b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawLine_rop_bitmap/res/res_XorROP.xbm @@ -0,0 +1,6 @@ +#define res_XorROP_width 8 +#define res_XorROP_height 8 +static char res_XorROP_bits[] = { + 0xf0,0xf0,0xcc,0xcc,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst1.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst2.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst3.png Binary files differnew file mode 100644 index 0000000000..8a3d28f3ed --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/dst3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP0.png Binary files differnew file mode 100644 index 0000000000..fe017ac1ab --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP1.png Binary files differnew file mode 100644 index 0000000000..82d938c023 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP2.png Binary files differnew file mode 100644 index 0000000000..2b67b928e4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP3.png Binary files differnew file mode 100644 index 0000000000..c95b5a10ba --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP4.png Binary files differnew file mode 100644 index 0000000000..bbe2a24530 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP5.png Binary files differnew file mode 100644 index 0000000000..0158278b84 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP6.png Binary files differnew file mode 100644 index 0000000000..aa1f403075 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP7.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndNotROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP0.png Binary files differnew file mode 100644 index 0000000000..ebf8244eee --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP1.png Binary files differnew file mode 100644 index 0000000000..88568bc330 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP2.png Binary files differnew file mode 100644 index 0000000000..0ed6de2865 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP3.png Binary files differnew file mode 100644 index 0000000000..c2ff341e6b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP4.png Binary files differnew file mode 100644 index 0000000000..e08c9acbe2 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP5.png Binary files differnew file mode 100644 index 0000000000..e9d7a57333 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP6.png Binary files differnew file mode 100644 index 0000000000..01438a195c --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP7.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_AndROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP0.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP1.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP2.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP3.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP4.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP5.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP6.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP7.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_ClearROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP0.png Binary files differnew file mode 100644 index 0000000000..587623d3e8 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP1.png Binary files differnew file mode 100644 index 0000000000..10e7ae59d5 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP2.png Binary files differnew file mode 100644 index 0000000000..5c14136eb4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP3.png Binary files differnew file mode 100644 index 0000000000..207f52564b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP4.png Binary files differnew file mode 100644 index 0000000000..6981cee080 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP5.png Binary files differnew file mode 100644 index 0000000000..8b8de9892a --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP6.png Binary files differnew file mode 100644 index 0000000000..9825c0539f --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP7.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_CopyROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP0.png Binary files differnew file mode 100644 index 0000000000..8d26638c03 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP1.png Binary files differnew file mode 100644 index 0000000000..f5b33589ba --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP2.png Binary files differnew file mode 100644 index 0000000000..adc4ee3701 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP3.png Binary files differnew file mode 100644 index 0000000000..dccc94c43b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP4.png Binary files differnew file mode 100644 index 0000000000..4d207e7968 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP5.png Binary files differnew file mode 100644 index 0000000000..aa93d4d4a4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP6.png Binary files differnew file mode 100644 index 0000000000..ad320f950b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP7.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NandROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP0.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP1.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP2.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP3.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP4.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP5.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP6.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP7.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NopROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP0.png Binary files differnew file mode 100644 index 0000000000..3e33bb1078 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP1.png Binary files differnew file mode 100644 index 0000000000..ce2b6f4e15 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP2.png Binary files differnew file mode 100644 index 0000000000..9eddc9840b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP3.png Binary files differnew file mode 100644 index 0000000000..4ea9669dd3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP4.png Binary files differnew file mode 100644 index 0000000000..c64e0a5630 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP5.png Binary files differnew file mode 100644 index 0000000000..1fe3def383 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP6.png Binary files differnew file mode 100644 index 0000000000..9c294b04d9 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP7.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NorROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP0.png Binary files differnew file mode 100644 index 0000000000..01c694cdcc --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP1.png Binary files differnew file mode 100644 index 0000000000..4b11aa9c41 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP2.png Binary files differnew file mode 100644 index 0000000000..accbe42112 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP3.png Binary files differnew file mode 100644 index 0000000000..3c58d4fac7 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP4.png Binary files differnew file mode 100644 index 0000000000..3b0a41c396 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP5.png Binary files differnew file mode 100644 index 0000000000..045ef33012 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP6.png Binary files differnew file mode 100644 index 0000000000..3a83725938 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP7.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotAndROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP0.png Binary files differnew file mode 100644 index 0000000000..7c51fc16fa --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP1.png Binary files differnew file mode 100644 index 0000000000..8f519e8c52 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP2.png Binary files differnew file mode 100644 index 0000000000..a0f9f60653 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP3.png Binary files differnew file mode 100644 index 0000000000..95931a4317 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP4.png Binary files differnew file mode 100644 index 0000000000..f825d523b0 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP5.png Binary files differnew file mode 100644 index 0000000000..245a27ea2f --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP6.png Binary files differnew file mode 100644 index 0000000000..b32020675b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP7.png Binary files differnew file mode 100644 index 0000000000..cff8926587 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotCopyROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP0.png Binary files differnew file mode 100644 index 0000000000..3622f3a2b1 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP1.png Binary files differnew file mode 100644 index 0000000000..e31793e4a3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP2.png Binary files differnew file mode 100644 index 0000000000..8e8237548b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP3.png Binary files differnew file mode 100644 index 0000000000..f4b98914b4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP4.png Binary files differnew file mode 100644 index 0000000000..b14fdba341 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP5.png Binary files differnew file mode 100644 index 0000000000..129d7f3dc6 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP6.png Binary files differnew file mode 100644 index 0000000000..d894c5cb68 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP7.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotOrROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP0.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP1.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP2.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP3.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP4.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP5.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP6.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP7.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP0.png Binary files differnew file mode 100644 index 0000000000..b1e61504cd --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP1.png Binary files differnew file mode 100644 index 0000000000..8cf29cde81 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP2.png Binary files differnew file mode 100644 index 0000000000..99fedf8c04 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP3.png Binary files differnew file mode 100644 index 0000000000..bc220f546e --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP4.png Binary files differnew file mode 100644 index 0000000000..f48e8b9f4d --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP5.png Binary files differnew file mode 100644 index 0000000000..c5e3c0fc63 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP6.png Binary files differnew file mode 100644 index 0000000000..13bb69f91b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP7.png Binary files differnew file mode 100644 index 0000000000..4a7ca7f9b3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_NotXorROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP0.png Binary files differnew file mode 100644 index 0000000000..85b964301d --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP1.png Binary files differnew file mode 100644 index 0000000000..d92bf16044 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP2.png Binary files differnew file mode 100644 index 0000000000..bb81c5abe8 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP3.png Binary files differnew file mode 100644 index 0000000000..9378f166cd --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP4.png Binary files differnew file mode 100644 index 0000000000..2ea026eb6c --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP5.png Binary files differnew file mode 100644 index 0000000000..8366d37eda --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP6.png Binary files differnew file mode 100644 index 0000000000..39c36d1b52 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP7.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrNotROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP0.png Binary files differnew file mode 100644 index 0000000000..beb2bc35b8 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP1.png Binary files differnew file mode 100644 index 0000000000..6ed17a72ed --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP2.png Binary files differnew file mode 100644 index 0000000000..9e0b63c220 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP3.png Binary files differnew file mode 100644 index 0000000000..6471b4aaa4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP4.png Binary files differnew file mode 100644 index 0000000000..c158ea0d01 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP5.png Binary files differnew file mode 100644 index 0000000000..eb3deacc86 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP6.png Binary files differnew file mode 100644 index 0000000000..51948b0ac9 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP7.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_OrROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP0.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP1.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP2.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP3.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP4.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP5.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP6.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP7.png Binary files differnew file mode 100644 index 0000000000..00968ffd06 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_SetROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP0.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP0.png Binary files differnew file mode 100644 index 0000000000..c2b009cac3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP0.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP1.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP1.png Binary files differnew file mode 100644 index 0000000000..42b0b3c308 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP1.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP2.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP2.png Binary files differnew file mode 100644 index 0000000000..bc43614ab3 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP2.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP3.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP3.png Binary files differnew file mode 100644 index 0000000000..7486d4b3f4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP3.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP4.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP4.png Binary files differnew file mode 100644 index 0000000000..8098634be4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP4.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP5.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP5.png Binary files differnew file mode 100644 index 0000000000..8c5b9feb7c --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP5.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP6.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP6.png Binary files differnew file mode 100644 index 0000000000..c7e51a1410 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP6.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP7.png b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP7.png Binary files differnew file mode 100644 index 0000000000..8605b64d93 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/res/res_XorROP7.png diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/src1.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop/src1.xbm new file mode 100644 index 0000000000..f088d28c8c --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/src1.xbm @@ -0,0 +1,12 @@ +#define src1_width 32 +#define src1_height 32 +static char src1_bits[] = { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/src2-mask.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop/src2-mask.xbm new file mode 100644 index 0000000000..bd73f9433c --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/src2-mask.xbm @@ -0,0 +1,16 @@ +#define src2_width 32 +#define src2_height 48 +static char src2_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/src2.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop/src2.xbm new file mode 100644 index 0000000000..40126a9d17 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/src2.xbm @@ -0,0 +1,16 @@ +#define src2_width 32 +#define src2_height 48 +static char src2_bits[] = { + 0xa7,0x01,0xc0,0x03,0x40,0x9b,0x80,0x08,0x18,0x00,0x00,0x00,0x48,0x00,0x00, + 0x00,0xbb,0xbb,0xbb,0xbb,0xee,0xee,0xee,0xee,0x00,0x00,0x00,0x00,0xfe,0xff, + 0xff,0xff,0x0d,0x00,0x0d,0x00,0x20,0x00,0x20,0x00,0x80,0xed,0xb7,0x08,0xe8, + 0x61,0x54,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x68,0xa2,0x02, + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop/src3.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop/src3.xbm new file mode 100644 index 0000000000..2f2d5472a4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop/src3.xbm @@ -0,0 +1,12 @@ +#define src3_width 32 +#define src3_height 32 +static char src3_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/dst.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/dst.xbm new file mode 100644 index 0000000000..45543c8ebf --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/dst.xbm @@ -0,0 +1,6 @@ +#define dst_width 8 +#define dst_height 8 +static char dst_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xb1,0x00,0x00,0x00,0x70,0xe6,0x6e,0x2b,0x70,0xe6,0x6e,0x2b,0x24,0x00,0x00, + 0x00,0x81 }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_AndNotROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_AndNotROP.xbm new file mode 100644 index 0000000000..303c799264 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_AndNotROP.xbm @@ -0,0 +1,6 @@ +#define res_AndNotROP_width 8 +#define res_AndNotROP_height 8 +static char res_AndNotROP_bits[] = { + 0xf0,0xf0,0xcc,0xcc,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_AndROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_AndROP.xbm new file mode 100644 index 0000000000..31333de879 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_AndROP.xbm @@ -0,0 +1,6 @@ +#define res_AndROP_width 8 +#define res_AndROP_height 8 +static char res_AndROP_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_ClearROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_ClearROP.xbm new file mode 100644 index 0000000000..9cc25ea147 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_ClearROP.xbm @@ -0,0 +1,6 @@ +#define res_ClearROP_width 8 +#define res_ClearROP_height 8 +static char res_ClearROP_bits[] = { + 0xf0,0xf0,0xc0,0xc0,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_CopyROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_CopyROP.xbm new file mode 100644 index 0000000000..869844dcee --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_CopyROP.xbm @@ -0,0 +1,6 @@ +#define res_CopyROP_width 8 +#define res_CopyROP_height 8 +static char res_CopyROP_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0x35,0x00,0x5a,0x00, + 0x41,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xc0,0x5b,0x2f, + 0x2b,0x50 }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NandROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NandROP.xbm new file mode 100644 index 0000000000..d058484fa8 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NandROP.xbm @@ -0,0 +1,6 @@ +#define res_NandROP_width 8 +#define res_NandROP_height 8 +static char res_NandROP_bits[] = { + 0xf0,0xf0,0xcc,0xcc,0xfc,0xfc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NopROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NopROP.xbm new file mode 100644 index 0000000000..3a2bc23468 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NopROP.xbm @@ -0,0 +1,6 @@ +#define res_NopROP_width 8 +#define res_NopROP_height 8 +static char res_NopROP_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NorROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NorROP.xbm new file mode 100644 index 0000000000..c74be41bbd --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NorROP.xbm @@ -0,0 +1,6 @@ +#define res_NorROP_width 8 +#define res_NorROP_height 8 +static char res_NorROP_bits[] = { + 0xf0,0xf0,0xc0,0xc0,0xcc,0xcc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotAndROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotAndROP.xbm new file mode 100644 index 0000000000..0cf8c3a82c --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotAndROP.xbm @@ -0,0 +1,6 @@ +#define res_NotAndROP_width 8 +#define res_NotAndROP_height 8 +static char res_NotAndROP_bits[] = { + 0xf0,0xf0,0xc0,0xc0,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotCopyROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotCopyROP.xbm new file mode 100644 index 0000000000..65474e16c5 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotCopyROP.xbm @@ -0,0 +1,6 @@ +#define res_NotCopyROP_width 8 +#define res_NotCopyROP_height 8 +static char res_NotCopyROP_bits[] = { + 0xf0,0xf0,0xc0,0xc0,0xfc,0xfc,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotOrROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotOrROP.xbm new file mode 100644 index 0000000000..144d8995b6 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotOrROP.xbm @@ -0,0 +1,6 @@ +#define res_NotOrROP_width 8 +#define res_NotOrROP_height 8 +static char res_NotOrROP_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xfc,0xfc,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotROP.xbm new file mode 100644 index 0000000000..ccb3d36fb4 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotROP.xbm @@ -0,0 +1,6 @@ +#define res_NotROP_width 8 +#define res_NotROP_height 8 +static char res_NotROP_bits[] = { + 0xf0,0xf0,0xcc,0xcc,0xcc,0xcc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotXorROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotXorROP.xbm new file mode 100644 index 0000000000..4be8f51a80 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_NotXorROP.xbm @@ -0,0 +1,6 @@ +#define res_NotXorROP_width 8 +#define res_NotXorROP_height 8 +static char res_NotXorROP_bits[] = { + 0xf0,0xf0,0xf0,0xf0,0xcc,0xcc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_OrNotROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_OrNotROP.xbm new file mode 100644 index 0000000000..d53fbe00e1 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_OrNotROP.xbm @@ -0,0 +1,6 @@ +#define res_OrNotROP_width 8 +#define res_OrNotROP_height 8 +static char res_OrNotROP_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xcc,0xcc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_OrROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_OrROP.xbm new file mode 100644 index 0000000000..06b51fcc68 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_OrROP.xbm @@ -0,0 +1,6 @@ +#define res_OrROP_width 8 +#define res_OrROP_height 8 +static char res_OrROP_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0xff,0xff,0xff,0x7f, + 0xff,0xff,0xff,0x7f,0x50,0x00,0x00,0x00,0x09,0x02,0x00,0x00,0xff,0xff,0xff, + 0x7f,0xff }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_SetROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_SetROP.xbm new file mode 100644 index 0000000000..ab42472bb0 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_SetROP.xbm @@ -0,0 +1,6 @@ +#define res_SetROP_width 8 +#define res_SetROP_height 8 +static char res_SetROP_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xfc,0xfc,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_XorROP.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_XorROP.xbm new file mode 100644 index 0000000000..5ac892dd0b --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/res/res_XorROP.xbm @@ -0,0 +1,6 @@ +#define res_XorROP_width 8 +#define res_XorROP_height 8 +static char res_XorROP_bits[] = { + 0xf0,0xf0,0xcc,0xcc,0xf0,0xf0,0xf0,0xf0,0x00,0x00,0x00,0x62,0x00,0x6d,0x00, + 0x00,0xb5,0x7a,0x2b,0x50,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x42,0x55,0x53, + 0x59,0x3a }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src1-mask.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src1-mask.xbm new file mode 100644 index 0000000000..ac9031f1f1 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src1-mask.xbm @@ -0,0 +1,6 @@ +#define src1_width 8 +#define src1_height 8 +static char src1_bits[] = { + 0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00, + 0x59,0x00,0x00,0x00,0x18,0xe6,0x6e,0x2b,0x18,0xe6,0x6e,0x2b,0x00,0x00,0x00, + 0x00,0x49 }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src1.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src1.xbm new file mode 100644 index 0000000000..d883569db2 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src1.xbm @@ -0,0 +1,6 @@ +#define src1_width 8 +#define src1_height 8 +static char src1_bits[] = { + 0xf0,0xf0,0xfc,0xfc,0xc0,0xc0,0xf0,0xf0,0x00,0x00,0x00,0xe0,0xe5,0x6e,0x2b, + 0x29,0x00,0x00,0x00,0xe8,0xe5,0x6e,0x2b,0xe8,0xe5,0x6e,0x2b,0x3c,0x00,0x00, + 0x05,0x3c }; diff --git a/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src2.xbm b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src2.xbm new file mode 100644 index 0000000000..fb203df28a --- /dev/null +++ b/tests/auto/gui/painting/qpainter/drawPixmap_rop_bitmap/src2.xbm @@ -0,0 +1,5 @@ +#define src2_width 4 +#define src2_height 4 +static char src2_bits[] = { + 0x0f,0x5f,0x40,0x00,0x00,0x00,0x00,0x2d,0x00,0x39,0x00,0x5f,0x00,0x5d,0x00, + 0x30 }; diff --git a/tests/auto/gui/painting/qpainter/qpainter.pro b/tests/auto/gui/painting/qpainter/qpainter.pro new file mode 100644 index 0000000000..00307d3e58 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/qpainter.pro @@ -0,0 +1,20 @@ +load(qttest_p4) + +QT += widgets widgets-private printsupport + +SOURCES += tst_qpainter.cpp +wince*|symbian: { + addFiles.files = drawEllipse drawLine_rop_bitmap drawPixmap_rop drawPixmap_rop_bitmap task217400.png + addFiles.path = . + DEPLOYMENT += addFiles +} + +wince* { + DEFINES += SRCDIR=\\\".\\\" +} else:!symbian { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} + + +mac*:CONFIG+=insignificant_test +contains(QT_CONFIG,xcb):qpa:CONFIG+=insignificant_test # QTBUG-20756 crashes on qpa, xcb diff --git a/tests/auto/gui/painting/qpainter/task217400.png b/tests/auto/gui/painting/qpainter/task217400.png Binary files differnew file mode 100644 index 0000000000..c12a602ba6 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/task217400.png diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp new file mode 100644 index 0000000000..c2c9002023 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -0,0 +1,4697 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include "../../../../shared/util.h" + +#include <qpainter.h> +#include <qapplication.h> +#include <qwidget.h> +#include <qfontmetrics.h> +#include <qbitmap.h> +#include <qimage.h> +#include <qthread.h> +#include <limits.h> +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) +#include <qprinter.h> +#include <math.h> +#endif +#include <qpaintengine.h> +#include <qdesktopwidget.h> +#include <qpixmap.h> + +#include <qpainter.h> + +#include <qlabel.h> + +#include <qqueue.h> + +#include <qgraphicsview.h> +#include <qgraphicsscene.h> +#include <qgraphicsproxywidget.h> +#include <qlayout.h> +#include <qfontdatabase.h> + +#if defined(Q_OS_SYMBIAN) +# define SRCDIR "." +#endif + +Q_DECLARE_METATYPE(QGradientStops) +Q_DECLARE_METATYPE(QLine) +Q_DECLARE_METATYPE(QRect) +Q_DECLARE_METATYPE(QSize) +Q_DECLARE_METATYPE(QPoint) +Q_DECLARE_METATYPE(QPainterPath) + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPainter : public QObject +{ +Q_OBJECT + +public: + tst_QPainter(); + virtual ~tst_QPainter(); + + +public slots: + void init(); + void cleanup(); +private slots: + void getSetCheck(); + void qt_format_text_clip(); + void qt_format_text_boundingRect(); + void drawPixmap_comp_data(); + void drawPixmap_comp(); + void saveAndRestore_data(); + void saveAndRestore(); + + void drawBorderPixmap(); + void drawPixmapFragments(); + + void drawLine_data(); + void drawLine(); + void drawLine_clipped(); + void drawLine_task121143(); + void drawLine_task216948(); + + void drawLine_task190634(); + void drawLine_task229459(); + void drawLine_task234891(); + + void drawRect_data() { fillData(); } + void drawRect(); + void drawRect2(); + + void fillRect(); + void fillRect2(); + void fillRect3(); + void fillRect4(); + + void drawEllipse_data(); + void drawEllipse(); + void drawClippedEllipse_data(); + void drawClippedEllipse(); + + void drawPath_data(); + void drawPath(); + void drawPath2(); + void drawPath3(); + + void drawRoundRect_data() { fillData(); } + void drawRoundRect(); + + void qimageFormats_data(); + void qimageFormats(); + void textOnTransparentImage(); + + void initFrom(); + + void setWindow(); + + void combinedMatrix(); + void renderHints(); + + void disableEnableClipping(); + void setClipRect(); + void setEqualClipRegionAndPath_data(); + void setEqualClipRegionAndPath(); + + void clipRectSaveRestore(); + + void clippedFillPath_data(); + void clippedFillPath(); + void clippedLines_data(); + void clippedLines(); + void clippedPolygon_data(); + void clippedPolygon(); + + void clippedText(); + + void clipBoundingRect(); + + void setOpacity_data(); + void setOpacity(); + + void drawhelper_blend_untransformed_data(); + void drawhelper_blend_untransformed(); + void drawhelper_blend_tiled_untransformed_data(); + void drawhelper_blend_tiled_untransformed(); + + void porterDuff_warning(); + + void drawhelper_blend_color(); + + void childWidgetViewport(); + + void fillRect_objectBoundingModeGradient(); + void fillRect_stretchToDeviceMode(); + void monoImages(); + + void linearGradientSymmetry_data(); + void linearGradientSymmetry(); + void gradientInterpolation(); + + void fpe_pixmapTransform(); + void fpe_zeroLengthLines(); + void fpe_divByZero(); + + void fpe_steepSlopes_data(); + void fpe_steepSlopes(); + void fpe_rasterizeLine_task232012(); + + void fpe_radialGradients(); + + void rasterizer_asserts(); + void rasterizer_negativeCoords(); + + void blendOverFlow_data(); + void blendOverFlow(); + + void largeImagePainting_data(); + void largeImagePainting(); + + void imageScaling_task206785(); + + void outlineFillConsistency(); + + void drawImage_task217400_data(); + void drawImage_task217400(); + void drawImage_1x1(); + void drawImage_task258776(); + void drawRect_task215378(); + void drawRect_task247505(); + + void drawText_subPixelPositionsInRaster_qtbug5053(); + + void drawImage_data(); + void drawImage(); + + void clippedImage(); + + void stateResetBetweenQPainters(); + + void imageCoordinateLimit(); + void imageBlending_data(); + void imageBlending(); + void imageBlending_clipped(); + + void paintOnNullPixmap(); + void checkCompositionMode(); + + void drawPolygon(); + + void inactivePainter(); + + void extendedBlendModes(); + + void zeroOpacity(); + void clippingBug(); + void emptyClip(); + + void taskQT4444_dontOverflowDashOffset(); + + void painterBegin(); + void setPenColorOnImage(); + void setPenColorOnPixmap(); + + void QTBUG5939_attachPainterPrivate(); + + void drawPointScaled(); + + void QTBUG14614_gradientCacheRaceCondition(); + void drawTextOpacity(); + + void QTBUG17053_zeroDashPattern(); + + void drawTextOutsideGuiThread(); + +private: + void fillData(); + void setPenColor(QPainter& p); + QColor baseColor( int k, int intensity=255 ); + QImage getResImage( const QString &dir, const QString &addition, const QString &extension ); + QBitmap getBitmap( const QString &dir, const QString &filename, bool mask ); +}; + +// Testing get/set functions +void tst_QPainter::getSetCheck() +{ + QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied); + QPainter obj1; + obj1.begin(&img); + // CompositionMode QPainter::compositionMode() + // void QPainter::setCompositionMode(CompositionMode) + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceOver)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceOver), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOver)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOver), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Clear)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Clear), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Source)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Source), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Destination)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Destination), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceIn)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceIn), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationIn)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationIn), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceOut)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceOut), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOut)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOut), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceAtop)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceAtop), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationAtop)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationAtop), obj1.compositionMode()); + obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Xor)); + QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Xor), obj1.compositionMode()); + + // const QPen & QPainter::pen() + // void QPainter::setPen(const QPen &) + QPen var3(Qt::red); + obj1.setPen(var3); + QCOMPARE(var3, obj1.pen()); + obj1.setPen(QPen()); + QCOMPARE(QPen(), obj1.pen()); + + // const QBrush & QPainter::brush() + // void QPainter::setBrush(const QBrush &) + QBrush var4(Qt::red); + obj1.setBrush(var4); + QCOMPARE(var4, obj1.brush()); + obj1.setBrush(QBrush()); + QCOMPARE(QBrush(), obj1.brush()); + + // const QBrush & QPainter::background() + // void QPainter::setBackground(const QBrush &) + QBrush var5(Qt::yellow); + obj1.setBackground(var5); + QCOMPARE(var5, obj1.background()); + obj1.setBackground(QBrush()); + QCOMPARE(QBrush(), obj1.background()); + + // bool QPainter::matrixEnabled() + // void QPainter::setMatrixEnabled(bool) + obj1.setMatrixEnabled(false); + QCOMPARE(false, obj1.matrixEnabled()); + obj1.setMatrixEnabled(true); + QCOMPARE(true, obj1.matrixEnabled()); + + // bool QPainter::viewTransformEnabled() + // void QPainter::setViewTransformEnabled(bool) + obj1.setViewTransformEnabled(false); + QCOMPARE(false, obj1.viewTransformEnabled()); + obj1.setViewTransformEnabled(true); + QCOMPARE(true, obj1.viewTransformEnabled()); +} + +Q_DECLARE_METATYPE(QPixmap) +Q_DECLARE_METATYPE(QPolygon) +Q_DECLARE_METATYPE(QBrush) +Q_DECLARE_METATYPE(QPen) +Q_DECLARE_METATYPE(QFont) +Q_DECLARE_METATYPE(QColor) +Q_DECLARE_METATYPE(QRegion) + +tst_QPainter::tst_QPainter() +{ + // QtTestCase sets this to false, but this turns off alpha pixmaps on Unix. + QApplication::setDesktopSettingsAware(TRUE); +} + +tst_QPainter::~tst_QPainter() +{ +} + +void tst_QPainter::init() +{ +} + +void tst_QPainter::cleanup() +{ +} + +/* tests the clipping operations in qt_format_text, making sure + the clip rectangle after the call is the same as before +*/ +void tst_QPainter::qt_format_text_clip() +{ + QVERIFY(1); + QSKIP( "Needs fixing...", SkipAll); + + QWidget *w = new QWidget( 0 ); + + int modes[] = { Qt::AlignVCenter|Qt::TextSingleLine, + Qt::AlignVCenter|Qt::TextSingleLine|Qt::TextDontClip, + Qt::AlignVCenter|Qt::TextWordWrap, + Qt::AlignVCenter|Qt::TextWordWrap|Qt::TextDontClip, + 0 + }; + + int *m = modes; + while( *m ) { + { + QPainter p( w ); + QRegion clipreg = p.clipRegion(); + bool hasClipping = p.hasClipping(); + qreal tx = p.matrix().dx(); + qreal ty = p.matrix().dy(); + + p.drawText( 10, 10, 100, 100, *m, + "fooo" ); + + QVERIFY( clipreg == p.clipRegion() ); + QVERIFY( hasClipping == p.hasClipping() ); + QCOMPARE( tx, p.matrix().dx() ); + QCOMPARE( ty, p.matrix().dy() ); + + p.setClipRect( QRect( 5, 5, 50, 50 ) ); + clipreg = p.clipRegion(); + hasClipping = p.hasClipping(); + + p.drawText( 10, 10, 100, 100, *m, + "fooo" ); + + QVERIFY( clipreg == p.clipRegion() ); + QVERIFY( hasClipping == p.hasClipping() ); + QCOMPARE( tx, p.matrix().dx() ); + QCOMPARE( ty, p.matrix().dy() ); + } + { + QPainter p( w ); + p.setMatrix( QMatrix( 2, 1, 3, 4, 5, 6 ) ); + QRegion clipreg = p.clipRegion(); + bool hasClipping = p.hasClipping(); + qreal tx = p.matrix().dx(); + qreal ty = p.matrix().dy(); + + p.drawText( 10, 10, 100, 100, *m, + "fooo" ); + + QVERIFY( clipreg == p.clipRegion() ); + QVERIFY( hasClipping == p.hasClipping() ); + QCOMPARE( tx, p.matrix().dx() ); + QCOMPARE( ty, p.matrix().dy() ); + + p.setClipRect( QRect( 5, 5, 50, 50 ) ); + clipreg = p.clipRegion(); + hasClipping = p.hasClipping(); + + p.drawText( 10, 10, 100, 100, *m, + "fooo" ); + + QVERIFY( clipreg == p.clipRegion() ); + QVERIFY( hasClipping == p.hasClipping() ); + QCOMPARE( tx, p.matrix().dx() ); + QCOMPARE( ty, p.matrix().dy() ); + } + { + QPainter p( w ); + QRegion clipreg = p.clipRegion(); + bool hasClipping = p.hasClipping(); + qreal tx = p.matrix().dx(); + qreal ty = p.matrix().dy(); + + p.drawText( 10, 10, 100, 100, *m, + "fooo" ); + + QVERIFY( clipreg == p.clipRegion() ); + QVERIFY( hasClipping == p.hasClipping() ); + QCOMPARE( tx, p.matrix().dx() ); + QCOMPARE( ty, p.matrix().dy() ); + + p.setClipRect( QRect( 5, 5, 50, 50 )); + clipreg = p.clipRegion(); + hasClipping = p.hasClipping(); + + p.drawText( 10, 10, 100, 100, *m, + "fooo" ); + + QVERIFY( clipreg == p.clipRegion() ); + QVERIFY( hasClipping == p.hasClipping() ); + QCOMPARE( tx, p.matrix().dx() ); + QCOMPARE( ty, p.matrix().dy() ); + } + { + QPainter p( w ); + p.setMatrix( QMatrix( 2, 1, 3, 4, 5, 6 ) ); + QRegion clipreg = p.clipRegion(); + bool hasClipping = p.hasClipping(); + qreal tx = p.matrix().dx(); + qreal ty = p.matrix().dy(); + + p.drawText( 10, 10, 100, 100, *m, + "fooo" ); + + QVERIFY( clipreg == p.clipRegion() ); + QVERIFY( hasClipping == p.hasClipping() ); + QCOMPARE( tx, p.matrix().dx() ); + QCOMPARE( ty, p.matrix().dy() ); + + p.setClipRect(QRect( 5, 5, 50, 50 )); + clipreg = p.clipRegion(); + hasClipping = p.hasClipping(); + + p.drawText( 10, 10, 100, 100, *m, + "fooo" ); + + QVERIFY( clipreg == p.clipRegion() ); + QVERIFY( hasClipping == p.hasClipping() ); + QCOMPARE( tx, p.matrix().dx() ); + QCOMPARE( ty, p.matrix().dy() ); + } + ++m; + } + delete w; +} + +/* tests the bounding rect calculations in qt_format_text, making sure + the bounding rect has a reasonable value. +*/ +void tst_QPainter::qt_format_text_boundingRect() +{ + QVERIFY(1); + QSKIP( "Needs fixing...", SkipAll); + + { + const char * strings[] = { + "a\n\nb", + "abc", + "a\n \nb", + "this is a longer string", + "\327\222\327\223\327\233\327\223\327\222\327\233\327\222\327\223\327\233", + "aa\327\222\327\233aa", + "\327\222\327\223\327\233\327\223\327\222\327\233\327\222\327\223\327\233", + "\327\222\327\233aa", + "linebreakatend\n", + "some text longer than 30 chars with a line break at the end\n", + "some text\nwith line breaks\nin the middle\nand at the end\n", + "foo\n\n\nfoo", + 0 + }; + + int modes[] = { Qt::AlignVCenter|Qt::TextSingleLine, + Qt::AlignVCenter|Qt::TextSingleLine|Qt::TextDontClip, + Qt::AlignVCenter|Qt::TextWordWrap, + Qt::AlignVCenter|Qt::TextWordWrap|Qt::TextDontClip, + Qt::AlignLeft, + Qt::AlignCenter, + Qt::AlignRight, + 0 + }; + + QFont f; + for(int i = 5; i < 15; ++i) { + f.setPointSize(i); + QFontMetrics fm(f); + const char **str = strings; + while( *str ) { + int *m = modes; + while( *m ) { + QRect br = fm.boundingRect( 0, 0, 2000, 100, *m, QString::fromUtf8( *str ) ); + QVERIFY( br.width() < 800 ); + + QRect br2 = fm.boundingRect( br.x(), br.y(), br.width(), br.height(), *m, QString::fromUtf8( *str ) ); + QCOMPARE( br, br2 ); +#if 0 + { + QPrinter printer; + printer.setOutputToFile(TRUE); + printer.setOutputFileName("tmp.prn"); + QPainter p(&printer); + QRect pbr = p.fontMetrics().boundingRect( 0, 0, 2000, 100, *m, QString::fromUtf8( *str ) ); + QCOMPARE(pbr, br); + } +#endif +#if !defined(QT_NO_PRINTER) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + { + QPrinter printer(QPrinter::HighResolution); + if (printer.printerName().isEmpty()) { + QSKIP( "No printers installed, skipping bounding rect test", + SkipSingle ); + break; + } + + printer.setOutputFileName("tmp.prn"); + QPainter p(&printer); + QRect pbr = p.fontMetrics().boundingRect( 0, 0, 12000, 600, *m, QString::fromUtf8( *str ) ); + QVERIFY(pbr.width() > 2*br.width()); + QVERIFY(pbr.height() > 2*br.height()); + } +#endif + ++m; + } + ++str; + } + } + } + + { + const char * strings[] = { + "a", + "a\nb", + "a\n\nb", + "abc", +// "a\n \nb", + "this is a longer string", +// "\327\222\327\223\327\233\327\223\327\222\327\233\327\222\327\223\327\233", +// "aa\327\222\327\233aa", +// "\327\222\327\223\327\233\327\223\327\222\327\233\327\222\327\223\327\233", +// "\327\222\327\233aa", +// "linebreakatend\n", +// "some text longer than 30 chars with a line break at the end\n", +// "some text\nwith line breaks\nin the middle\nand at the end\n", + "foo\n\n\nfoo", + "a\n\n\n\n\nb", + "a\n\n\n\n\n\nb", +// "\347\231\273\351\214\262\346\203\205\345\240\261\343\201\214\350\246\213\343\201\244\343\201\213\343\202\211\343\201\252\343\201\204\343\201\213\347\204\241\345\212\271\343\201\252\343\201\237\343\202\201\343\200\201\nPhotoshop Album \343\202\222\350\265\267\345\213\225\343\201\247\343\201\215\343\201\276\343\201\233\343\202\223\343\200\202\345\206\215\343\202\244\343\203\263\343\202\271\343\203\210\343\203\274\343\203\253\343\201\227\343\201\246\343\201\217\343\201\240\343\201\225\343\201\204\343\200\202" +// "\347\231\273\351\214\262\346\203\205\345\240\261\343\201\214\350\246\213\343\201\244\343\201\213\343\202\211\343\201\252\343\201\204\343\201\213\347\204\241\345\212\271\343\201\252\343\201\237\343\202\201\343\200\201\n\343\202\222\350\265\267\345\213\225\343\201\247\343\201\215\343\201\276\343\201\233\343\202\223\343\200\202\345\206\215\343\202\244\343\203\263\343\202\271\343\203\210\343\203\274\343\203\253\343\201\227\343\201\246\343\201\217\343\201\240\343\201\225\343\201\204\343\200\202", + 0 + }; + + int modes[] = { Qt::AlignVCenter, + Qt::AlignLeft, + Qt::AlignCenter, + Qt::AlignRight, + 0 + }; + + + QFont f; + for(int i = 5; i < 15; ++i) { + f.setPointSize(i); + QFontMetrics fm(f); + const char **str = strings; + while( *str ) { + int *m = modes; + while( *m ) { + QString s = QString::fromUtf8(*str); + QRect br = fm.boundingRect(0, 0, 1000, 1000, *m, s ); + int lines = + s.count("\n"); + int expectedHeight = fm.height()+lines*fm.lineSpacing(); + QCOMPARE(br.height(), expectedHeight); + ++m; + } + ++str; + } + QRect br = fm.boundingRect(0, 0, 100, 0, Qt::TextWordWrap, + "A paragraph with gggggggggggggggggggggggggggggggggggg in the middle."); + QVERIFY(br.height() >= fm.height()+2*fm.lineSpacing()); + } + } +} + + +static const char* const maskSource_data[] = { +"16 13 6 1", +". c None", +"d c #000000", +"# c #999999", +"c c #cccccc", +"b c #ffff00", +"a c #ffffff", +"...#####........", +"..#aaaaa#.......", +".#abcbcba######.", +".#acbcbcaaaaaa#d", +".#abcbcbcbcbcb#d", +"#############b#d", +"#aaaaaaaaaa##c#d", +"#abcbcbcbcbbd##d", +".#abcbcbcbcbcd#d", +".#acbcbcbcbcbd#d", +"..#acbcbcbcbb#dd", +"..#############d", +"...ddddddddddddd"}; + +static const char* const maskResult_data[] = { +"16 13 6 1", +". c #ff0000", +"d c #000000", +"# c #999999", +"c c #cccccc", +"b c #ffff00", +"a c #ffffff", +"...#####........", +"..#aaaaa#.......", +".#abcbcba######.", +".#acbcbcaaaaaa#d", +".#abcbcbcbcbcb#d", +"#############b#d", +"#aaaaaaaaaa##c#d", +"#abcbcbcbcbbd##d", +".#abcbcbcbcbcd#d", +".#acbcbcbcbcbd#d", +"..#acbcbcbcbb#dd", +"..#############d", +"...ddddddddddddd"}; + + +void tst_QPainter::drawPixmap_comp_data() +{ + if (qApp->desktop()->depth() < 24) { + QSKIP("Test only works on 32 bit displays", SkipAll); + return; + } + + QTest::addColumn<uint>("dest"); + QTest::addColumn<uint>("source"); + + QTest::newRow("0% on 0%, 1") << 0x00000000u<< 0x00000000u; + QTest::newRow("0% on 0%, 2") << 0x00007fffu << 0x00ff007fu; + + QTest::newRow("50% on a=0%") << 0x00000000u << 0x7fff0000u; + QTest::newRow("50% on a=50%") << 0x7f000000u << 0x7fff0000u; + QTest::newRow("50% on deadbeef") << 0xdeafbeefu << 0x7fff0000u; + QTest::newRow("deadbeef on a=0%") << 0x00000000u << 0xdeadbeefu; + QTest::newRow("deadbeef on a=50%") << 0x7f000000u << 0xdeadbeefu; + QTest::newRow("50% blue on 50% red") << 0x7fff0000u << 0x7f0000ffu; + QTest::newRow("50% blue on 50% green") << 0x7f00ff00u << 0x7f0000ffu; + QTest::newRow("50% red on 50% green") << 0x7f00ff00u << 0x7fff0000u; + QTest::newRow("0% on 50%") << 0x7fff00ffu << 0x00ffffffu; + QTest::newRow("100% on deadbeef") << 0xdeafbeefu << 0xffabcdefu; + QTest::newRow("100% on a=0%") << 0x00000000u << 0xffabcdefu; +} + +QRgb qt_compose_alpha(QRgb source, QRgb dest) +{ + int r1 = qRed(dest), g1 = qGreen(dest), b1 = qBlue(dest), a1 = qAlpha(dest); + int r2 = qRed(source), g2 = qGreen(source), b2 = qBlue(source), a2 = qAlpha(source); + + int alpha = qMin(a2 + ((255 - a2) * a1 + 127) / 255, 255); + if (alpha == 0) + return qRgba(0, 0, 0, 0); + + return qRgba( + qMin((r2 * a2 + (255 - a2) * r1 * a1 / 255) / alpha, 255), + qMin((g2 * a2 + (255 - a2) * g1 * a1 / 255) / alpha, 255), + qMin((b2 * a2 + (255 - a2) * b1 * a1 / 255) / alpha, 255), + alpha); +} + +/* Tests that drawing masked pixmaps works +*/ +void tst_QPainter::drawPixmap_comp() +{ +#ifdef Q_WS_MAC + QSKIP("Mac has other ideas about alpha composition", SkipAll); +#endif + + QFETCH(uint, dest); + QFETCH(uint, source); + + QRgb expected = qt_compose_alpha(source, dest); + + QColor c1(qRed(dest), qGreen(dest), qBlue(dest), qAlpha(dest)); + QColor c2(qRed(source), qGreen(source), qBlue(source), qAlpha(source)); + + QPixmap destPm(10, 10), srcPm(10, 10); + destPm.fill(c1); + srcPm.fill(c2); + +#if defined(Q_WS_X11) + if (!destPm.x11PictureHandle()) + QSKIP("Requires XRender support", SkipAll); +#endif + + QPainter p(&destPm); + p.drawPixmap(0, 0, srcPm); + p.end(); + + QImage result = destPm.toImage().convertToFormat(QImage::Format_ARGB32); + bool different = false; + for (int y=0; y<result.height(); ++y) + for (int x=0; x<result.width(); ++x) { + bool diff; + if (qAlpha(expected) == 0) { + diff = qAlpha(result.pixel(x, y)) != 0; + } else { + // Compensate for possible roundoff / platform fudge + int off = 1; + QRgb pix = result.pixel(x, y); + diff = (qAbs(qRed(pix) - qRed(expected)) > off) + || (qAbs(qGreen(pix) - qGreen(expected)) > off) + || (qAbs(qBlue(pix) - qBlue(expected)) > off) + || (qAbs(qAlpha(pix) - qAlpha(expected)) > off); + } + if (diff && !different) + qDebug( "Different at %d,%d pixel [%d,%d,%d,%d] expected [%d,%d,%d,%d]", x, y, + qRed(result.pixel(x, y)), qGreen(result.pixel(x, y)), + qBlue(result.pixel(x, y)), qAlpha(result.pixel(x, y)), + qRed(expected), qGreen(expected), qBlue(expected), qAlpha(expected)); + different |= diff; + } + + QVERIFY(!different); +} + +void tst_QPainter::saveAndRestore_data() +{ + QVERIFY(1); + + QTest::addColumn<QFont>("font"); + QTest::addColumn<QPen>("pen"); + QTest::addColumn<QBrush>("brush"); + QTest::addColumn<QColor>("backgroundColor"); + QTest::addColumn<int>("backgroundMode"); + QTest::addColumn<QPoint>("brushOrigin"); + QTest::addColumn<QRegion>("clipRegion"); + QTest::addColumn<QRect>("window"); + QTest::addColumn<QRect>("viewport"); + + QPixmap pixmap(1, 1); + QPainter p(&pixmap); + QFont font = p.font(); + QPen pen = p.pen(); + QBrush brush = p.brush(); + QColor backgroundColor = p.background().color(); + Qt::BGMode backgroundMode = p.backgroundMode(); + QPoint brushOrigin = p.brushOrigin(); + QRegion clipRegion = p.clipRegion(); + QRect window = p.window(); + QRect viewport = p.viewport(); + + QTest::newRow("Original") << font << pen << brush << backgroundColor << int(backgroundMode) + << brushOrigin << clipRegion << window << viewport; + + QFont font2 = font; + font2.setPointSize( 24 ); + QTest::newRow("Modified font.pointSize, brush, backgroundColor, backgroundMode") + << font2 << pen << QBrush(Qt::red) << QColor(Qt::blue) << int(Qt::TransparentMode) + << brushOrigin << clipRegion << window << viewport; + + font2 = font; + font2.setPixelSize( 20 ); + QTest::newRow("Modified font.pixelSize, brushOrigin, pos") + << font2 << pen << brush << backgroundColor << int(backgroundMode) + << QPoint( 50, 32 ) << clipRegion << window << viewport; + + QTest::newRow("Modified clipRegion, window, viewport") + << font << pen << brush << backgroundColor << int(backgroundMode) + << brushOrigin << clipRegion.subtracted(QRect(10,10,50,30)) + << QRect(-500, -500, 500, 500 ) << QRect( 0, 0, 50, 50 ); +} + +void tst_QPainter::saveAndRestore() +{ + QFETCH( QFont, font ); + QFETCH( QPen, pen ); + QFETCH( QBrush, brush ); + QFETCH( QColor, backgroundColor ); + QFETCH( int, backgroundMode ); + QFETCH( QPoint, brushOrigin ); + QFETCH( QRegion, clipRegion ); + QFETCH( QRect, window ); + QFETCH( QRect, viewport ); + + QPixmap pixmap(1, 1); + QPainter painter(&pixmap); + + QFont font_org = painter.font(); + QPen pen_org = painter.pen(); + QBrush brush_org = painter.brush(); + QColor backgroundColor_org = painter.background().color(); + Qt::BGMode backgroundMode_org = painter.backgroundMode(); + QPoint brushOrigin_org = painter.brushOrigin(); + QRegion clipRegion_org = painter.clipRegion(); + QRect window_org = painter.window(); + QRect viewport_org = painter.viewport(); + + painter.save(); + painter.setFont( font ); + painter.setPen( QPen(pen) ); + painter.setBrush( brush ); + painter.setBackground( backgroundColor ); + painter.setBackgroundMode( (Qt::BGMode)backgroundMode ); + painter.setBrushOrigin( brushOrigin ); + painter.setClipRegion( clipRegion ); + painter.setWindow( window ); + painter.setViewport( viewport ); + painter.restore(); + + QCOMPARE( painter.font(), font_org ); + QCOMPARE( painter.font().pointSize(), font_org.pointSize() ); + QCOMPARE( painter.font().pixelSize(), font_org.pixelSize() ); + QCOMPARE( painter.pen(), pen_org ); + QCOMPARE( painter.brush(), brush_org ); + QCOMPARE( painter.background().color(), backgroundColor_org ); + QCOMPARE( painter.backgroundMode(), backgroundMode_org ); + QCOMPARE( painter.brushOrigin(), brushOrigin_org ); + QCOMPARE( painter.clipRegion(), clipRegion_org ); + QCOMPARE( painter.window(), window_org ); + QCOMPARE( painter.viewport(), viewport_org ); +} + +/* + Helper functions +*/ + +QColor tst_QPainter::baseColor( int k, int intensity ) +{ + int r = ( k & 1 ) * intensity; + int g = ( (k>>1) & 1 ) * intensity; + int b = ( (k>>2) & 1 ) * intensity; + return QColor( r, g, b ); +} + +QImage tst_QPainter::getResImage( const QString &dir, const QString &addition, const QString &extension ) +{ + QImage res; + QString resFilename = dir + QString( "/res_%1." ).arg( addition ) + extension; + if ( !res.load( resFilename ) ) { + QWARN(QString("Could not load result data %s %1").arg(resFilename).toLatin1()); + return QImage(); + } + return res; +} + +QBitmap tst_QPainter::getBitmap( const QString &dir, const QString &filename, bool mask ) +{ + QBitmap bm; + QString bmFilename = dir + QString( "/%1.xbm" ).arg( filename ); + if ( !bm.load( bmFilename ) ) { + QWARN(QString("Could not load bitmap '%1'").arg(bmFilename).toLatin1()); + return QBitmap(); + } + if ( mask ) { + QBitmap mask; + QString maskFilename = dir + QString( "/%1-mask.xbm" ).arg( filename ); + if ( !mask.load( maskFilename ) ) { + QWARN(QString("Could not load mask '%1'").arg(maskFilename).toLatin1()); + return QBitmap(); + } + bm.setMask( mask ); + } + return bm; +} + +static int getPaintedPixels(const QImage &image, const QColor &background) +{ + uint color = background.rgba(); + + int pixels = 0; + + for (int y = 0; y < image.height(); ++y) + for (int x = 0; x < image.width(); ++x) + if (image.pixel(x, y) != color) + ++pixels; + + return pixels; +} + +static QRect getPaintedSize(const QImage &image, const QColor &background) +{ + // not the fastest but at least it works.. + int xmin = image.width() + 1; + int xmax = -1; + int ymin = image.height() +1; + int ymax = -1; + + uint color = background.rgba(); + + for ( int y = 0; y < image.height(); ++y ) { + for ( int x = 0; x < image.width(); ++x ) { + QRgb pixel = image.pixel( x, y ); + if ( pixel != color && x < xmin ) + xmin = x; + if ( pixel != color && x > xmax ) + xmax = x; + if ( pixel != color && y < ymin ) + ymin = y; + if ( pixel != color && y > ymax ) + ymax = y; + } + } + + return QRect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); +} + +static QRect getPaintedSize(const QPixmap &pm, const QColor &background) +{ + return getPaintedSize(pm.toImage(), background); +} + +void tst_QPainter::initFrom() +{ + QWidget *widget = new QWidget(); + QPalette pal = widget->palette(); + pal.setColor(QPalette::Foreground, QColor(255, 0, 0)); + pal.setBrush(QPalette::Background, QColor(0, 255, 0)); + widget->setPalette(pal); + + QFont font = widget->font(); + font.setPointSize(26); + font.setItalic(true); + widget->setFont(font); + + QPixmap pm(100, 100); + QPainter p(&pm); + p.initFrom(widget); + + QCOMPARE(p.font(), font); + QCOMPARE(p.pen().color(), pal.color(QPalette::Foreground)); + QCOMPARE(p.background(), pal.background()); + + delete widget; +} + +void tst_QPainter::drawBorderPixmap() +{ + QPixmap src(79,79); + src.fill(Qt::transparent); + + QImage pm(200,200,QImage::Format_RGB32); + QPainter p(&pm); + p.setTransform(QTransform(-1,0,0,-1,173.5,153.5)); + qDrawBorderPixmap(&p, QRect(0,0,75,105), QMargins(39,39,39,39), src, QRect(0,0,79,79), QMargins(39,39,39,39), + QTileRules(Qt::StretchTile,Qt::StretchTile), 0); +} + +void tst_QPainter::drawPixmapFragments() +{ + QPixmap origPixmap(20, 20); + QPixmap resPixmap(20, 20); + QPainter::PixmapFragment fragments[4] = { {15, 15, 0, 0, 10, 10, 1, 1, 0, 1}, + { 5, 15, 10, 0, 10, 10, 1, 1, 0, 1}, + {15, 5, 0, 10, 10, 10, 1, 1, 0, 1}, + { 5, 5, 10, 10, 10, 10, 1, 1, 0, 1} }; + { + QPainter p(&origPixmap); + p.fillRect(0, 0, 10, 10, Qt::red); + p.fillRect(10, 0, 10, 10, Qt::green); + p.fillRect(0, 10, 10, 10, Qt::blue); + p.fillRect(10, 10, 10, 10, Qt::yellow); + } + { + QPainter p(&resPixmap); + p.drawPixmapFragments(fragments, 4, origPixmap); + } + + QImage origImage = origPixmap.toImage().convertToFormat(QImage::Format_ARGB32); + QImage resImage = resPixmap.toImage().convertToFormat(QImage::Format_ARGB32); + + QVERIFY(resImage.size() == resPixmap.size()); + QVERIFY(resImage.pixel(5, 5) == origImage.pixel(15, 15)); + QVERIFY(resImage.pixel(5, 15) == origImage.pixel(15, 5)); + QVERIFY(resImage.pixel(15, 5) == origImage.pixel(5, 15)); + QVERIFY(resImage.pixel(15, 15) == origImage.pixel(5, 5)); + + + QPainter::PixmapFragment fragment = QPainter::PixmapFragment::create(QPointF(20, 20), QRectF(30, 30, 2, 2)); + QVERIFY(fragment.x == 20); + QVERIFY(fragment.y == 20); + QVERIFY(fragment.sourceLeft == 30); + QVERIFY(fragment.sourceTop == 30); + QVERIFY(fragment.width == 2); + QVERIFY(fragment.height == 2); + QVERIFY(fragment.scaleX == 1); + QVERIFY(fragment.scaleY == 1); + QVERIFY(fragment.rotation == 0); + QVERIFY(fragment.opacity == 1); +} + +void tst_QPainter::drawLine_data() +{ + QTest::addColumn<QLine>("line"); + + QTest::newRow("0-45") << QLine(0, 20, 100, 0); + QTest::newRow("45-90") << QLine(0, 100, 20, 0); + QTest::newRow("90-135") << QLine(20, 100, 0, 0); + QTest::newRow("135-180") << QLine(100, 20, 0, 0); + QTest::newRow("180-225") << QLine(100, 0, 0, 20); + QTest::newRow("225-270") << QLine(20, 0, 0, 100); + QTest::newRow("270-315") << QLine(0, 0, 20, 100); + QTest::newRow("315-360") << QLine(0, 0, 100, 20); +} + +void tst_QPainter::drawLine() +{ + const int offset = 5; + const int epsilon = 1; // allow for one pixel difference + + QFETCH(QLine, line); + + QPixmap pixmapUnclipped(qMin(line.x1(), line.x2()) + + 2*offset + qAbs(line.dx()), + qMin(line.y1(), line.y2()) + + 2*offset + qAbs(line.dy())); + + { // unclipped + pixmapUnclipped.fill(Qt::white); + QPainter p(&pixmapUnclipped); + p.translate(offset, offset); + p.setPen(QPen(Qt::black)); + p.drawLine(line); + p.end(); + + const QRect painted = getPaintedSize(pixmapUnclipped, Qt::white); + + QLine l = line; + l.translate(offset, offset); + QVERIFY(qAbs(painted.width() - qAbs(l.dx())) <= epsilon); + QVERIFY(qAbs(painted.height() - qAbs(l.dy())) <= epsilon); + QVERIFY(qAbs(painted.top() - qMin(l.y1(), l.y2())) <= epsilon); + QVERIFY(qAbs(painted.left() - qMin(l.x1(), l.x2())) <= epsilon); + QVERIFY(qAbs(painted.bottom() - qMax(l.y1(), l.y2())) <= epsilon); + QVERIFY(qAbs(painted.right() - qMax(l.x1(), l.x2())) <= epsilon); + } + + QPixmap pixmapClipped(qMin(line.x1(), line.x2()) + + 2*offset + qAbs(line.dx()), + qMin(line.y1(), line.y2()) + + 2*offset + qAbs(line.dy())); + { // clipped + const QRect clip = QRect(line.p1(), line.p2()).normalized(); + + pixmapClipped.fill(Qt::white); + QPainter p(&pixmapClipped); + p.translate(offset, offset); + p.setClipRect(clip); + p.setPen(QPen(Qt::black)); + p.drawLine(line); + p.end(); + } + + const QImage unclipped = pixmapUnclipped.toImage(); + const QImage clipped = pixmapClipped.toImage(); + QCOMPARE(unclipped, clipped); +} + +void tst_QPainter::drawLine_clipped() +{ + QImage image(16, 1, QImage::Format_ARGB32_Premultiplied); + image.fill(0x0); + + QPainter p(&image); + p.setPen(QPen(Qt::black, 10)); + + // this should fill the whole image + p.drawLine(-1, -1, 17, 1); + p.end(); + + for (int x = 0; x < 16; ++x) + QCOMPARE(image.pixel(x, 0), 0xff000000); +} + +void tst_QPainter::drawLine_task121143() +{ + QPen pen(Qt::black); + + QImage image(5, 5, QImage::Format_ARGB32_Premultiplied); + image.fill(0xffffffff); + QPainter p(&image); + p.setPen(pen); + p.drawLine(QLine(0, 0+4, 0+4, 0)); + p.end(); + + QImage expected(5, 5, QImage::Format_ARGB32_Premultiplied); + expected.fill(0xffffffff); + for (int x = 0; x < 5; ++x) + expected.setPixel(x, 5-x-1, pen.color().rgb()); + + QCOMPARE(image, expected); +} + +void tst_QPainter::drawLine_task190634() +{ + QPen pen(Qt::black, 3); + + QImage image(32, 32, QImage::Format_ARGB32_Premultiplied); + QPainter p(&image); + p.fillRect(0, 0, image.width(), image.height(), Qt::white); + + p.setPen(pen); + p.drawLine(QLineF(2, -1.6, 10, -1.6)); + p.end(); + + const uint *data = reinterpret_cast<uint *>(image.bits()); + + for (int i = 0; i < image.width() * image.height(); ++i) + QCOMPARE(data[i], 0xffffffff); + + p.begin(&image); + p.fillRect(0, 0, image.width(), image.height(), Qt::white); + + p.setPen(pen); + p.drawLine(QLineF(-1.6, 2, -1.6, 10)); + p.end(); + + data = reinterpret_cast<uint *>(image.bits()); + + for (int i = 0; i < image.width() * image.height(); ++i) + QCOMPARE(data[i], 0xffffffff); + + p.begin(&image); + p.fillRect(0, 0, image.width(), image.height(), Qt::white); + + p.setPen(pen); + p.drawLine( QPoint(2,-2), QPoint(3,-5) ); + p.end(); + + data = reinterpret_cast<uint *>(image.bits()); + + for (int i = 0; i < image.width() * image.height(); ++i) + QCOMPARE(data[i], 0xffffffff); +} + +void tst_QPainter::drawLine_task229459() +{ + QImage image(32, 32, QImage::Format_ARGB32_Premultiplied); + image.fill(0x0); + QPen pen(Qt::black, 64); + + QPainter p(&image); + p.setPen(pen); + p.drawLine(-8, -8, 10000000, 10000000); + p.end(); + + QImage expected = image; + expected.fill(0xff000000); + + QCOMPARE(image, expected); +} + +void tst_QPainter::drawLine_task234891() +{ + QImage img(100, 1000, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + QImage expected = img; + + QPainter p(&img); + p.setPen(QPen(QBrush(QColor(255,0,0)), 6)); + p.drawLine(QPointF(25000,100),QPointF(30000,105)); + + p.setPen(QPen(QBrush(QColor(0,255,0)), 6)); + p.drawLine(QPointF(30000,150),QPointF(35000,155)); + + p.setPen(QPen(QBrush(QColor(0,0,255)), 6)); + p.drawLine(QPointF(65000,200),QPointF(66000,205)); + + QCOMPARE(expected, img); +} + +void tst_QPainter::drawLine_task216948() +{ + QImage img(1, 10, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + + QPainter p(&img); + QLine line(10, 0, 10, 10); + p.translate(-10, 0); + p.drawLine(line); + p.end(); + + for (int i = 0; i < img.height(); ++i) + QCOMPARE(img.pixel(0, i), QColor(Qt::black).rgba()); +} + +void tst_QPainter::drawRect() +{ + QFETCH(QRect, rect); + QFETCH(bool, usePen); + + QPixmap pixmap(rect.x() + rect.width() + 10, + rect.y() + rect.height() + 10); + { + pixmap.fill(Qt::white); + QPainter p(&pixmap); + p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen)); + p.setBrush(Qt::black); + p.drawRect(rect); + p.end(); + + int increment = usePen ? 1 : 0; + + const QRect painted = getPaintedSize(pixmap, Qt::white); + QCOMPARE(painted.width(), rect.width() + increment); + QCOMPARE(painted.height(), rect.height() + increment); + } +} + +void tst_QPainter::drawRect2() +{ + QImage image(64, 64, QImage::Format_ARGB32_Premultiplied); + { + image.fill(0xffffffff); + + QTransform transform(0.368567, 0, 0, 0, 0.368567, 0, 0.0289, 0.0289, 1); + + QPainter p(&image); + p.setTransform(transform); + p.setBrush(Qt::red); + p.setPen(Qt::NoPen); + p.drawRect(QRect(14, 14, 39, 39)); + p.end(); + + QRect fill = getPaintedSize(image, Qt::white); + image.fill(0xffffffff); + + p.begin(&image); + p.setTransform(transform); + p.drawRect(QRect(14, 14, 39, 39)); + p.end(); + + QRect stroke = getPaintedSize(image, Qt::white); + QCOMPARE(stroke.adjusted(1, 1, 0, 0), fill.adjusted(0, 0, 1, 1)); + } +} + +void tst_QPainter::fillRect() +{ + QImage image(100, 100, QImage::Format_ARGB32_Premultiplied); + image.fill(QColor(0, 0, 0, 0).rgba()); + + QPainter p(&image); + + p.fillRect(0, 0, 100, 100, QColor(255, 0, 0, 127)); + +// pixmap.save("bla1.png", "PNG"); + QCOMPARE(getPaintedSize(image, QColor(0, 0, 0, 0)), + QRect(0, 0, 100, 100)); + QCOMPARE(getPaintedSize(image, QColor(127, 0, 0, 127)).isValid(), + QRect().isValid()); + + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + p.fillRect(50, 0, 50, 100, QColor(0, 0, 255, 255)); + + QCOMPARE(getPaintedSize(image, QColor(127, 0, 0, 127)), + QRect(50, 0, 50, 100)); + QCOMPARE(getPaintedSize(image, QColor(0, 0, 127, 127)), + QRect(0, 0, 50, 100)); +} + +void tst_QPainter::fillRect2() +{ + QRgb background = 0x0; + + QImage img(1, 20, QImage::Format_ARGB32_Premultiplied); + img.fill(background); + + QPainter p(&img); + + QRectF rect(0, 1, 1.2, 18); + p.fillRect(rect, Qt::black); + + p.end(); + + QCOMPARE(img.pixel(0, 0), background); + QCOMPARE(img.pixel(0, img.height() - 1), background); + + QCOMPARE(img.pixel(0, 1), img.pixel(0, 2)); + QCOMPARE(img.pixel(0, img.height() - 2), img.pixel(0, img.height() - 3)); +} + +void tst_QPainter::fillRect3() +{ + QImage img(1, 1, QImage::Format_ARGB32_Premultiplied); + img.fill(QColor(Qt::black).rgba()); + + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(img.rect(), Qt::transparent); + p.end(); + + QCOMPARE(img.pixel(0, 0), 0U); +} + +void tst_QPainter::fillRect4() +{ + QImage image(100, 1, QImage::Format_ARGB32_Premultiplied); + image.fill(0x0); + + QImage expected = image; + expected.fill(0xffffffff); + + QPainter p(&image); + p.scale(1.1, 1); + p.setPen(Qt::NoPen); + + for (int i = 0; i < 33; ++i) + p.fillRect(QRectF(3 * i, 0, 3, 1), Qt::white); + + p.end(); + + QCOMPARE(image, expected); +} + +void tst_QPainter::drawPath_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<QRect>("expectedBounds"); + QTest::addColumn<int>("expectedPixels"); + + { + QPainterPath p; + p.addRect(2, 2, 10, 10); + QTest::newRow("int-aligned rect") << p << QRect(2, 2, 10, 10) << 10 * 10; + } + + { + QPainterPath p; + p.addRect(2.25, 2.25, 10, 10); + QTest::newRow("non-aligned rect") << p << QRect(3, 3, 10, 10) << 10 * 10; + } + + { + QPainterPath p; + p.addRect(2.25, 2.25, 10.5, 10.5); + QTest::newRow("non-aligned rect 2") << p << QRect(3, 3, 10, 10) << 10 * 10; + } + + { + QPainterPath p; + p.addRect(2.5, 2.5, 10, 10); + QTest::newRow("non-aligned rect 3") << p << QRect(3, 3, 10, 10) << 10 * 10; + } + + { + QPainterPath p; + p.addRect(2, 2, 10, 10); + p.addRect(4, 4, 6, 6); + QTest::newRow("rect-in-rect") << p << QRect(2, 2, 10, 10) << 10 * 10 - 6 * 6; + } + + { + QPainterPath p; + p.addRect(2, 2, 10, 10); + p.addRect(4, 4, 6, 6); + p.addRect(6, 6, 2, 2); + QTest::newRow("rect-in-rect-in-rect") << p << QRect(2, 2, 10, 10) << 10 * 10 - 6 * 6 + 2 * 2; + } +} + +void tst_QPainter::drawPath() +{ + QFETCH(QPainterPath, path); + QFETCH(QRect, expectedBounds); + QFETCH(int, expectedPixels); + + const int offset = 2; + + QImage image(expectedBounds.width() + 2 * offset, expectedBounds.height() + 2 * offset, + QImage::Format_ARGB32_Premultiplied); + image.fill(QColor(Qt::white).rgb()); + + QPainter p(&image); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + p.translate(offset - expectedBounds.left(), offset - expectedBounds.top()); + p.drawPath(path); + p.end(); + + const QRect paintedBounds = getPaintedSize(image, Qt::white); + + QCOMPARE(paintedBounds.x(), offset); + QCOMPARE(paintedBounds.y(), offset); + QCOMPARE(paintedBounds.width(), expectedBounds.width()); + QCOMPARE(paintedBounds.height(), expectedBounds.height()); + + if (expectedPixels != -1) { + int paintedPixels = getPaintedPixels(image, Qt::white); + QCOMPARE(paintedPixels, expectedPixels); + } +} + +void tst_QPainter::drawPath2() +{ + const int w = 50; + + for (int h = 5; h < 200; ++h) { + QPainterPath p1, p2; + p1.lineTo(w, 0); + p1.lineTo(w, h); + + p2.lineTo(w, h); + p2.lineTo(0, h); + + const int offset = 2; + + QImage image(w + 2 * offset, h + 2 * offset, + QImage::Format_ARGB32_Premultiplied); + image.fill(QColor(Qt::white).rgb()); + + QPainter p(&image); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + p.translate(offset, offset); + p.drawPath(p1); + p.end(); + + const int p1Pixels = getPaintedPixels(image, Qt::white); + + image.fill(QColor(Qt::white).rgb()); + p.begin(&image); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + p.translate(offset, offset); + p.drawPath(p2); + p.end(); + + const int p2Pixels = getPaintedPixels(image, Qt::white); + + QCOMPARE(p1Pixels + p2Pixels, w * h); + } +} + +void tst_QPainter::drawPath3() +{ +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QImage imgA(400, 400, QImage::Format_RGB32); +#else + QImage imgA(100, 100, QImage::Format_RGB32); +#endif + imgA.fill(0xffffff); + QImage imgB = imgA; + + QPainterPath path; + for (int y = 0; y < imgA.height(); ++y) { + for (int x = 0; x < imgA.width(); ++x) { + if ((x + y) & 1) { + imgA.setPixel(x, y, 0); + path.addRect(x, y, 1, 1); + } + } + } + + QPainter p(&imgB); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + + p.drawPath(path); + p.end(); + + QVERIFY(imgA == imgB); + + imgA.invertPixels(); + imgB.fill(0xffffff); + + p.begin(&imgB); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + + QRectF rect(0, 0, imgA.width(), imgA.height()); + path.addRect(rect.adjusted(-10, -10, 10, 10)); + p.drawPath(path); + p.end(); + + QVERIFY(imgA == imgB); + + path.setFillRule(Qt::WindingFill); + imgB.fill(0xffffff); + + p.begin(&imgB); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + QRect clip = rect.adjusted(10, 10, -10, -10).toRect(); + p.setClipRect(clip); + p.drawPath(path); + p.end(); + + QCOMPARE(getPaintedPixels(imgB, Qt::white), clip.width() * clip.height()); +} + +void tst_QPainter::drawEllipse_data() +{ + QTest::addColumn<QSize>("size"); + QTest::addColumn<bool>("usePen"); + + // The current drawEllipse algorithm (drawEllipse_midpoint_i in + // qpaintengine_raster.cpp) draws ellipses that are too wide if the + // ratio between width and hight is too large/small (task 114874). Those + // ratios are therefore currently avoided. + for (int w = 10; w < 128; w += 7) { + for (int h = w/2; h < qMin(2*w, 128); h += 13) { + QString s = QString("%1x%2").arg(w).arg(h); + QTest::newRow(QString("%1 with pen").arg(s).toLatin1()) << QSize(w, h) << true; + QTest::newRow(QString("%1 no pen").arg(s).toLatin1()) << QSize(w, h) << false; + } + } +} + +void tst_QPainter::drawEllipse() +{ + QFETCH(QSize, size); + QFETCH(bool, usePen); + + const int offset = 10; + QRect rect(QPoint(offset, offset), size); + + QImage image(size.width() + 2 * offset, size.height() + 2 * offset, + QImage::Format_ARGB32_Premultiplied); + image.fill(QColor(Qt::white).rgb()); + + QPainter p(&image); + p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen)); + p.setBrush(Qt::black); + p.drawEllipse(rect); + p.end(); + + QPixmap pixmap = QPixmap::fromImage(image); + + const QRect painted = getPaintedSize(pixmap, Qt::white); + + QCOMPARE(painted.x(), rect.x()); + QCOMPARE(painted.y(), rect.y() + (usePen ? 0 : 1)); + QCOMPARE(painted.width(), size.width() + (usePen ? 1 : 0)); + QCOMPARE(painted.height(), size.height() + (usePen ? 1 : -1)); +} + +void tst_QPainter::drawClippedEllipse_data() +{ + QTest::addColumn<QRect>("rect"); + + for (int w = 20; w < 128; w += 7) { + for (int h = w/2; h < qMin(2*w, 128); h += 13) { + QString s = QString("%1x%2").arg(w).arg(h); + QTest::newRow(QString("%1 top").arg(s).toLatin1()) << QRect(0, -h/2, w, h); + QTest::newRow(QString("%1 topright").arg(s).toLatin1()) << QRect(w/2, -h/2, w, h); + QTest::newRow(QString("%1 right").arg(s).toLatin1()) << QRect(w/2, 0, w, h); + QTest::newRow(QString("%1 bottomright").arg(s).toLatin1()) << QRect(w/2, h/2, w, h); + QTest::newRow(QString("%1 bottom").arg(s).toLatin1()) << QRect(0, h/2, w, h); + QTest::newRow(QString("%1 bottomleft").arg(s).toLatin1()) << QRect(-w/2, h/2, w, h); + QTest::newRow(QString("%1 left").arg(s).toLatin1()) << QRect(-w/2, 0, w, h); + QTest::newRow(QString("%1 topleft").arg(s).toLatin1()) << QRect(-w/2, -h/2, w, h); + } + } +} + +void tst_QPainter::drawClippedEllipse() +{ + QFETCH(QRect, rect); + if (sizeof(qreal) != sizeof(double)) + QSKIP("Test only works for qreal==double", SkipAll); + QImage image(rect.width() + 1, rect.height() + 1, + QImage::Format_ARGB32_Premultiplied); + QRect expected = QRect(rect.x(), rect.y(), rect.width()+1, rect.height()+1) + & QRect(0, 0, image.width(), image.height()); + + + image.fill(QColor(Qt::white).rgb()); + QPainter p(&image); + p.drawEllipse(rect); + p.end(); + + QPixmap pixmap = QPixmap::fromImage(image); + const QRect painted = getPaintedSize(pixmap, Qt::white); + + QCOMPARE(painted.x(), expected.x()); + QCOMPARE(painted.y(), expected.y()); + QCOMPARE(painted.width(), expected.width()); + QCOMPARE(painted.height(), expected.height()); + +} + +void tst_QPainter::drawRoundRect() +{ + QFETCH(QRect, rect); + QFETCH(bool, usePen); + +#ifdef Q_WS_MAC + if (QTest::currentDataTag() == QByteArray("rect(6, 12, 3, 14) with pen") || + QTest::currentDataTag() == QByteArray("rect(6, 17, 3, 25) with pen") || + QTest::currentDataTag() == QByteArray("rect(10, 6, 10, 3) with pen") || + QTest::currentDataTag() == QByteArray("rect(10, 12, 10, 14) with pen") || + QTest::currentDataTag() == QByteArray("rect(13, 45, 17, 80) with pen") || + QTest::currentDataTag() == QByteArray("rect(13, 50, 17, 91) with pen") || + QTest::currentDataTag() == QByteArray("rect(17, 6, 24, 3) with pen") || + QTest::currentDataTag() == QByteArray("rect(24, 12, 38, 14) with pen")) + QSKIP("The Mac paint engine is off-by-one on certain rect sizes", SkipSingle); +#endif + QPixmap pixmap(rect.x() + rect.width() + 10, + rect.y() + rect.height() + 10); + { + pixmap.fill(Qt::white); + QPainter p(&pixmap); + p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen)); + p.setBrush(Qt::black); + p.drawRoundRect(rect); + p.end(); + + int increment = usePen ? 1 : 0; + + const QRect painted = getPaintedSize(pixmap, Qt::white); + QCOMPARE(painted.width(), rect.width() + increment); + QCOMPARE(painted.height(), rect.height() + increment); + } +} + +Q_DECLARE_METATYPE(QImage::Format) + +void tst_QPainter::qimageFormats_data() +{ + QTest::addColumn<QImage::Format>("format"); + QTest::newRow("QImage::Format_RGB32") << QImage::Format_RGB32; + QTest::newRow("QImage::Format_ARGB32") << QImage::Format_ARGB32; + QTest::newRow("QImage::Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("QImage::Format_RGB16") << QImage::Format_RGB16; + QTest::newRow("Qimage::Format_ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied; + QTest::newRow("Qimage::Format_RGB666") << QImage::Format_RGB666; + QTest::newRow("Qimage::Format_RGB555") << QImage::Format_RGB555; + QTest::newRow("Qimage::Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied; + QTest::newRow("Qimage::Format_RGB888") << QImage::Format_RGB888; +} + +/* + Tests that QPainter can paint on various QImage formats. +*/ +void tst_QPainter::qimageFormats() +{ + QFETCH(QImage::Format, format); + + const QSize size(100, 100); + QImage image(size, format); + image.fill(0); + + const QColor testColor(Qt::red); + QPainter p(&image); + QVERIFY(p.isActive()); + p.setBrush(QBrush(testColor)); + p.drawRect(QRect(QPoint(0,0), size)); + QCOMPARE(image.pixel(50, 50), testColor.rgb()); +} + +void tst_QPainter::fillData() +{ + QTest::addColumn<QRect>("rect"); + QTest::addColumn<bool>("usePen"); + + for (int w = 3; w < 50; w += 7) { + for (int h = 3; h < 50; h += 11) { + int x = w/2 + 5; + int y = h/2 + 5; + QTest::newRow(QString("rect(%1, %2, %3, %4) with pen").arg(x).arg(y).arg(w).arg(h).toLatin1()) + << QRect(x, y, w, h) << true; + QTest::newRow(QString("rect(%1, %2, %3, %4) no pen").arg(x).arg(y).arg(w).arg(h).toLatin1()) + << QRect(x, y, w, h) << false; + } + } +} + +/* + Test that drawline works properly after setWindow has been called. +*/ +void tst_QPainter::setWindow() +{ + QPixmap pixmap(600, 600); + pixmap.fill(QColor(Qt::white)); + + QPainter painter(&pixmap); + painter.setWindow(0, 0, 3, 3); + painter.drawLine(1, 1, 2, 2); + + const QRect painted = getPaintedSize(pixmap, Qt::white); + QVERIFY(195 < painted.y() && painted.y() < 205); // correct value is around 200 + QVERIFY(195 < painted.height() && painted.height() < 205); // correct value is around 200 +} + +void tst_QPainter::combinedMatrix() +{ + QPixmap pm(64, 64); + + QPainter p(&pm); + p.setWindow(0, 0, 1, 1); + p.setViewport(32, 0, 32, 32); + + p.translate(0.5, 0.5); + + QMatrix cm = p.combinedMatrix(); + + QPointF pt = QPointF(0, 0) * cm; + + QCOMPARE(pt.x(), 48.0); + QCOMPARE(pt.y(), 16.0); +} + +void tst_QPainter::textOnTransparentImage() +{ + bool foundPixel = false; + QImage image(10, 10, QImage::Format_ARGB32_Premultiplied); + image.fill(qRgba(0, 0, 0, 0)); // transparent + { + QPainter painter(&image); + painter.setPen(QColor(255, 255, 255)); + painter.drawText(0, 10, "W"); + } + for (int x = 0; x < image.width(); ++x) + for (int y = 0; y < image.height(); ++y) + if (image.pixel(x, y) != 0) + foundPixel = true; + QVERIFY(foundPixel); +} + +void tst_QPainter::renderHints() +{ + QImage img(1, 1, QImage::Format_RGB32); + + QPainter p(&img); + + // Turn off all... + p.setRenderHints(QPainter::RenderHints(0xffffffff), false); + QCOMPARE(p.renderHints(), QPainter::RenderHints(0)); + + // Single set/get + p.setRenderHint(QPainter::Antialiasing); + QVERIFY(p.renderHints() & QPainter::Antialiasing); + + p.setRenderHint(QPainter::Antialiasing, false); + QVERIFY(!(p.renderHints() & QPainter::Antialiasing)); + + // Multi set/get + p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + QVERIFY(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform)); + + p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false); + QVERIFY(!(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform))); +} + +int countPixels(const QImage &img, const QRgb &color) +{ + int count = 0; + for (int y = 0; y < img.height(); ++y) { + for (int x = 0; x < img.width(); ++x) { + count += ((img.pixel(x, y) & 0xffffff) == color); + } + } + return count; +} + +template <typename T> +void testClipping(QImage &img) +{ + QPainterPath a, b; + a.addRect(QRect(2, 2, 4, 4)); + b.addRect(QRect(4, 4, 4, 4)); + QPainter p(&img); + + p.end(); + img.fill(0x0); + p.begin(&img); + p.setClipPath(a); + p.setClipPath(b, Qt::IntersectClip); + + p.setClipping(false); + p.setPen(Qt::NoPen); + p.setBrush(QColor(0xff0000)); + p.drawRect(T(0, 0, 10, 10)); + + p.setClipping(true); + p.setBrush(QColor(0x00ff00)); + p.drawRect(T(0, 0, 10, 10)); + + QCOMPARE(countPixels(img, 0xff0000), 96); + QCOMPARE(countPixels(img, 0x00ff00), 4); +} + +void tst_QPainter::disableEnableClipping() +{ + QImage img(10, 10, QImage::Format_RGB32); + + testClipping<QRectF>(img); + testClipping<QRect>(img); +} + +void tst_QPainter::setClipRect() +{ + QImage img(10, 10, QImage::Format_RGB32); + // simple test to let valgrind check for buffer overflow + { + QPainter p(&img); + p.setClipRect(-10, -10, 100, 100); + p.fillRect(-10, -10, 100, 100, QBrush(QColor(Qt::red))); + } + + // rects with negative width/height + { + QPainter p(&img); + p.setClipRect(QRect(10, 10, -10, 10)); + QVERIFY(p.clipRegion().isEmpty()); + p.setClipRect(QRect(10, 10, 10, -10)); + QVERIFY(p.clipRegion().isEmpty()); + p.setClipRect(QRectF(10.5, 10.5, -10.5, 10.5)); + QVERIFY(p.clipRegion().isEmpty()); + p.setClipRect(QRectF(10.5, 10.5, 10.5, -10.5)); + QVERIFY(p.clipRegion().isEmpty()); + } +} + +/* + This tests the two different clipping approaches in QRasterPaintEngine, + one when using a QRegion and one when using a QPainterPath. They should + give equal results. +*/ +void tst_QPainter::setEqualClipRegionAndPath_data() +{ + QTest::addColumn<QSize>("deviceSize"); + QTest::addColumn<QRegion>("region"); + + QTest::newRow("empty") << QSize(100, 100) << QRegion(); + QTest::newRow("simple rect") << QSize(100, 100) + << QRegion(QRect(5, 5, 10, 10)); + + QVector<QRect> rects; + QRegion region; + + rects << QRect(5, 5, 10, 10) << QRect(20, 20, 10, 10); + region.setRects(rects.constData(), rects.size()); + QTest::newRow("two rects") << QSize(100, 100) << region; + + rects.clear(); + rects << QRect(5, 5, 10, 10) << QRect(20, 5, 10, 10); + region.setRects(rects.constData(), rects.size()); + QTest::newRow("two x-adjacent rects") << QSize(100, 100) << region; + + rects.clear(); + rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100); + region.setRects(rects.constData(), rects.size()); + QTest::newRow("two x-adjacent rects 2") << QSize(100, 100) << region; + + rects.clear(); + rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100); + region.setRects(rects.constData(), rects.size()); + QTest::newRow("two x-adjacent rects 3") << QSize(50, 50) << region; + + rects.clear(); + rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100); + region.setRects(rects.constData(), rects.size()); + QTest::newRow("two x-adjacent rects 4") << QSize(101, 101) << region; + + region = QRegion(QRect(0, 0, 200, 200), QRegion::Ellipse); + + QTest::newRow("ellipse") << QSize(190, 200) << region; + + region ^= QRect(50, 50, 50, 50); + QTest::newRow("ellipse 2") << QSize(200, 200) << region; +} + +void tst_QPainter::setEqualClipRegionAndPath() +{ + QFETCH(QSize, deviceSize); + QFETCH(QRegion, region); + + QPainterPath path; + path.addRegion(region); + + QImage img1(deviceSize.width(), deviceSize.height(), + QImage::Format_ARGB32); + QImage img2(deviceSize.width(), deviceSize.height(), + QImage::Format_ARGB32); + img1.fill(0x12345678); + img2.fill(0x12345678); + + { + QPainter p(&img1); + p.setClipRegion(region); + p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red)); + } + { + QPainter p(&img2); + p.setClipPath(path); + p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red)); + } + +#if 0 + if (img1 != img2) { + img1.save("setEqualClipRegionAndPath_1.xpm", "XPM"); + img2.save("setEqualClipRegionAndPath_2.xpm", "XPM"); + } +#endif + QCOMPARE(img1, img2); + +#if 0 + // rotated + img1.fill(0x12345678); + img2.fill(0x12345678); + + { + QPainter p(&img1); + p.rotate(25); + p.setClipRegion(region); + p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red)); + } + { + QPainter p(&img2); + p.rotate(25); + p.setClipPath(path); + p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red)); + } + +#if 1 + if (img1 != img2) { + img1.save("setEqualClipRegionAndPath_1.xpm", "XPM"); + img2.save("setEqualClipRegionAndPath_2.xpm", "XPM"); + } +#endif + QCOMPARE(img1, img2); +#endif + + img1.fill(0x12345678); + img2.fill(0x12345678); + + // simple intersectclip + img1.fill(0x12345678); + img2.fill(0x12345678); + { + QPainter p(&img1); + p.setClipRegion(region); + p.setClipRegion(region, Qt::IntersectClip); + p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red)); + } + { + QPainter p(&img2); + p.setClipPath(path); + p.setClipPath(path, Qt::IntersectClip); + p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red)); + } +#if 0 + if (img1 != img2) { + img1.save("setEqualClipRegionAndPath_1.png", "PNG"); + img2.save("setEqualClipRegionAndPath_2.png", "PNG"); + } +#endif + QCOMPARE(img1, img2); + + img1.fill(0x12345678); + img2.fill(0x12345678); + { + QPainter p(&img1); + p.setClipPath(path); + p.setClipRegion(region, Qt::IntersectClip); + p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red)); + } + { + QPainter p(&img2); + p.setClipRegion(region); + p.setClipPath(path, Qt::IntersectClip); + p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red)); + } +#if 0 + if (img1 != img2) { + img1.save("setEqualClipRegionAndPath_1.xpm", "XPM"); + img2.save("setEqualClipRegionAndPath_2.xpm", "XPM"); + } +#endif + QCOMPARE(img1, img2); + +} + +void tst_QPainter::clippedFillPath_data() +{ + QTest::addColumn<QSize>("imageSize"); + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<QRect>("clipRect"); + QTest::addColumn<QBrush>("brush"); + QTest::addColumn<QPen>("pen"); + + QLinearGradient gradient(QPoint(0, 0), QPoint(100, 100)); + gradient.setColorAt(0, Qt::red); + gradient.setColorAt(1, Qt::blue); + + + QPen pen2(QColor(223, 223, 0, 223)); + pen2.setWidth(2); + + QPainterPath path; + path.addRect(QRect(15, 15, 50, 50)); + QTest::newRow("simple rect 0") << QSize(100, 100) << path + << QRect(15, 15, 49, 49) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("simple rect 1") << QSize(100, 100) << path + << QRect(15, 15, 50, 50) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("simple rect 2") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("simple rect 3") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(QColor(Qt::blue)) + << QPen(Qt::NoPen); + QTest::newRow("simple rect 4") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(gradient) + << pen2; + + path = QPainterPath(); + path.addEllipse(QRect(15, 15, 50, 50)); + QTest::newRow("ellipse 0") << QSize(100, 100) << path + << QRect(15, 15, 49, 49) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("ellipse 1") << QSize(100, 100) << path + << QRect(15, 15, 50, 50) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("ellipse 2") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("ellipse 3") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(QColor(Qt::blue)) + << QPen(Qt::NoPen); + QTest::newRow("ellipse 4") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(gradient) + << pen2; + + path = QPainterPath(); + path.addRoundRect(QRect(15, 15, 50, 50), 20); + QTest::newRow("round rect 0") << QSize(100, 100) << path + << QRect(15, 15, 49, 49) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("round rect 1") << QSize(100, 100) << path + << QRect(15, 15, 50, 50) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("round rect 2") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("round rect 3") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(QColor(Qt::blue)) + << QPen(Qt::NoPen); + QTest::newRow("round rect 4") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(gradient) + << pen2; + + path = QPainterPath(); + path.moveTo(15, 50); + path.cubicTo(40, 50, 40, 15, 65, 50); + path.lineTo(15, 50); + QTest::newRow("cubic 0") << QSize(100, 100) << path + << QRect(15, 15, 49, 49) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("cubic 1") << QSize(100, 100) << path + << QRect(15, 15, 50, 50) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("cubic 2") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(Qt::NoBrush) + << QPen(Qt::black); + QTest::newRow("cubic 3") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(QColor(Qt::blue)) + << QPen(Qt::NoPen); + QTest::newRow("cubic 4") << QSize(100, 100) << path + << QRect(15, 15, 51, 51) + << QBrush(gradient) + << pen2; +} + +void tst_QPainter::clippedFillPath() +{ + QFETCH(QSize, imageSize); + QFETCH(QPainterPath, path); + QFETCH(QRect, clipRect); + QPainterPath clipPath; + clipPath.addRect(clipRect); + QFETCH(QBrush, brush); + QFETCH(QPen, pen); + + const int width = imageSize.width(); + const int height = imageSize.height(); + + QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied); + clippedRect.fill(0x12345678); + { + QPainter painter(&clippedRect); + painter.setPen(pen); + painter.setBrush(brush); + painter.setClipRect(clipRect); + painter.drawPath(path); + } + + QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied); + clippedPath.fill(0x12345678); + { + QPainter painter(&clippedPath); + painter.setPen(pen); + painter.setBrush(brush); + painter.setClipPath(clipPath); + painter.drawPath(path); + } + +#if 0 + if (clippedRect != clippedPath) { + clippedRect.save(QString("clippedRect.png"), "PNG"); + clippedPath.save(QString("clippedPath.png"), "PNG"); + } +#endif + QCOMPARE(clippedRect, clippedPath); + + // repeat with antialiasing + + clippedRect.fill(0x12345678); + { + QPainter painter(&clippedRect); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(pen); + painter.setBrush(brush); + painter.setClipRect(clipRect); + painter.drawPath(path); + } + + clippedPath.fill(0x12345678); + { + QPainter painter(&clippedPath); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(pen); + painter.setBrush(brush); + painter.setClipPath(clipPath); + painter.drawPath(path); + } + +#if 1 + if (clippedRect != clippedPath) { + clippedRect.save(QString("clippedRect.png"), "PNG"); + clippedPath.save(QString("clippedPath.png"), "PNG"); + } +#endif + QCOMPARE(clippedRect, clippedPath); + +} + +void tst_QPainter::clippedLines_data() +{ + QTest::addColumn<QSize>("imageSize"); + QTest::addColumn<QLineF>("line"); + QTest::addColumn<QRect>("clipRect"); + QTest::addColumn<QPen>("pen"); + + QPen pen2(QColor(223, 223, 0, 223)); + pen2.setWidth(2); + + QVector<QLineF> lines; + lines << QLineF(15, 15, 65, 65) + << QLineF(14, 14, 66, 66) + << QLineF(16, 16, 64, 64) + << QLineF(65, 65, 15, 15) + << QLineF(66, 66, 14, 14) + << QLineF(64, 64, 14, 14) + << QLineF(15, 50, 15, 64) + << QLineF(15, 50, 15, 65) + << QLineF(15, 50, 15, 66) + << QLineF(15, 50, 64, 50) + << QLineF(15, 50, 65, 50) + << QLineF(15, 50, 66, 50); + + foreach (QLineF line, lines) { + QString desc = QString("line (%1, %2, %3, %4) %5").arg(line.x1()) + .arg(line.y1()).arg(line.x2()).arg(line.y2()); + QTest::newRow(qPrintable(desc.arg(0))) << QSize(100, 100) << line + << QRect(15, 15, 49, 49) + << QPen(Qt::black); + QTest::newRow(qPrintable(desc.arg(1))) << QSize(100, 100) << line + << QRect(15, 15, 50, 50) + << QPen(Qt::black); + QTest::newRow(qPrintable(desc.arg(2))) << QSize(100, 100) << line + << QRect(15, 15, 51, 51) + << QPen(Qt::black); + QTest::newRow(qPrintable(desc.arg(3))) << QSize(100, 100) << line + << QRect(15, 15, 51, 51) + << QPen(Qt::NoPen); + QTest::newRow(qPrintable(desc.arg(4))) << QSize(100, 100) << line + << QRect(15, 15, 51, 51) + << pen2; + } +} + +void tst_QPainter::clippedLines() +{ + QFETCH(QSize, imageSize); + QFETCH(QLineF, line); + QFETCH(QRect, clipRect); + QPainterPath clipPath; + clipPath.addRect(clipRect); + QFETCH(QPen, pen); + + const int width = imageSize.width(); + const int height = imageSize.height(); + + QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied); + clippedRect.fill(0x12345678); + { + QPainter painter(&clippedRect); + painter.setPen(pen); + painter.setClipRect(clipRect); + painter.drawLine(line); + painter.drawLine(line.toLine()); + } + + QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied); + clippedPath.fill(0x12345678); + { + QPainter painter(&clippedPath); + painter.setPen(pen); + painter.setClipPath(clipPath); + painter.drawLine(line); + painter.drawLine(line.toLine()); + } + +#if 0 + if (clippedRect != clippedPath) { + clippedRect.save(QString("clippedRect.png"), "PNG"); + clippedPath.save(QString("clippedPath.png"), "PNG"); + } +#endif + QCOMPARE(clippedRect, clippedPath); + + // repeat with antialiasing + clippedRect.fill(0x12345678); + { + QPainter painter(&clippedRect); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(pen); + painter.setClipRect(clipRect); + painter.drawLine(line); + painter.drawLine(line.toLine()); + } + + clippedPath.fill(0x12345678); + { + QPainter painter(&clippedPath); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(pen); + painter.setClipPath(clipPath); + painter.drawLine(line); + painter.drawLine(line.toLine()); + } + +#if 0 + if (clippedRect != clippedPath) { + clippedRect.save(QString("clippedRect.png"), "PNG"); + clippedPath.save(QString("clippedPath.png"), "PNG"); + } +#endif + QCOMPARE(clippedRect, clippedPath); +} + +void tst_QPainter::clippedPolygon_data() +{ + clippedFillPath_data(); +}; + +void tst_QPainter::clippedPolygon() +{ + QFETCH(QSize, imageSize); + QFETCH(QPainterPath, path); + QPolygonF polygon = path.toFillPolygon(); + QFETCH(QRect, clipRect); + QPainterPath clipPath; + clipPath.addRect(clipRect); + QFETCH(QPen, pen); + QFETCH(QBrush, brush); + + const int width = imageSize.width(); + const int height = imageSize.height(); + + QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied); + clippedRect.fill(0x12345678); + { + QPainter painter(&clippedRect); + painter.setPen(pen); + painter.setBrush(brush); + painter.setClipRect(clipRect); + painter.drawPolygon(polygon); + painter.drawPolygon(polygon.toPolygon()); + } + + QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied); + clippedPath.fill(0x12345678); + { + QPainter painter(&clippedPath); + painter.setPen(pen); + painter.setBrush(brush); + painter.setClipRect(clipRect); + painter.drawPolygon(polygon); + painter.drawPolygon(polygon.toPolygon()); + } + +#if 0 + if (clippedRect != clippedPath) { + clippedRect.save(QString("clippedRect.png"), "PNG"); + clippedPath.save(QString("clippedPath.png"), "PNG"); + } +#endif + QCOMPARE(clippedRect, clippedPath); + + // repeat with antialiasing + + clippedRect.fill(0x12345678); + { + QPainter painter(&clippedRect); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(pen); + painter.setBrush(brush); + painter.setClipRect(clipRect); + painter.drawPolygon(polygon); + painter.drawPolygon(polygon.toPolygon()); + } + + clippedPath.fill(0x12345678); + { + QPainter painter(&clippedPath); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(pen); + painter.setBrush(brush); + painter.setClipRect(clipRect); + painter.drawPolygon(polygon); + painter.drawPolygon(polygon.toPolygon()); + } + +#if 0 + if (clippedRect != clippedPath) { + clippedRect.save(QString("clippedRect.png"), "PNG"); + clippedPath.save(QString("clippedPath.png"), "PNG"); + } +#endif + QCOMPARE(clippedRect, clippedPath); +} + +// this just draws some text that should be clipped in the raster +// paint engine. +void tst_QPainter::clippedText() +{ + for (char ch = 'A'; ch < 'Z'; ++ch) { + //qDebug() << ch; + QFont f; + f.setPixelSize(24); + QFontMetrics metrics(f); + QRect textRect = metrics.boundingRect(QChar(ch)); + + if (textRect.width() <= 8) + continue; + if (textRect.height() <= 8) + continue; + + QRect imageRect = textRect.adjusted(4, 4, -4, -4); + + QImage image(imageRect.size(), QImage::Format_ARGB32_Premultiplied); + + image.fill(qRgba(255, 255, 255, 255)); + { + QPainter painter(&image); + painter.setFont(f); + painter.setPen(Qt::black); + + painter.drawText(0, 0, QChar(ch)); + } + + image.fill(qRgba(255, 255, 255, 255)); + { + QPainter painter(&image); + painter.setFont(f); + painter.setPen(Qt::black); + + painter.drawText(-imageRect.topLeft(), QChar(ch)); + } + + bool foundPixel = false; + for (int x = 0; x < image.width(); ++x) + for (int y = 0; y < image.height(); ++y) + if (image.pixel(x, y) != 0) + foundPixel = true; + // can't QVERIFY(foundPixel) as sometimes all pixels are clipped + // away. For example for 'O' + // just call /some/ function to prevent the compiler from optimizing + // foundPixel away + QString::number(foundPixel); + + //image.save(QString("debug") + ch + ".xpm"); + } + + QVERIFY(true); // reached, don't trigger any valgrind errors +} + +void tst_QPainter::setOpacity_data() +{ + QTest::addColumn<QImage::Format>("destFormat"); + QTest::addColumn<QImage::Format>("srcFormat"); + + QTest::newRow("ARGB32P on ARGB32P") << QImage::Format_ARGB32_Premultiplied + << QImage::Format_ARGB32_Premultiplied; + + QTest::newRow("ARGB32 on ARGB32") << QImage::Format_ARGB32 + << QImage::Format_ARGB32; + + QTest::newRow("RGB32 on RGB32") << QImage::Format_RGB32 + << QImage::Format_RGB32; + + QTest::newRow("RGB16 on RGB16") << QImage::Format_RGB16 + << QImage::Format_RGB16; + + QTest::newRow("ARGB8565_Premultiplied on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied + << QImage::Format_ARGB8565_Premultiplied; + + QTest::newRow("RGB555 on RGB555") << QImage::Format_RGB555 + << QImage::Format_RGB555; + + QTest::newRow("RGB666 on RGB666") << QImage::Format_RGB666 + << QImage::Format_RGB666; + + QTest::newRow("ARGB8555_Premultiplied on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied + << QImage::Format_ARGB8555_Premultiplied; + + QTest::newRow("RGB888 on RGB888") << QImage::Format_RGB888 + << QImage::Format_RGB888; + + QTest::newRow("RGB32 on RGB16") << QImage::Format_RGB16 + << QImage::Format_RGB32; + + QTest::newRow("RGB32 on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied + << QImage::Format_RGB32; + + QTest::newRow("RGB32 on RGB666") << QImage::Format_RGB666 + << QImage::Format_RGB32; + + QTest::newRow("RGB32 on RGB555") << QImage::Format_RGB555 + << QImage::Format_RGB32; + + QTest::newRow("RGB32 on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied + << QImage::Format_RGB32; + + QTest::newRow("RGB32 on RGB888") << QImage::Format_RGB888 + << QImage::Format_RGB32; + + QTest::newRow("RGB16 on RGB32") << QImage::Format_RGB32 + << QImage::Format_RGB16; + + QTest::newRow("ARGB8565_Premultiplied on RGB32") << QImage::Format_RGB32 + << QImage::Format_ARGB8565_Premultiplied; + + QTest::newRow("RGB666 on RGB32") << QImage::Format_RGB32 + << QImage::Format_RGB666; + + QTest::newRow("RGB555 on RGB32") << QImage::Format_RGB32 + << QImage::Format_RGB555; + + QTest::newRow("ARGB8555_Premultiplied on RGB32") << QImage::Format_RGB32 + << QImage::Format_ARGB8555_Premultiplied; + + QTest::newRow("RGB888 on RGB32") << QImage::Format_RGB32 + << QImage::Format_RGB888; + + QTest::newRow("RGB555 on RGB888") << QImage::Format_RGB888 + << QImage::Format_RGB555; + + QTest::newRow("RGB666 on RGB888") << QImage::Format_RGB888 + << QImage::Format_RGB666; + + QTest::newRow("RGB444 on RGB444") << QImage::Format_RGB444 + << QImage::Format_RGB444; +} + +void tst_QPainter::setOpacity() +{ + QFETCH(QImage::Format, destFormat); + QFETCH(QImage::Format, srcFormat); + + const QSize imageSize(12, 12); + const QRect imageRect(QPoint(0, 0), imageSize); + QColor destColor = Qt::black; + QColor srcColor = Qt::white; + + QImage dest(imageSize, destFormat); + QImage src(imageSize, srcFormat); + + QPainter p; + p.begin(&dest); + p.fillRect(imageRect, destColor); + p.end(); + + p.begin(&src); + p.fillRect(imageRect, srcColor); + p.end(); + + p.begin(&dest); + p.setOpacity(0.5); + p.drawImage(imageRect, src, imageRect); + p.end(); + + QImage actual = dest.convertToFormat(QImage::Format_RGB32); + + for (int y = 0; y < actual.height(); ++y) { + QRgb *p = (QRgb *)actual.scanLine(y); + for (int x = 0; x < actual.width(); ++x) { + QVERIFY(qAbs(qRed(p[x]) - 127) <= 0xf); + QVERIFY(qAbs(qGreen(p[x]) - 127) <= 0xf); + QVERIFY(qAbs(qBlue(p[x]) - 127) <= 0xf); + } + } +} + +void tst_QPainter::drawhelper_blend_untransformed_data() +{ + setOpacity_data(); +} + +void tst_QPainter::drawhelper_blend_untransformed() +{ + QFETCH(QImage::Format, destFormat); + QFETCH(QImage::Format, srcFormat); + + const int size = 128; + const QSize imageSize(size, size); + const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing + + QColor destColor(127, 127, 127); + QColor srcColor(Qt::white); + + QImage dest(imageSize, destFormat); + QImage src(imageSize, srcFormat); + + QPainter p; + p.begin(&src); + p.fillRect(paintRect, srcColor); + p.end(); + + QList<qreal> opacities = (QList<qreal>() << 0.0 << 0.1 << 0.01 << 0.4 + << 0.5 << 0.6 << 0.9 << 1.0); + foreach (qreal opacity, opacities) { + p.begin(&dest); + p.fillRect(paintRect, destColor); + + p.setOpacity(opacity); + p.drawImage(paintRect, src, paintRect); + p.end(); + + // sanity check: make sure all pixels are equal + QImage expected(size - 2, size, destFormat); + p.begin(&expected); + p.fillRect(0, 0, expected.width(), expected.height(), + QColor(dest.pixel(1, 0))); + p.end(); + + const QImage subDest(dest.bits() + dest.depth() / 8, + dest.width() - 2, dest.height(), + dest.bytesPerLine(), dest.format()); + + if (dest.format() == QImage::Format_ARGB8565_Premultiplied || + dest.format() == QImage::Format_ARGB8555_Premultiplied) { + // Test skipped due to rounding errors... + continue; + } +#if 0 + if (subDest != expected) { + qDebug() << "size" << size << "opacity" << opacity; + for (int j = 0; j < expected.height(); ++j) { + for (int i = 0; i < expected.width(); ++i) { + if (expected.pixel(i,j) != subDest.pixel(i,j)) + qDebug() << i << j << hex << expected.pixel(i, j) + << subDest.pixel(i, j); + } + } + } +#endif + QCOMPARE(subDest, expected); + } +} + +void tst_QPainter::drawhelper_blend_tiled_untransformed_data() +{ + setOpacity_data(); +} + +void tst_QPainter::drawhelper_blend_tiled_untransformed() +{ + QFETCH(QImage::Format, destFormat); + QFETCH(QImage::Format, srcFormat); + + const int size = 128; + const QSize imageSize(size, size); + const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing + + QColor destColor(127, 127, 127); + QColor srcColor(Qt::white); + + QImage dest(imageSize, destFormat); + QImage src(imageSize / 2, srcFormat); + + QPainter p; + p.begin(&src); + p.fillRect(QRect(QPoint(0, 0), imageSize/ 2), srcColor); + p.end(); + + const QBrush brush(src); + + QList<qreal> opacities = (QList<qreal>() << 0.0 << 0.1 << 0.01 << 0.4 + << 0.5 << 0.6 << 0.9 << 1.0); + foreach (qreal opacity, opacities) { + p.begin(&dest); + p.fillRect(paintRect, destColor); + + p.setOpacity(opacity); + p.fillRect(paintRect, brush); + p.end(); + + // sanity check: make sure all pixels are equal + QImage expected(size - 2, size, destFormat); + p.begin(&expected); + p.fillRect(0, 0, expected.width(), expected.height(), + QColor(dest.pixel(1, 0))); + p.end(); + + const QImage subDest(dest.bits() + dest.depth() / 8, + dest.width() - 2, dest.height(), + dest.bytesPerLine(), dest.format()); + + if (dest.format() == QImage::Format_ARGB8565_Premultiplied || + dest.format() == QImage::Format_ARGB8555_Premultiplied) { + // Skipping test due to rounding errors. Test needs rewrite + continue; + } +#if 0 + if (subDest != expected) { + qDebug() << "size" << size << "opacity" << opacity; + for (int j = 0; j < expected.height(); ++j) { + for (int i = 0; i < expected.width(); ++i) { + if (expected.pixel(i,j) != subDest.pixel(i,j)) + qDebug() << i << j << hex << expected.pixel(i, j) + << subDest.pixel(i, j); + } + } + } +#endif + QCOMPARE(subDest, expected); + } +} + +static QPaintEngine::PaintEngineFeatures no_porter_duff() +{ + QPaintEngine::PaintEngineFeatures features = QPaintEngine::AllFeatures; + return features & ~QPaintEngine::PorterDuff; +} + +class DummyPaintEngine : public QPaintEngine, public QPaintDevice +{ +public: + DummyPaintEngine() : QPaintEngine(no_porter_duff()) {} + virtual bool begin(QPaintDevice *) { return true; } + virtual bool end() { return true; } + + virtual void updateState(const QPaintEngineState &) {} + virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {} + + virtual Type type() const { return User; } + + virtual QPaintEngine *paintEngine() const { return (QPaintEngine *)this; } + + virtual int metric(PaintDeviceMetric metric) const { Q_UNUSED(metric); return 0; }; +}; + +static bool success; + +void porterDuff_warningChecker(QtMsgType type, const char *msg) +{ + if (type == QtWarningMsg && msg == QLatin1String("QPainter::setCompositionMode: PorterDuff modes not supported on device")) + success = false; +} + +void tst_QPainter::porterDuff_warning() +{ + QtMsgHandler old = qInstallMsgHandler(porterDuff_warningChecker); + DummyPaintEngine dummy; + QPainter p(&dummy); + + success = true; + p.setCompositionMode(QPainter::CompositionMode_Source); + QVERIFY(success); + + success = true; + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + QVERIFY(success); + + success = true; + p.setCompositionMode(QPainter::CompositionMode_DestinationOver); + QVERIFY(!success); + + QVERIFY(qInstallMsgHandler(old) == porterDuff_warningChecker); +} + +class quint24 +{ +public: + inline quint24(quint32 v) + { + data[0] = qBlue(v); + data[1] = qGreen(v); + data[2] = qRed(v); + } + + inline operator quint32 () + { + return qRgb(data[2], data[1], data[0]); + } + + inline bool operator==(const quint24 &v) const { + return (data[0] == v.data[0] && data[1] == v.data[1] && data[2] == v.data[2]); + } + + uchar data[3]; +} Q_PACKED; + +void tst_QPainter::drawhelper_blend_color() +{ + QImage dest(32, 32, QImage::Format_ARGB8555_Premultiplied); + dest.fill(0xff000000); + + { + QPainter p(&dest); + p.fillRect(0, 0, dest.width(), dest.height(), QColor(255, 0, 0, 127)); + } + + QImage expected(32, 32, QImage::Format_ARGB8555_Premultiplied); + expected.fill(0xff3c007f); + + QCOMPARE(dest.pixel(1, 1), expected.pixel(1, 1)); + QCOMPARE(dest, expected); +} + +class ViewportTestWidget : public QWidget +{ +public: + ViewportTestWidget(QWidget *parent = 0) : QWidget(parent), hasPainted(false) {} + QSize sizeHint() const { + return QSize(100, 100); + } + + QRect viewport; + bool hasPainted; + +protected: + void paintEvent(QPaintEvent *) { + hasPainted = true; + QPainter p(this); + viewport = p.viewport(); + } +}; + +void tst_QPainter::childWidgetViewport() +{ + QWidget parent; + parent.setAutoFillBackground(true); + parent.resize(200, 200); + ViewportTestWidget child(&parent); + child.setAutoFillBackground(true); + parent.show(); + parent.update(); + qApp->processEvents(); + + if (child.hasPainted) { + QCOMPARE(child.viewport, QRect(QPoint(0, 0), child.sizeHint())); + } else { + qWarning("Failed to ensure that paintEvent has been run. Could not run test."); + } +} + +void tst_QPainter::fillRect_objectBoundingModeGradient() +{ + QImage a(10, 10, QImage::Format_ARGB32_Premultiplied); + a.fill(0x0); + QImage b = a; + + QLinearGradient g(QPoint(0, 0), QPoint(0, 1)); + g.setColorAt(0, Qt::red); + g.setColorAt(1, Qt::blue); + g.setCoordinateMode(QGradient::ObjectBoundingMode); + + QPainter p(&a); + p.fillRect(QRect(0, 0, a.width(), a.height()), g); + p.end(); + + QPainterPath path; + path.addRect(0, 0, a.width(), a.height()); + + p.begin(&b); + p.fillPath(path, g); + p.end(); + + QCOMPARE(a, b); +} + +void tst_QPainter::fillRect_stretchToDeviceMode() +{ + QImage img(64, 64, QImage::Format_ARGB32_Premultiplied); + + QLinearGradient g(QPoint(0, 0), QPoint(0, 1)); + g.setCoordinateMode(QGradient::StretchToDeviceMode); + + QPainter p(&img); + p.fillRect(img.rect(), g); + p.end(); + + for (int i = 1; i < img.height(); ++i) + QVERIFY(img.pixel(0, i) != img.pixel(0, i-1)); +} + +void tst_QPainter::monoImages() +{ + Qt::GlobalColor colorPairs[][2] = { + { Qt::white, Qt::black }, + { Qt::color0, Qt::color1 }, + { Qt::red, Qt::blue } + }; + + const int numColorPairs = sizeof(colorPairs) / sizeof(QRgb[2]); + + QImage transparent(2, 2, QImage::Format_ARGB32_Premultiplied); + transparent.fill(0x0); + + for (int i = 1; i < QImage::NImageFormats; ++i) { + for (int j = 0; j < numColorPairs; ++j) { + const QImage::Format format = QImage::Format(i); + if (format == QImage::Format_Indexed8) + continue; + + QImage img(2, 2, format); + + if (img.colorCount() > 0) { + img.setColor(0, QColor(colorPairs[j][0]).rgba()); + img.setColor(1, QColor(colorPairs[j][1]).rgba()); + } + + img.fill(0x0); + QPainter p(&img); + p.fillRect(0, 0, 2, 2, colorPairs[j][0]); + p.fillRect(0, 0, 1, 1, colorPairs[j][1]); + p.fillRect(1, 1, 1, 1, colorPairs[j][1]); + p.end(); + + QImage original = img; + + p.begin(&img); + p.drawImage(0, 0, transparent); + p.end(); + + // drawing a transparent image on top of another image + // should not change the image + QCOMPARE(original, img); + + if (img.colorCount() == 0) + continue; + + for (int k = 0; k < 2; ++k) { + QPainter p(&img); + p.fillRect(0, 0, 2, 2, colorPairs[j][k]); + p.end(); + + QImage argb32p(2, 2, QImage::Format_ARGB32_Premultiplied); + p.begin(&argb32p); + p.fillRect(0, 0, 2, 2, colorPairs[j][k]); + p.end(); + + QCOMPARE(argb32p, img.convertToFormat(argb32p.format())); + + // drawing argb32p image on mono image + p.begin(&img); + p.drawImage(0, 0, argb32p); + p.end(); + + QCOMPARE(argb32p, img.convertToFormat(argb32p.format())); + + // drawing mono image on argb32p image + p.begin(&argb32p); + p.drawImage(0, 0, img); + p.end(); + + QCOMPARE(argb32p, img.convertToFormat(argb32p.format())); + } + } + } +} + +#if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_CC_MSVC) && !defined(Q_OS_SOLARIS) && !defined(Q_OS_SYMBIAN) +#include <fenv.h> + +static const QString fpeExceptionString(int exception) +{ +#ifdef FE_INEXACT + if (exception & FE_INEXACT) + return QLatin1String("Inexact result"); +#endif + if (exception & FE_UNDERFLOW) + return QLatin1String("Underflow"); + if (exception & FE_OVERFLOW) + return QLatin1String("Overflow"); + if (exception & FE_DIVBYZERO) + return QLatin1String("Divide by zero"); + if (exception & FE_INVALID) + return QLatin1String("Invalid operation"); + return QLatin1String("No exception"); +} + +class FpExceptionChecker +{ +public: + FpExceptionChecker(int exceptionMask) + : m_exceptionMask(exceptionMask) + { + feclearexcept(m_exceptionMask); + } + + ~FpExceptionChecker() + { + const int exceptions = fetestexcept(m_exceptionMask); + QVERIFY2(!exceptions, qPrintable(QLatin1String("Floating point exception: ") + fpeExceptionString(exceptions))); + } + +private: + int m_exceptionMask; +}; + +void fpe_rasterizeLine_task232012() +{ + FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO); + QImage img(128, 128, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + QPainter p(&img); + + p.setBrush(Qt::black); + p.drawRect(QRectF(0, 0, 5, 0)); + p.drawRect(QRectF(0, 0, 0, 5)); +} + +void fpe_pixmapTransform() +{ + FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO); + + QImage img(128, 128, QImage::Format_ARGB32_Premultiplied); + + QPainter p(&img); + + const qreal scaleFactor = 0.001; + const int translateDistance = 1000000; + + p.setPen(Qt::red); + p.setBrush(QBrush(Qt::red,Qt::Dense6Pattern)); + + for (int i = 0; i < 2; ++i) { + p.setRenderHint(QPainter::SmoothPixmapTransform, i); + + p.resetTransform(); + p.scale(1.1, 1.1); + p.translate(translateDistance, 0); + p.drawRect(-translateDistance, 0, 100, 100); + + p.resetTransform(); + p.scale(scaleFactor, scaleFactor); + p.drawRect(QRectF(0, 0, 1 / scaleFactor, 1 / scaleFactor)); + } +} + +void fpe_zeroLengthLines() +{ + FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO); + + QImage img(128, 128, QImage::Format_ARGB32_Premultiplied); + + QPainter p(&img); + + p.setPen(QPen(Qt::black, 3)); + p.drawLine(64, 64, 64, 64); +} + +void fpe_divByZero() +{ + FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO); + + QImage img(128, 128, QImage::Format_ARGB32_Premultiplied); + + QPainter p(&img); + + p.setRenderHint(QPainter::Antialiasing); + + p.drawRect(QRectF(10, 10, 100, 0)); + p.drawRect(QRectF(10, 10, 0, 100)); + + p.drawRect(QRect(10, 10, 100, 0)); + p.drawRect(QRect(10, 10, 0, 100)); + + p.fillRect(QRectF(10, 10, 100, 0), Qt::black); + p.fillRect(QRectF(10, 10, 0, 100), Qt::black); + + p.fillRect(QRect(10, 10, 100, 0), Qt::black); + p.fillRect(QRect(10, 10, 0, 100), Qt::black); +} + +void fpe_steepSlopes() +{ + FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO); + + QImage img(1024, 1024, QImage::Format_ARGB32_Premultiplied); + + QFETCH(QTransform, transform); + QFETCH(QLineF, line); + QFETCH(bool, antialiased); + + QPainter p(&img); + + p.setPen(QPen(Qt::black, 1)); + p.setRenderHint(QPainter::Antialiasing, antialiased); + p.setTransform(transform); + + p.drawLine(line); +} + +void fpe_radialGradients() +{ + FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO); + + QImage img(21, 21, QImage::Format_ARGB32_Premultiplied); + img.fill(0); + + double m = img.width() * 0.5; + + QPainter p(&img); + p.setRenderHints(QPainter::Antialiasing); + p.setPen(Qt::NoPen); + p.setBrush(QRadialGradient(m, m, m)); + p.drawEllipse(img.rect()); +} + +#define FPE_TEST(x) \ +void tst_QPainter::x() \ +{ \ + ::x(); \ +} +#else +#define FPE_TEST(x) \ +void tst_QPainter::x() \ +{ \ + QSKIP("Floating point exception checking (fenv.h) not available", SkipAll); \ +} +#endif + +FPE_TEST(fpe_rasterizeLine_task232012) +FPE_TEST(fpe_pixmapTransform) +FPE_TEST(fpe_zeroLengthLines) +FPE_TEST(fpe_divByZero) +FPE_TEST(fpe_steepSlopes) +FPE_TEST(fpe_radialGradients) + +void tst_QPainter::fpe_steepSlopes_data() +{ + QTest::addColumn<QTransform>("transform"); + QTest::addColumn<QLineF>("line"); + QTest::addColumn<bool>("antialiased"); + + { + const qreal dsin = 0.000014946676875461832484392500630665523431162000633776187896728515625; + const qreal dcos = 0.9999999998882984630910186751862056553363800048828125; + + const QTransform transform = QTransform(QMatrix(dcos, dsin, -dsin, dcos, 64, 64)); + const QLineF line(2, 2, 2, 6); + + QTest::newRow("task 207147 aa") << transform << line << true; + QTest::newRow("task 207147 no aa") << transform << line << false; + } + + { + QTransform transform; + transform.rotate(0.0000001); + const QLineF line(5, 5, 10, 5); + + QTest::newRow("task 166702 aa") << transform << line << true; + QTest::newRow("task 166702 no aa") << transform << line << false; + } + + { + const QTransform transform; + const QLineF line(2.5, 2.5, 2.5 + 1/256., 60000.5); + + QTest::newRow("steep line aa") << transform << line << true; + QTest::newRow("steep line no aa") << transform << line << false; + } + + { + const QTransform transform; + const QLineF line(2.5, 2.5, 2.5 + 1/256., 1024); + + QTest::newRow("steep line 2 aa") << transform << line << true; + QTest::newRow("steep line 2 no aa") << transform << line << false; + } + + { + const QTransform transform; + const QLineF line(2.5, 2.5, 2.5 + 1/64., 1024); + + QTest::newRow("steep line 3 aa") << transform << line << true; + QTest::newRow("steep line 3 no aa") << transform << line << false; + } +} + +qreal randf() +{ + return rand() / (RAND_MAX + 1.0); +} + +QPointF randInRect(const QRectF &rect) +{ + const qreal x = rect.left() + rect.width() * randf(); + const qreal y = rect.top() + rect.height() * randf(); + + return QPointF(x, y); +} + +void tst_QPainter::rasterizer_asserts() +{ + QImage img(64, 64, QImage::Format_ARGB32_Premultiplied); + + QRectF middle(QPointF(0, 0), img.size()); + QRectF left = middle.translated(-middle.width(), 0); + QRectF right = middle.translated(middle.width(), 0); + + QPainter p(&img); + img.fill(Qt::white); + p.setCompositionMode(QPainter::CompositionMode_Destination); + for (int i = 0; i < 100000; ++i) { + QPainterPath path; + path.moveTo(randInRect(middle)); + path.lineTo(randInRect(left)); + path.lineTo(randInRect(right)); + + p.fillPath(path, Qt::black); + } +} + +void tst_QPainter::rasterizer_negativeCoords() +{ + QImage img(64, 64, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + + QImage original = img; + + QPainter p(&img); + p.rotate(90); + p.fillRect(0, 0, 70, 50, Qt::black); + + // image should not have changed + QCOMPARE(img.pixel(0, 0), 0x0U); + QCOMPARE(img, original); +} + +void tst_QPainter::blendOverFlow_data() +{ + QTest::addColumn<QImage::Format>("format"); + QTest::addColumn<int>("width"); + QTest::addColumn<int>("height"); + + QImage::Format format = QImage::Format_ARGB8555_Premultiplied; + QTest::newRow("555,1,1") << format << 1 << 1; + QTest::newRow("555,2,2") << format << 2 << 2; + QTest::newRow("555,10,10") << format << 10 << 10; + + format = QImage::Format_ARGB8565_Premultiplied; + QTest::newRow("565,1,1") << format << 1 << 1; + QTest::newRow("565,2,2") << format << 2 << 2; + QTest::newRow("565,10,10") << format << 10 << 10; +} + +void tst_QPainter::blendOverFlow() +{ + QFETCH(QImage::Format, format); + QFETCH(int, width); + QFETCH(int, height); + + QImage dest(width, height, format); + QImage src(width, height, format); + + { + QPainter p(&dest); + p.fillRect(0, 0, width, height, Qt::green); + } + QImage expected = dest; + + { + QPainter p(&src); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, width, height, QColor(0, 255, 0, 6)); + } + + { + QPainter p(&dest); + p.drawImage(0, 0, src); + } + + QCOMPARE(dest.pixel(0, 0), expected.pixel(0, 0)); + QCOMPARE(dest, expected); +} + +void tst_QPainter::largeImagePainting_data() +{ + QTest::addColumn<int>("width"); + QTest::addColumn<int>("height"); + QTest::addColumn<bool>("antialiased"); + + QTest::newRow("tall") << 1 << 32767 << false; + QTest::newRow("tall aa") << 1 << 32767 << true; + QTest::newRow("wide") << 32767 << 1 << false; + QTest::newRow("wide aa") << 32767 << 1 << true; +} + +void tst_QPainter::largeImagePainting() +{ + QPainterPath path; + path.addRect(0, 0, 1, 1); + path.addRect(2, 0, 1, 1); + path.addRect(0, 2, 1, 1); + + QFETCH(int, width); + QFETCH(int, height); + QFETCH(bool, antialiased); + + QImage img(width, height, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + + QPainter p(&img); + p.setPen(Qt::NoPen); + p.setBrush(Qt::white); + + p.setRenderHint(QPainter::Antialiasing, antialiased); + + for (int i = 0; i < img.width(); i += 4) { + p.drawPath(path); + p.translate(4, 0); + } + + p.resetMatrix(); + + for (int i = 4; i < img.height(); i += 4) { + p.translate(0, 4); + p.drawPath(path); + } + + for (int i = 0; i < img.width(); ++i) { + if (i % 2) + QCOMPARE(img.pixel(i, 0), 0x0U); + else + QCOMPARE(img.pixel(i, 0), 0xffffffffU); + } + + for (int i = 1; i < img.height(); ++i) { + if (i % 2) + QCOMPARE(img.pixel(0, i), 0x0U); + else + QCOMPARE(img.pixel(0, i), 0xffffffffU); + } +} + +void tst_QPainter::imageScaling_task206785() +{ + QImage src(32, 2, QImage::Format_ARGB32_Premultiplied); + src.fill(0xffffffff); + + QImage dst(128, 128, QImage::Format_ARGB32_Premultiplied); + + QImage expected(128, 128, QImage::Format_ARGB32_Premultiplied); + expected.fill(0xffffffff); + + for (int i = 1; i < 5; ++i) { + qreal scale = i / qreal(5); + + dst.fill(0xff000000); + + QPainter p(&dst); + p.scale(dst.width() / qreal(src.width()), scale); + + for (int y = 0; y * scale < dst.height(); ++y) + p.drawImage(0, y, src); + + p.end(); + + QCOMPARE(dst, expected); + } +} + +#define FOR_EACH_NEIGHBOR_8 for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if (dx != 0 || dy != 0) +#define FOR_EACH_NEIGHBOR_4 for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if ((dx == 0) != (dy == 0)) + +uint qHash(const QPoint &point) +{ + return qHash(qMakePair(point.x(), point.y())); +} + +bool verifyOutlineFillConsistency(const QImage &img, QRgb outside, QRgb inside, QRgb outline) +{ + if (img.pixel(img.width() / 2, img.height() / 2) != inside) + return false; + + int x = img.width() / 2; + int y = img.height() / 2; + + while (img.pixel(++x, y) == inside) + ; + + if (img.pixel(x, y) != outline) + return false; + + QQueue<QPoint> discovered; + discovered.enqueue(QPoint(x, y)); + + QVector<bool> visited(img.width() * img.height()); + visited.fill(false); + + while (!discovered.isEmpty()) { + QPoint p = discovered.dequeue(); + QRgb pixel = img.pixel(p.x(), p.y()); + + bool &v = visited[p.y() * img.width() + p.x()]; + if (v) + continue; + v = true; + + if (pixel == outline) { + FOR_EACH_NEIGHBOR_8 { + QPoint x(p.x() + dx, p.y() + dy); + discovered.enqueue(x); + } + } else { + FOR_EACH_NEIGHBOR_4 { + if ((dx == 0) == (dy == 0)) + continue; + QRgb neighbor = img.pixel(p.x() + dx, p.y() + dy); + if ((pixel == inside && neighbor == outside) || + (pixel == outside && neighbor == inside)) + return false; + } + } + } + + return true; +} + +#undef FOR_EACH_NEIGHBOR_8 +#undef FOR_EACH_NEIGHBOR_4 + +void tst_QPainter::outlineFillConsistency() +{ + QSKIP("currently broken...", SkipAll); + return; + + QImage dst(256, 256, QImage::Format_ARGB32_Premultiplied); + + QPolygonF poly; + poly << QPointF(5, -100) << QPointF(-70, 20) << QPointF(95, 25); + + QPen pen(Qt::red); + QBrush brush(Qt::black); + + QRgb background = 0xffffffff; + for (int i = 0; i < 360; ++i) { + dst.fill(background); + + QPainter p(&dst); + p.translate(dst.width() / 2, dst.height() / 2); + + QPolygonF copy = poly; + for (int j = 0; j < copy.size(); ++j) + copy[j] = QTransform().rotate(i).map(copy[j]); + + p.setPen(pen); + p.setBrush(brush); + p.drawPolygon(copy); + p.end(); + +#if 0 + if (!verifyOutlineFillConsistency(dst, background, p.brush().color().rgba(), p.pen().color().rgba())) + dst.save(QString("outlineFillConsistency-%1.png").arg(i)); +#endif + + QVERIFY(verifyOutlineFillConsistency(dst, background, brush.color().rgba(), pen.color().rgba())); + } +} + +void tst_QPainter::drawImage_task217400_data() +{ + QTest::addColumn<QImage::Format>("format"); + + QTest::newRow("444") << QImage::Format_ARGB4444_Premultiplied; + QTest::newRow("555") << QImage::Format_ARGB8555_Premultiplied; + QTest::newRow("565") << QImage::Format_ARGB8565_Premultiplied; +// QTest::newRow("666") << QImage::Format_ARGB6666_Premultiplied; + QTest::newRow("888p") << QImage::Format_ARGB32_Premultiplied; + QTest::newRow("888") << QImage::Format_ARGB32; +} + +void tst_QPainter::drawImage_task217400() +{ + QFETCH(QImage::Format, format); + + const QImage src = QImage(QString(SRCDIR) + "/task217400.png") + .convertToFormat(format); + QVERIFY(!src.isNull()); + + QImage expected(src.size(), format); + { + QPainter p(&expected); + p.fillRect(0, 0, expected.width(), expected.height(), Qt::white); + p.drawImage(0, 0, src); + } + + for (int i = 1; i <= 4; ++i) { + QImage dest(src.width() + i, src.height(), format); + { + QPainter p(&dest); + p.fillRect(0, 0, dest.width(), dest.height(), Qt::white); + p.drawImage(i, 0, src); + } + + const QImage result = dest.copy(i, 0, src.width(), src.height()); + +#if 0 + if (result != expected) { + qDebug("i=%i", i); + result.save("result.png"); + expected.save("expected.png"); + } +#endif + QCOMPARE(result, expected); + } +} + +void tst_QPainter::drawImage_task258776() +{ + QImage src(16, 16, QImage::Format_RGB888); + QImage dest(33, 33, QImage::Format_RGB888); + src.fill(0x00ff00); + dest.fill(0x0000ff); + + QPainter painter(&dest); + painter.drawImage(QRectF(0.499, 0.499, 32, 32), src, QRectF(0, 0, 16, 16)); + painter.end(); + + QImage expected(33, 33, QImage::Format_RGB32); + expected.fill(0xff0000); + + painter.begin(&expected); + painter.drawImage(QRectF(0, 0, 32, 32), src); + painter.end(); + + dest = dest.convertToFormat(QImage::Format_RGB32); + + dest.save("dest.png"); + expected.save("expected.png"); + QCOMPARE(dest, expected); +} + +void tst_QPainter::clipRectSaveRestore() +{ + QImage img(64, 64, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + + QPainter p(&img); + p.setClipRect(QRect(0, 0, 10, 10)); + p.save(); + p.setClipRect(QRect(5, 5, 5, 5), Qt::IntersectClip); + p.restore(); + p.fillRect(0, 0, 64, 64, Qt::black); + p.end(); + + QCOMPARE(img.pixel(0, 0), QColor(Qt::black).rgba()); +} + +void tst_QPainter::clippedImage() +{ + QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + + QImage src(16, 16, QImage::Format_RGB32); + src.fill(QColor(Qt::red).rgba()); + + QPainter p(&img); + p.setClipRect(QRect(1, 1, 14, 14)); + p.drawImage(0, 0, src); + p.end(); + + QCOMPARE(img.pixel(0, 0), 0x0U); + QCOMPARE(img.pixel(1, 1), src.pixel(1, 1)); +} + +void tst_QPainter::stateResetBetweenQPainters() +{ + QImage img(16, 16, QImage::Format_ARGB32); + + { + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, 16, 16, Qt::red); + } + + { + QPainter p2(&img); + p2.fillRect(0, 0, 16, 16, QColor(0, 0, 255, 63)); + } + + img.save("foo.png"); + + QVERIFY(img.pixel(0, 0) != qRgba(0, 0, 255, 63)); + QVERIFY(qRed(img.pixel(0, 0)) > 0); // We didn't erase the red channel... + QVERIFY(qBlue(img.pixel(0, 0)) < 255); // We blended the blue channel +} + +void tst_QPainter::drawRect_task215378() +{ + QImage img(11, 11, QImage::Format_ARGB32_Premultiplied); + img.fill(QColor(Qt::white).rgba()); + + QPainter p(&img); + p.setPen(QColor(127, 127, 127, 127)); + p.drawRect(0, 0, 10, 10); + p.end(); + + QCOMPARE(img.pixel(0, 0), img.pixel(1, 0)); + QCOMPARE(img.pixel(0, 0), img.pixel(0, 1)); + QVERIFY(img.pixel(0, 0) != img.pixel(1, 1)); +} + +void tst_QPainter::drawRect_task247505() +{ + QImage a(10, 10, QImage::Format_ARGB32_Premultiplied); + a.fill(0); + QImage b = a; + + QPainter p(&a); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + p.drawRect(QRectF(10, 0, -10, 10)); + p.end(); + p.begin(&b); + p.setPen(Qt::NoPen); + p.setBrush(Qt::black); + p.drawRect(QRectF(0, 0, 10, 10)); + p.end(); + + QCOMPARE(a, b); +} + +void tst_QPainter::drawImage_data() +{ + QTest::addColumn<int>("x"); + QTest::addColumn<int>("y"); + QTest::addColumn<int>("w"); + QTest::addColumn<int>("h"); + QTest::addColumn<QImage::Format>("srcFormat"); + QTest::addColumn<QImage::Format>("dstFormat"); + + for (int srcFormat = QImage::Format_Mono; srcFormat < QImage::NImageFormats; ++srcFormat) { + for (int dstFormat = QImage::Format_Mono; dstFormat < QImage::NImageFormats; ++dstFormat) { + if (dstFormat == QImage::Format_Indexed8) + continue; + for (int odd_x = 0; odd_x <= 1; ++odd_x) { + for (int odd_width = 0; odd_width <= 1; ++odd_width) { + QString description = + QString("srcFormat %1, dstFormat %2, odd x: %3, odd width: %4") + .arg(srcFormat).arg(dstFormat).arg(odd_x).arg(odd_width); + + QTest::newRow(qPrintable(description)) << (10 + odd_x) << 10 << (20 + odd_width) << 20 + << QImage::Format(srcFormat) + << QImage::Format(dstFormat); + } + } + } + } +} + +bool verifyImage(const QImage &img, int x, int y, int w, int h, uint background) +{ + int imgWidth = img.width(); + int imgHeight = img.height(); + for (int i = 0; i < imgHeight; ++i) { + for (int j = 0; j < imgWidth; ++j) { + uint pixel = img.pixel(j, i); + bool outside = j < x || j >= (x + w) || i < y || i >= (y + h); + if (outside != (pixel == background)) { + //printf("%d %d, expected %x, got %x, outside: %d\n", x, y, background, pixel, outside); + return false; + } + } + } + + return true; +} + +void tst_QPainter::drawImage() +{ + QFETCH(int, x); + QFETCH(int, y); + QFETCH(int, w); + QFETCH(int, h); + QFETCH(QImage::Format, srcFormat); + QFETCH(QImage::Format, dstFormat); + + QImage dst(40, 40, QImage::Format_RGB32); + dst.fill(0xffffffff); + + dst = dst.convertToFormat(dstFormat); + uint background = dst.pixel(0, 0); + + QImage src(w, h, QImage::Format_RGB32); + src.fill(0xff000000); + src = src.convertToFormat(srcFormat); + + QPainter p(&dst); + p.drawImage(x, y, src); + p.end(); + + QVERIFY(verifyImage(dst, x, y, w, h, background)); +} + +void tst_QPainter::imageCoordinateLimit() +{ + QImage img(64, 40000, QImage::Format_MonoLSB); + QPainter p(&img); + p.drawText(10, 36000, QLatin1String("foo")); + p.setPen(QPen(Qt::black, 2)); + p.drawLine(10, 0, 60, 40000); + + p.setRenderHint(QPainter::Antialiasing); + p.drawLine(10, 0, 60, 40000); +} + + +void tst_QPainter::imageBlending_data() +{ + QTest::addColumn<QImage::Format>("sourceFormat"); + QTest::addColumn<QImage::Format>("destFormat"); + QTest::addColumn<int>("error"); + + int error_rgb565 = ((1<<3) + (1<<2) + (1<<3)); + QTest::newRow("rgb565_on_rgb565") << QImage::Format_RGB16 + << QImage::Format_RGB16 + << 0; + QTest::newRow("argb8565_on_rgb565") << QImage::Format_ARGB8565_Premultiplied + << QImage::Format_RGB16 + << error_rgb565; + + QTest::newRow("rgb32_on_rgb565") << QImage::Format_RGB32 + << QImage::Format_RGB16 + << error_rgb565; + + QTest::newRow("argb32pm_on_rgb565") << QImage::Format_ARGB32_Premultiplied + << QImage::Format_RGB16 + << error_rgb565; +} + +int diffColor(quint32 ap, quint32 bp) +{ + int a = qAlpha(ap) - qAlpha(bp); + int r = qRed(ap) - qRed(bp); + int b = qBlue(ap) - qBlue(bp); + int g = qBlue(ap) - qBlue(bp); + + return qAbs(a) + qAbs(r) + qAbs(g) + qAbs(b); +} + +// this test assumes premultiplied pixels... + +void tst_QPainter::imageBlending() +{ + QFETCH(QImage::Format, sourceFormat); + QFETCH(QImage::Format, destFormat); + QFETCH(int, error); + + QImage dest; + { + QImage orig_dest(6, 6, QImage::Format_ARGB32_Premultiplied); + orig_dest.fill(0); + QPainter p(&orig_dest); + p.fillRect(0, 0, 6, 3, QColor::fromRgbF(1, 0, 0)); + p.fillRect(3, 0, 3, 6, QColor::fromRgbF(0, 0, 1, 0.5)); + p.end(); + dest = orig_dest.convertToFormat(destFormat); + + // An image like this: (r = red, m = magenta, b = light alpha blue, 0 = transparent) + // r r r m m m + // r r r m m m + // r r r m m m + // 0 0 0 b b b + // 0 0 0 b b b + // 0 0 0 b b b + } + + QImage source; + { + QImage orig_source(6, 6, QImage::Format_ARGB32_Premultiplied); + orig_source.fill(0); + QPainter p(&orig_source); + p.fillRect(1, 1, 4, 4, QColor::fromRgbF(0, 1, 0, 0.5)); + p.fillRect(2, 2, 2, 2, QColor::fromRgbF(0, 1, 0)); + p.end(); + source = orig_source.convertToFormat(sourceFormat); + + // An image like this: (0 = transparent, . = green at 0.5 alpha, g = opaque green. + // 0 0 0 0 0 0 + // 0 . . . . 0 + // 0 . g g . 0 + // 0 . g g . 0 + // 0 . . . . 0 + // 0 0 0 0 0 0 + } + + QPainter p(&dest); + p.drawImage(0, 0, source); + p.end(); + + // resulting image: + // r r r m m m + // r r. r. m. m. m + // r r. g g m. m + // 0 . g g b. b + // 0 . . b. b. b + // 0 0 0 b b b + + // the g pixels, always green.. + QVERIFY(diffColor(dest.pixel(2, 2), 0xff00ff00) <= error); // g + + if (source.hasAlphaChannel()) { + QVERIFY(diffColor(dest.pixel(0, 0), 0xffff0000) <= error); // r + QVERIFY(diffColor(dest.pixel(5, 0), 0xff7f007f) <= error); // m + QVERIFY(diffColor(dest.pixel(1, 1), 0xff7f7f00) <= error); // r. + QVERIFY(diffColor(dest.pixel(4, 1), 0xff3f7f3f) <= error); // m. + if (dest.hasAlphaChannel()) { + QVERIFY(diffColor(dest.pixel(1, 3), 0x7f007f00) <= error); // . + QVERIFY(diffColor(dest.pixel(4, 3), 0x7f007f3f) <= error); // b. + QVERIFY(diffColor(dest.pixel(4, 3), 0x7f007f3f) <= error); // b. + QVERIFY(diffColor(dest.pixel(4, 4), 0x7f00007f) <= error); // b + QVERIFY(diffColor(dest.pixel(4, 0), 0) <= 0); // 0 + } + } else { + QVERIFY(diffColor(dest.pixel(0, 0), 0xff000000) <= 0); + QVERIFY(diffColor(dest.pixel(1, 1), 0xff007f00) <= error); + } +} + +void tst_QPainter::imageBlending_clipped() +{ + QImage src(20, 20, QImage::Format_RGB16); + QPainter p(&src); + p.fillRect(src.rect(), Qt::red); + p.end(); + + QImage dst(40, 20, QImage::Format_RGB16); + p.begin(&dst); + p.fillRect(dst.rect(), Qt::white); + p.end(); + + QImage expected = dst; + + p.begin(&dst); + p.setClipRect(QRect(23, 0, 20, 20)); + + // should be completely clipped + p.drawImage(QRectF(3, 0, 20, 20), src); + p.end(); + + // dst should be left unchanged + QCOMPARE(dst, expected); +} + +void tst_QPainter::paintOnNullPixmap() +{ + QPixmap pix(16, 16); + + QPixmap textPixmap; + QPainter p(&textPixmap); + p.drawPixmap(10, 10, pix); + p.end(); + + QPixmap textPixmap2(16,16); + p.begin(&textPixmap2); + p.end(); +} + +void tst_QPainter::checkCompositionMode() +{ + QImage refImage(50,50,QImage::Format_ARGB32); + QPainter painter(&refImage); + painter.fillRect(QRect(0,0,50,50),Qt::blue); + + QImage testImage(50,50,QImage::Format_ARGB32); + QPainter p(&testImage); + p.fillRect(QRect(0,0,50,50),Qt::red); + p.save(); + p.setCompositionMode(QPainter::CompositionMode_SourceOut); + p.restore(); + p.fillRect(QRect(0,0,50,50),Qt::blue); + + QCOMPARE(refImage.pixel(20,20),testImage.pixel(20,20)); +} + +static QLinearGradient inverseGradient(QLinearGradient g) +{ + QLinearGradient g2 = g; + + QGradientStops stops = g.stops(); + + QGradientStops inverse; + foreach (QGradientStop stop, stops) + inverse << QGradientStop(1 - stop.first, stop.second); + + g2.setStops(inverse); + return g2; +} + +void tst_QPainter::linearGradientSymmetry_data() +{ + QTest::addColumn<QGradientStops>("stops"); + + if (sizeof(qreal) != sizeof(float)) { + QGradientStops stops; + stops << qMakePair(qreal(0.0), QColor(Qt::blue)); + stops << qMakePair(qreal(0.2), QColor(220, 220, 220, 0)); + stops << qMakePair(qreal(0.6), QColor(Qt::red)); + stops << qMakePair(qreal(0.9), QColor(220, 220, 220, 255)); + stops << qMakePair(qreal(1.0), QColor(Qt::black)); + QTest::newRow("multiple stops") << stops; + } + + { + QGradientStops stops; + stops << qMakePair(qreal(0.0), QColor(Qt::blue)); + stops << qMakePair(qreal(1.0), QColor(Qt::black)); + QTest::newRow("two stops") << stops; + } + + if (sizeof(qreal) != sizeof(float)) { + QGradientStops stops; + stops << qMakePair(qreal(0.3), QColor(Qt::blue)); + stops << qMakePair(qreal(0.6), QColor(Qt::black)); + QTest::newRow("two stops 2") << stops; + } +} + +void tst_QPainter::linearGradientSymmetry() +{ +#ifdef Q_WS_QWS + QSKIP("QWS has limited resolution in the gradient color table", SkipAll); +#else + QFETCH(QGradientStops, stops); + + QImage a(64, 8, QImage::Format_ARGB32_Premultiplied); + QImage b(64, 8, QImage::Format_ARGB32_Premultiplied); + + a.fill(0); + b.fill(0); + + QLinearGradient gradient(QRectF(b.rect()).topLeft(), QRectF(b.rect()).topRight()); + gradient.setStops(stops); + + QPainter pa(&a); + pa.fillRect(a.rect(), gradient); + pa.end(); + + QPainter pb(&b); + pb.fillRect(b.rect(), inverseGradient(gradient)); + pb.end(); + + b = b.mirrored(true); + QCOMPARE(a, b); +#endif +} + +void tst_QPainter::gradientInterpolation() +{ + QImage image(256, 8, QImage::Format_ARGB32_Premultiplied); + QPainter painter; + + QLinearGradient gradient(QRectF(image.rect()).topLeft(), QRectF(image.rect()).topRight()); + gradient.setColorAt(0.0, QColor(255, 0, 0, 0)); + gradient.setColorAt(1.0, Qt::blue); + + image.fill(0); + painter.begin(&image); + painter.fillRect(image.rect(), gradient); + painter.end(); + + const QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(3)); + + for (int i = 0; i < 256; ++i) { + QCOMPARE(qAlpha(line[i]), qBlue(line[i])); // bright blue + QVERIFY(qAbs(qAlpha(line[i]) - i) < 3); // linear alpha + QCOMPARE(qRed(line[i]), 0); // no red component + QCOMPARE(qGreen(line[i]), 0); // no green component + } + + gradient.setInterpolationMode(QGradient::ComponentInterpolation); + + image.fill(0); + painter.begin(&image); + painter.fillRect(image.rect(), gradient); + painter.end(); + + for (int i = 1; i < 256; ++i) { + if (i < 128) { + QVERIFY(qRed(line[i]) >= qBlue(line[i])); // red is dominant + } else { + QVERIFY(qRed(line[i]) <= qBlue(line[i])); // blue is dominant + } + QVERIFY((qRed(line[i]) - 0.5) * (qAlpha(line[i - 1]) - 0.5) <= (qRed(line[i - 1]) + 0.5) * (qAlpha(line[i]) + 0.5)); // decreasing red + QVERIFY((qBlue(line[i]) + 0.5) * (qAlpha(line[i - 1]) + 0.5) >= (qBlue(line[i - 1]) - 0.5) * (qAlpha(line[i]) - 0.5)); // increasing blue + QVERIFY(qAbs(qAlpha(line[i]) - i) < 3); // linear alpha + QCOMPARE(qGreen(line[i]), 0); // no green component + } +} + +void tst_QPainter::drawPolygon() +{ + QImage img(128, 128, QImage::Format_ARGB32_Premultiplied); + + QPainterPathStroker stroker; + stroker.setWidth(1.5); + + QPainterPath path; + path.moveTo(2, 34); + path.lineTo(34, 2); + + QPolygonF poly = stroker.createStroke(path).toFillPolygon(); + + img.fill(0xffffffff); + QPainter p(&img); + p.setRenderHint(QPainter::Antialiasing); + p.setBrush(Qt::red); + p.setPen(Qt::NoPen); + p.drawPolygon(poly); + p.translate(64, 64); + p.drawPolygon(poly); + p.end(); + + QImage a = img.copy(); + + img.fill(0xffffffff); + p.begin(&img); + p.setRenderHint(QPainter::Antialiasing); + p.setBrush(Qt::red); + p.setPen(Qt::NoPen); + p.translate(64, 64); + p.drawPolygon(poly); + p.resetTransform(); + p.drawPolygon(poly); + p.end(); + + QCOMPARE(a, img); +} + +void tst_QPainter::inactivePainter() +{ + // This test succeeds if it doesn't segfault. + + QPainter p; + QPainterPath path; + QRegion region(QRect(20, 20, 60, 40)); + QPolygonF polygon(QVector<QPointF>() << QPointF(0, 0) << QPointF(12, 0) << QPointF(8, 6)); + path.addPolygon(polygon); + + p.save(); + p.restore(); + + p.background(); + p.setBackground(QBrush(Qt::blue)); + + p.brush(); + p.setBrush(Qt::red); + p.setBrush(Qt::NoBrush); + p.setBrush(QBrush(Qt::white, Qt::DiagCrossPattern)); + + p.backgroundMode(); + p.setBackgroundMode(Qt::OpaqueMode); + + p.boundingRect(QRectF(0, 0, 100, 20), Qt::AlignCenter, QLatin1String("Hello, World!")); + p.boundingRect(QRect(0, 0, 100, 20), Qt::AlignCenter, QLatin1String("Hello, World!")); + + p.brushOrigin(); + p.setBrushOrigin(QPointF(12, 34)); + p.setBrushOrigin(QPoint(12, 34)); + + p.clipPath(); + p.clipRegion(); + p.hasClipping(); + p.setClipPath(path); + p.setClipRect(QRectF(42, 42, 42, 42)); + p.setClipRect(QRect(42, 42, 42, 42)); + p.setClipRegion(region); + p.setClipping(true); + + p.combinedMatrix(); + p.combinedTransform(); + + p.compositionMode(); + p.setCompositionMode(QPainter::CompositionMode_Plus); + + p.device(); + p.deviceMatrix(); + p.deviceTransform(); + + p.font(); + p.setFont(QFont(QLatin1String("Times"), 24)); + + p.fontInfo(); + p.fontMetrics(); + + p.layoutDirection(); + p.setLayoutDirection(Qt::RightToLeft); + + p.opacity(); + p.setOpacity(0.75); + + p.pen(); + p.setPen(QPen(Qt::red)); + p.setPen(Qt::green); + p.setPen(Qt::NoPen); + + p.renderHints(); + p.setRenderHint(QPainter::Antialiasing, true); + p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false); + + p.resetMatrix(); + p.resetTransform(); + p.rotate(1); + p.scale(2, 2); + p.shear(-1, 1); + p.translate(3, 14); + + p.viewTransformEnabled(); + p.setViewTransformEnabled(true); + + p.viewport(); + p.setViewport(QRect(10, 10, 620, 460)); + + p.window(); + p.setWindow(QRect(10, 10, 620, 460)); + + p.worldMatrix(); + p.setWorldMatrix(QMatrix().translate(43, 21), true); + p.setWorldMatrixEnabled(true); + + p.transform(); + p.setTransform(QTransform().translate(12, 34), true); + + p.worldTransform(); + p.setWorldTransform(QTransform().scale(0.5, 0.5), true); +} + +bool testCompositionMode(int src, int dst, int expected, QPainter::CompositionMode op, qreal opacity = 1.0) +{ + // The test image needs to be large enough to test SIMD code + const QSize imageSize(100, 100); + + QImage actual(imageSize, QImage::Format_ARGB32_Premultiplied); + actual.fill(QColor(dst, dst, dst).rgb()); + + QPainter p(&actual); + p.setCompositionMode(op); + p.setOpacity(opacity); + p.fillRect(QRect(QPoint(), imageSize), QColor(src, src, src)); + p.end(); + + if (qRed(actual.pixel(0, 0)) != expected) { + qDebug("Fail: mode %d, src[%d] dst [%d] actual [%d] expected [%d]", op, + src, dst, qRed(actual.pixel(0, 0)), expected); + return false; + } else { + QImage refImage(imageSize, QImage::Format_ARGB32_Premultiplied); + refImage.fill(QColor(expected, expected, expected).rgb()); + return actual == refImage; + } +} + +void tst_QPainter::extendedBlendModes() +{ + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Plus)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Plus)); + QVERIFY(testCompositionMode(127, 128, 255, QPainter::CompositionMode_Plus)); + QVERIFY(testCompositionMode(127, 0, 127, QPainter::CompositionMode_Plus)); + QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Plus)); + QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Plus)); + QVERIFY(testCompositionMode( 0, 255, 255, QPainter::CompositionMode_Plus)); + QVERIFY(testCompositionMode(128, 128, 255, QPainter::CompositionMode_Plus)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Plus, 0.3)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Plus, 0.3)); + QVERIFY(testCompositionMode(127, 128, 165, QPainter::CompositionMode_Plus, 0.3)); + QVERIFY(testCompositionMode(127, 0, 37, QPainter::CompositionMode_Plus, 0.3)); + QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Plus, 0.3)); + QVERIFY(testCompositionMode(255, 0, 75, QPainter::CompositionMode_Plus, 0.3)); + QVERIFY(testCompositionMode( 0, 255, 255, QPainter::CompositionMode_Plus, 0.3)); + QVERIFY(testCompositionMode(128, 128, 166, QPainter::CompositionMode_Plus, 0.3)); + QVERIFY(testCompositionMode(186, 200, 255, QPainter::CompositionMode_Plus, 0.3)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Multiply)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Multiply)); + QVERIFY(testCompositionMode(127, 255, 127, QPainter::CompositionMode_Multiply)); + QVERIFY(testCompositionMode(255, 127, 127, QPainter::CompositionMode_Multiply)); + QVERIFY(testCompositionMode( 63, 255, 63, QPainter::CompositionMode_Multiply)); + QVERIFY(testCompositionMode(255, 63, 63, QPainter::CompositionMode_Multiply)); + QVERIFY(testCompositionMode(127, 127, 63, QPainter::CompositionMode_Multiply)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Screen)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Screen)); + QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Screen)); + QVERIFY(testCompositionMode(255, 63, 255, QPainter::CompositionMode_Screen)); + QVERIFY(testCompositionMode( 63, 0, 63, QPainter::CompositionMode_Screen)); + QVERIFY(testCompositionMode( 0, 63, 63, QPainter::CompositionMode_Screen)); + QVERIFY(testCompositionMode(127, 127, 191, QPainter::CompositionMode_Screen)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Overlay)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Overlay)); + QVERIFY(testCompositionMode( 63, 63, 31, QPainter::CompositionMode_Overlay)); + QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Overlay)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Darken)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Darken)); + QVERIFY(testCompositionMode( 63, 63, 63, QPainter::CompositionMode_Darken)); + QVERIFY(testCompositionMode( 63, 255, 63, QPainter::CompositionMode_Darken)); + QVERIFY(testCompositionMode(255, 63, 63, QPainter::CompositionMode_Darken)); + QVERIFY(testCompositionMode( 63, 127, 63, QPainter::CompositionMode_Darken)); + QVERIFY(testCompositionMode(127, 63, 63, QPainter::CompositionMode_Darken)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Lighten)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Lighten)); + QVERIFY(testCompositionMode( 63, 63, 63, QPainter::CompositionMode_Lighten)); + QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Lighten)); + QVERIFY(testCompositionMode(255, 63, 255, QPainter::CompositionMode_Lighten)); + QVERIFY(testCompositionMode( 63, 127, 127, QPainter::CompositionMode_Lighten)); + QVERIFY(testCompositionMode(127, 63, 127, QPainter::CompositionMode_Lighten)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_ColorDodge)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_ColorDodge)); + QVERIFY(testCompositionMode( 63, 127, 169, QPainter::CompositionMode_ColorDodge)); + QVERIFY(testCompositionMode(191, 127, 255, QPainter::CompositionMode_ColorDodge)); + QVERIFY(testCompositionMode(127, 191, 255, QPainter::CompositionMode_ColorDodge)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_ColorBurn)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_ColorBurn)); + QVERIFY(testCompositionMode(127, 127, 0, QPainter::CompositionMode_ColorBurn)); + QVERIFY(testCompositionMode(128, 128, 2, QPainter::CompositionMode_ColorBurn)); + QVERIFY(testCompositionMode(191, 127, 84, QPainter::CompositionMode_ColorBurn)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_HardLight)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_HardLight)); + QVERIFY(testCompositionMode(127, 127, 127, QPainter::CompositionMode_HardLight)); + QVERIFY(testCompositionMode( 63, 63, 31, QPainter::CompositionMode_HardLight)); + QVERIFY(testCompositionMode(127, 63, 63, QPainter::CompositionMode_HardLight)); + + QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_SoftLight)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_SoftLight)); + QVERIFY(testCompositionMode(127, 127, 126, QPainter::CompositionMode_SoftLight)); + QVERIFY(testCompositionMode( 63, 63, 39, QPainter::CompositionMode_SoftLight)); + QVERIFY(testCompositionMode(127, 63, 62, QPainter::CompositionMode_SoftLight)); + + QVERIFY(testCompositionMode(255, 255, 0, QPainter::CompositionMode_Difference)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Difference)); + QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Difference)); + QVERIFY(testCompositionMode(127, 127, 0, QPainter::CompositionMode_Difference)); + QVERIFY(testCompositionMode(127, 128, 1, QPainter::CompositionMode_Difference)); + QVERIFY(testCompositionMode(127, 63, 64, QPainter::CompositionMode_Difference)); + QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Difference)); + + QVERIFY(testCompositionMode(255, 255, 0, QPainter::CompositionMode_Exclusion)); + QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Exclusion)); + QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Exclusion)); + QVERIFY(testCompositionMode(127, 127, 127, QPainter::CompositionMode_Exclusion)); + QVERIFY(testCompositionMode( 63, 127, 127, QPainter::CompositionMode_Exclusion)); + QVERIFY(testCompositionMode( 63, 63, 95, QPainter::CompositionMode_Exclusion)); + QVERIFY(testCompositionMode(191, 191, 96, QPainter::CompositionMode_Exclusion)); +} + +void tst_QPainter::zeroOpacity() +{ + QImage source(1, 1, QImage::Format_ARGB32_Premultiplied); + source.fill(0xffffffff); + + QImage target(1, 1, QImage::Format_RGB32); + target.fill(0xff000000); + + QPainter p(&target); + p.setOpacity(0.0); + p.drawImage(0, 0, source); + p.end(); + + QCOMPARE(target.pixel(0, 0), 0xff000000); +} + +void tst_QPainter::clippingBug() +{ + QImage img(32, 32, QImage::Format_ARGB32_Premultiplied); + img.fill(0); + + QImage expected = img; + QPainter p(&expected); + p.fillRect(1, 1, 30, 30, Qt::red); + p.end(); + + QPainterPath path; + path.addRect(1, 1, 30, 30); + path.addRect(1, 1, 30, 30); + path.addRect(1, 1, 30, 30); + + p.begin(&img); + p.setClipPath(path); + p.fillRect(0, 0, 32, 32, Qt::red); + p.end(); + + QCOMPARE(img, expected); +} + +void tst_QPainter::emptyClip() +{ + QImage img(64, 64, QImage::Format_ARGB32_Premultiplied); + QPainter p(&img); + p.setRenderHints(QPainter::Antialiasing); + p.setClipRect(0, 32, 64, 0); + p.fillRect(0, 0, 64, 64, Qt::white); + + QPainterPath path; + path.lineTo(64, 0); + path.lineTo(64, 64); + path.lineTo(40, 64); + path.lineTo(40, 80); + path.lineTo(0, 80); + + p.fillPath(path, Qt::green); +} + +void tst_QPainter::drawImage_1x1() +{ + QImage source(1, 1, QImage::Format_ARGB32_Premultiplied); + source.fill(0xffffffff); + + QImage img(32, 32, QImage::Format_ARGB32_Premultiplied); + img.fill(0xff000000); + QPainter p(&img); + p.drawImage(QRectF(0.9, 0.9, 32, 32), source); + p.end(); + + QImage expected = img; + expected.fill(0xff000000); + p.begin(&expected); + p.fillRect(1, 1, 31, 31, Qt::white); + p.end(); + + QCOMPARE(img, expected); +} + +void tst_QPainter::taskQT4444_dontOverflowDashOffset() +{ + QPainter p; + + QPen pen; + pen.setWidth(2); + pen.setStyle(Qt::DashDotLine); + + QPointF point[4]; + point[0] = QPointF(182.50868749707968,347.78457234212630); + point[1] = QPointF(182.50868749707968,107.22501998401277); + point[2] = QPointF(182.50868749707968,107.22501998401277); + point[3] = QPointF(520.46600762283651,107.22501998401277); + + QImage crashImage(QSize(1000, 120), QImage::Format_ARGB32_Premultiplied); + p.begin(&crashImage); + p.setPen(pen); + p.drawLines(point, 2); + p.end(); + + QVERIFY(true); // Don't crash +} + +void tst_QPainter::painterBegin() +{ + QImage nullImage; + QImage indexed8Image(16, 16, QImage::Format_Indexed8); + QImage rgb32Image(16, 16, QImage::Format_RGB32); + QImage argb32Image(16, 16, QImage::Format_ARGB32_Premultiplied); + + QPainter p; + + // Painting on null image should fail. + QVERIFY(!p.begin(&nullImage)); + + // Check that the painter is not messed up by using it on another image. + QVERIFY(p.begin(&rgb32Image)); + QVERIFY(p.end()); + + // If painting on indexed8 image fails, the painter state should still be OK. + if (p.begin(&indexed8Image)) + QVERIFY(p.end()); + QVERIFY(p.begin(&rgb32Image)); + QVERIFY(p.end()); + + // Try opening a painter on the two different images. + QVERIFY(p.begin(&rgb32Image)); + QVERIFY(!p.begin(&argb32Image)); + QVERIFY(p.end()); + + // Try opening two painters on the same image. + QVERIFY(p.begin(&rgb32Image)); + QPainter q; + QVERIFY(!q.begin(&rgb32Image)); + QVERIFY(!q.end()); + QVERIFY(p.end()); + + // Try ending an inactive painter. + QVERIFY(!p.end()); +} + +void tst_QPainter::setPenColor(QPainter& p) +{ + p.setPen(Qt::NoPen); + + // Setting color, then style + // Should work even though the pen is "NoPen with color", temporarily. + QPen newPen(p.pen()); + newPen.setColor(Qt::red); + QCOMPARE(p.pen().style(), newPen.style()); + QCOMPARE(p.pen().style(), Qt::NoPen); + p.setPen(newPen); + + QCOMPARE(p.pen().color().name(), QString("#ff0000")); + + QPen newPen2(p.pen()); + newPen2.setStyle(Qt::SolidLine); + p.setPen(newPen2); + + QCOMPARE(p.pen().color().name(), QString("#ff0000")); +} + +void tst_QPainter::setPenColorOnImage() +{ + QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied); + QPainter p(&img); + setPenColor(p); +} + +void tst_QPainter::setPenColorOnPixmap() +{ + QPixmap pix(10, 10); + QPainter p(&pix); + setPenColor(p); +} + +class TestProxy : public QGraphicsProxyWidget +{ +public: + TestProxy() : QGraphicsProxyWidget() {} + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + QGraphicsProxyWidget::paint(painter, option, widget); + deviceTransform = painter->deviceTransform(); + } + QTransform deviceTransform; +}; + +class TestWidget : public QWidget +{ +Q_OBJECT +public: + TestWidget() : QWidget(), painted(false) {} + void paintEvent(QPaintEvent *) + { + QPainter p(this); + deviceTransform = p.deviceTransform(); + worldTransform = p.worldTransform(); + painted = true; + } + QTransform deviceTransform; + QTransform worldTransform; + bool painted; +}; + +void tst_QPainter::QTBUG5939_attachPainterPrivate() +{ + QWidget *w = new QWidget(); + QGraphicsScene *scene = new QGraphicsScene(); + QGraphicsView *view = new QGraphicsView(scene, w); + view->move(50 ,50); + TestProxy *proxy = new TestProxy(); + TestWidget *widget = new TestWidget(); + proxy->setWidget(widget); + scene->addItem(proxy); + proxy->rotate(45); + w->resize(scene->sceneRect().size().toSize()); + + w->show(); + QTRY_VERIFY(widget->painted); + + QVERIFY(widget->worldTransform.isIdentity()); + QCOMPARE(widget->deviceTransform, proxy->deviceTransform); +} + +void tst_QPainter::clipBoundingRect() +{ + QPixmap pix(500, 500); + + QPainter p(&pix); + + // Test a basic rectangle + p.setClipRect(100, 100, 200, 100); + QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100))); + QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200))); + p.setClipRect(120, 120, 20, 20, Qt::IntersectClip); + QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20))); + QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100))); + + // Test a basic float rectangle + p.setClipRect(QRectF(100, 100, 200, 100)); + QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100))); + QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200))); + p.setClipRect(QRectF(120, 120, 20, 20), Qt::IntersectClip); + QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20))); + QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100))); + + // Test a basic path + region + QPainterPath path; + path.addRect(100, 100, 200, 100); + p.setClipPath(path); + QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100))); + QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200))); + p.setClipRegion(QRegion(120, 120, 20, 20), Qt::IntersectClip); + QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20))); + QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100))); + + p.setClipRect(0, 0, 500, 500); + p.translate(250, 250); + for (int i=0; i<360; ++i) { + p.rotate(1); + p.setClipRect(-100, -100, 200, 200, Qt::IntersectClip); + } + QVERIFY(p.clipBoundingRect().contains(QRectF(-100, -100, 200, 200))); + QVERIFY(!p.clipBoundingRect().contains(QRectF(-250, -250, 500, 500))); + +} + +void tst_QPainter::drawText_subPixelPositionsInRaster_qtbug5053() +{ +#if !defined(Q_WS_MAC) || !defined(QT_MAC_USE_COCOA) + QSKIP("Only Mac/Cocoa supports sub pixel positions in raster engine currently", SkipAll); +#endif + QFontMetricsF fm(qApp->font()); + + QImage baseLine(fm.width(QChar::fromLatin1('e')), fm.height(), QImage::Format_RGB32); + baseLine.fill(Qt::white); + { + QPainter p(&baseLine); + p.drawText(0, fm.ascent(), QString::fromLatin1("e")); + } + + bool foundDifferentRasterization = false; + for (int i=1; i<12; ++i) { + QImage comparison(baseLine.size(), QImage::Format_RGB32); + comparison.fill(Qt::white); + + { + QPainter p(&comparison); + p.drawText(QPointF(i / 12.0, fm.ascent()), QString::fromLatin1("e")); + } + + if (comparison != baseLine) { + foundDifferentRasterization = true; + break; + } + } + + QVERIFY(foundDifferentRasterization); +} + +void tst_QPainter::drawPointScaled() +{ + QImage image(32, 32, QImage::Format_RGB32); + image.fill(0xffffffff); + + QPainter p(&image); + + p.scale(0.1, 0.1); + + QPen pen; + pen.setWidth(1000); + pen.setColor(Qt::red); + + p.setPen(pen); + p.drawPoint(0, 0); + p.end(); + + QCOMPARE(image.pixel(16, 16), 0xffff0000); +} + +class GradientProducer : public QThread +{ +protected: + void run(); +}; + +void GradientProducer::run() +{ + QImage image(1, 1, QImage::Format_RGB32); + QPainter p(&image); + + for (int i = 0; i < 1000; ++i) { + QLinearGradient g; + g.setColorAt(0, QColor(i % 256, 0, 0)); + g.setColorAt(1, Qt::white); + + p.fillRect(image.rect(), g); + } +} + +void tst_QPainter::QTBUG14614_gradientCacheRaceCondition() +{ + const int threadCount = 16; + GradientProducer producers[threadCount]; + for (int i = 0; i < threadCount; ++i) + producers[i].start(); + for (int i = 0; i < threadCount; ++i) + producers[i].wait(); +} + +void tst_QPainter::drawTextOpacity() +{ + QImage image(32, 32, QImage::Format_RGB32); + image.fill(0xffffffff); + + QPainter p(&image); + p.setPen(QColor("#6F6F6F")); + p.setOpacity(0.5); + p.drawText(5, 30, QLatin1String("Qt")); + p.end(); + + QImage copy = image; + image.fill(0xffffffff); + + p.begin(&image); + p.setPen(QColor("#6F6F6F")); + p.drawLine(-10, -10, -1, -1); + p.setOpacity(0.5); + p.drawText(5, 30, QLatin1String("Qt")); + p.end(); + + QCOMPARE(image, copy); +} + +void tst_QPainter::QTBUG17053_zeroDashPattern() +{ + QImage image(32, 32, QImage::Format_RGB32); + image.fill(0xffffffff); + + QImage original = image; + + QVector<qreal> pattern; + pattern << qreal(0) << qreal(0); + + QPainter p(&image); + QPen pen(Qt::black, 2.0); + pen.setDashPattern(pattern); + + p.setPen(pen); + p.drawLine(0, 0, image.width(), image.height()); + + QCOMPARE(image, original); +} + +class TextDrawerThread : public QThread +{ +public: + void run(); + QImage rendering; +}; + +void TextDrawerThread::run() +{ + rendering = QImage(100, 100, QImage::Format_ARGB32_Premultiplied); + rendering.fill(0); + QPainter p(&rendering); + p.fillRect(10, 10, 100, 100, Qt::blue); + p.setPen(Qt::green); + p.drawText(20, 20, "some text"); + p.end(); +} + +void tst_QPainter::drawTextOutsideGuiThread() +{ + if (!QFontDatabase::supportsThreadedFontRendering()) + QSKIP("No threaded font rendering", SkipAll); + + QImage referenceRendering(100, 100, QImage::Format_ARGB32_Premultiplied); + referenceRendering.fill(0); + QPainter p(&referenceRendering); + p.fillRect(10, 10, 100, 100, Qt::blue); + p.setPen(Qt::green); + p.drawText(20, 20, "some text"); + p.end(); + + TextDrawerThread t; + t.start(); + t.wait(); + + QCOMPARE(referenceRendering, t.rendering); +} + +QTEST_MAIN(tst_QPainter) + +#include "tst_qpainter.moc" diff --git a/tests/auto/gui/painting/qpainter/utils/createImages/createImages.pro b/tests/auto/gui/painting/qpainter/utils/createImages/createImages.pro new file mode 100644 index 0000000000..ce2d341e92 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/utils/createImages/createImages.pro @@ -0,0 +1,11 @@ +###################################################################### +# Automatically generated by qmake (1.02a) Thu Apr 18 18:56:53 2002 +###################################################################### + +TEMPLATE = app +CONFIG -= moc + +# Input +SOURCES += main.cpp + + diff --git a/tests/auto/gui/painting/qpainter/utils/createImages/main.cpp b/tests/auto/gui/painting/qpainter/utils/createImages/main.cpp new file mode 100644 index 0000000000..418c385717 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/utils/createImages/main.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qapplication.h> +#include <qpixmap.h> +#include <qpainter.h> +#include <qbitmap.h> + +static QColor baseColor( int k, int intensity ) +{ + int r = ( k & 1 ) * intensity; + int g = ( (k>>1) & 1 ) * intensity; + int b = ( (k>>2) & 1 ) * intensity; + return QColor( r, g, b ); +} + +static QPixmap createDestPixmap() +{ + const int colorbands = 3; + const int intensities = 4; + QPixmap pm( 32, colorbands*intensities*4 ); + QPainter painter; + painter.begin( &pm ); + for ( int i=0; i<colorbands; i++ ) { + for ( int j=0; j<intensities; j++ ) { + int intensity = 255 * (j+1) / intensities; // 25%, 50%, 75% and 100% + for ( int k=0; k<8; k++ ) { + QColor col = baseColor( k, intensity ); + painter.setPen( QPen( col, 1 ) ); + painter.setBrush( col ); + painter.drawRect( k*4, j*4 + i*intensities*4, 4, 4 ); + } + } + } + painter.end(); + return pm; +} + +static QBitmap createDestBitmap() +{ + // create a bitmap that looks like: + // (0 is color0 and 1 is color1) + // 00001111 + // 00001111 + // 00001111 + // 00001111 + // 00001111 + // 00001111 + // 00001111 + // 00001111 + QBitmap bm( 8, 8 ); + QPainter painter; + painter.begin( &bm ); + painter.setPen( QPen( Qt::color0, 4 ) ); + painter.drawLine( 2, 0, 2, 8 ); + painter.setPen( QPen( Qt::color1, 4 ) ); + painter.drawLine( 6, 0, 6, 8 ); + painter.end(); + return bm; +} + +static QBitmap createSrcBitmap( int size, int border ) +{ + // create the source bitmap that looks like + // (for size=4 and border=2): + // + // + // 1111 + // 1111 + // 0000 + // 0000 + // + // + // If \a border is 0, the bitmap does not have a mask, otherwise the inner + // part is masked. + // \a size specifies the size of the inner (i.e. masked) part. It should be + // a multiple of 2. + int size2 = size/2; + int totalSize = 2 * ( size2 + border ); + QBitmap bm( totalSize, totalSize ); + QPainter painter; + painter.begin( &bm ); + painter.setPen( QPen( Qt::color0, 1 ) ); + painter.setBrush( Qt::color0 ); + painter.drawRect( border, size2+border, size, size2 ); + painter.setPen( QPen( Qt::color1, 1 ) ); + painter.setBrush( Qt::color1 ); + painter.drawRect( border, border, size, size2 ); + painter.end(); + if ( border > 0 ) { + QBitmap mask( totalSize, totalSize, TRUE ); + QPainter painter; + painter.begin( &mask ); + painter.setPen( QPen( Qt::color1, 1 ) ); + painter.setBrush( Qt::color1 ); + painter.drawRect( border, border, size, size ); + painter.end(); + bm.setMask( mask ); + } + return bm; +} + + +int main( int argc, char **argv ) +{ + QApplication a( argc, argv ); + + // input for tst_QPainter::drawLine_rop_bitmap() + { + QBitmap dst = createDestBitmap(); + dst.save( "../../drawLine_rop_bitmap/dst.xbm", "XBM" ); + } + + // input for tst_QPainter::drawPixmap_rop_bitmap() + { + QBitmap dst = createDestBitmap(); + QBitmap src1 = createSrcBitmap( 4, 2 ); + QBitmap src2 = createSrcBitmap( 4, 0 ); + dst.save( "../../drawPixmap_rop_bitmap/dst.xbm", "XBM" ); + src1.save( "../../drawPixmap_rop_bitmap/src1.xbm", "XBM" ); + src1.mask()->save( "../../drawPixmap_rop_bitmap/src1-mask.xbm", "XBM" ); + src2.save( "../../drawPixmap_rop_bitmap/src2.xbm", "XBM" ); + } + + // input for tst_QPainter::drawPixmap_rop() + { + QPixmap dst1 = createDestPixmap(); + QPixmap dst2 = createDestPixmap(); + dst2.resize( 32, 32 ); + QBitmap src1 = createSrcBitmap( 32, 0 ); + + QBitmap src_tmp = createSrcBitmap( 32, 0 ).xForm( QWMatrix( 1, 0, 0, -1, 0, 0 ) ); + src_tmp.resize( 32, 48 ); + QBitmap src2 = src_tmp.xForm( QWMatrix( 1, 0, 0, -1, 0, 0 ) ); + QBitmap mask( 32, 48, TRUE ); + { + QPainter painter; + painter.begin( &mask ); + painter.setPen( QPen( Qt::color1, 1 ) ); + painter.setBrush( Qt::color1 ); + painter.drawRect( 0, 16, 32, 32 ); + painter.end(); + } + src2.setMask( mask ); + + QBitmap src3 = createSrcBitmap( 32, 0 ).xForm( QWMatrix( 1, 0, 0, -1, 0, 0 ) ); + + dst1.save( "../../drawPixmap_rop/dst1.png", "PNG" ); + dst2.save( "../../drawPixmap_rop/dst2.png", "PNG" ); + src1.save( "../../drawPixmap_rop/src1.xbm", "XBM" ); + src2.save( "../../drawPixmap_rop/src2.xbm", "XBM" ); + src2.mask()->save( "../../drawPixmap_rop/src2-mask.xbm", "XBM" ); + src3.save( "../../drawPixmap_rop/src3.xbm", "XBM" ); + } +} diff --git a/tests/auto/gui/painting/qpainterpath/.gitignore b/tests/auto/gui/painting/qpainterpath/.gitignore new file mode 100644 index 0000000000..4e0e797989 --- /dev/null +++ b/tests/auto/gui/painting/qpainterpath/.gitignore @@ -0,0 +1,2 @@ +tst_qpainterpath +data diff --git a/tests/auto/gui/painting/qpainterpath/qpainterpath.pro b/tests/auto/gui/painting/qpainterpath/qpainterpath.pro new file mode 100644 index 0000000000..9708222c99 --- /dev/null +++ b/tests/auto/gui/painting/qpainterpath/qpainterpath.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qpainterpath.cpp + + + diff --git a/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp b/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp new file mode 100644 index 0000000000..33315adc06 --- /dev/null +++ b/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp @@ -0,0 +1,1332 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qfile.h> +#include <qpainterpath.h> +#include <qpen.h> + +#define _USE_MATH_DEFINES +#include <math.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPainterPath : public QObject +{ + Q_OBJECT + +public: + +private slots: + void getSetCheck(); + void swap(); + + void contains_QPointF_data(); + void contains_QPointF(); + + void contains_QRectF_data(); + void contains_QRectF(); + + void intersects_QRectF_data(); + void intersects_QRectF(); + + void testContainsAndIntersects_data(); + void testContainsAndIntersects(); + + void testSimplified_data(); + void testSimplified(); + + void testStroker_data(); + void testStroker(); + + void currentPosition(); + + void testOperatorEquals(); + void testOperatorEquals_fuzzy(); + void testOperatorDatastream(); + + void testArcMoveTo_data(); + void testArcMoveTo(); + void setElementPositionAt(); + + void testOnPath_data(); + void testOnPath(); + + void pointAtPercent_data(); + void pointAtPercent(); + + void angleAtPercent(); + + void arcWinding_data(); + void arcWinding(); + + void testToFillPolygons(); + + void testNaNandInfinites(); + + void closing(); + + void operators_data(); + void operators(); + + void connectPathDuplicatePoint(); + void connectPathMoveTo(); + + void translate(); + + void lineWithinBounds(); +}; + +// Testing get/set functions +void tst_QPainterPath::getSetCheck() +{ + QPainterPathStroker obj1; + // qreal QPainterPathStroker::width() + // void QPainterPathStroker::setWidth(qreal) + obj1.setWidth(0.0); + QCOMPARE(qreal(1.0), obj1.width()); // Pathstroker sets with to 1 if <= 0 + obj1.setWidth(0.5); + QCOMPARE(qreal(0.5), obj1.width()); + obj1.setWidth(1.1); + QCOMPARE(qreal(1.1), obj1.width()); + + // qreal QPainterPathStroker::miterLimit() + // void QPainterPathStroker::setMiterLimit(qreal) + obj1.setMiterLimit(0.0); + QCOMPARE(qreal(0.0), obj1.miterLimit()); + obj1.setMiterLimit(1.1); + QCOMPARE(qreal(1.1), obj1.miterLimit()); + + // qreal QPainterPathStroker::curveThreshold() + // void QPainterPathStroker::setCurveThreshold(qreal) + obj1.setCurveThreshold(0.0); + QCOMPARE(qreal(0.0), obj1.curveThreshold()); + obj1.setCurveThreshold(1.1); + QCOMPARE(qreal(1.1), obj1.curveThreshold()); +} + +void tst_QPainterPath::swap() +{ + QPainterPath p1; + p1.addRect( 0, 0,10,10); + QPainterPath p2; + p2.addRect(10,10,10,10); + p1.swap(p2); + QCOMPARE(p1.boundingRect().toRect(), QRect(10,10,10,10)); + QCOMPARE(p2.boundingRect().toRect(), QRect( 0, 0,10,10)); +} + +Q_DECLARE_METATYPE(QPainterPath) +Q_DECLARE_METATYPE(QPointF) +Q_DECLARE_METATYPE(QRectF) + +void tst_QPainterPath::currentPosition() +{ + QPainterPath p; + + QCOMPARE(p.currentPosition(), QPointF()); + + p.moveTo(100, 100); + QCOMPARE(p.currentPosition(), QPointF(100, 100)); + + p.lineTo(200, 200); + QCOMPARE(p.currentPosition(), QPointF(200, 200)); + + p.cubicTo(300, 200, 200, 300, 500, 500); + QCOMPARE(p.currentPosition(), QPointF(500, 500)); +} + +void tst_QPainterPath::contains_QPointF_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<QPointF>("pt"); + QTest::addColumn<bool>("contained"); + + QPainterPath path; + path.addRect(0, 0, 100, 100); + + // ##### + // # # + // # # + // # # + // ##### + + QTest::newRow("[0,0] in [0,0,100,100]") << path << QPointF(0, 0) << true; + + QTest::newRow("[99,0] in [0,0,100,100]") << path << QPointF(99, 0) << true; + QTest::newRow("[0,99] in [0,0,100,100]") << path << QPointF(0, 99) << true; + QTest::newRow("[99,99] in [0,0,100,100]") << path << QPointF(99, 99) << true; + + QTest::newRow("[99.99,0] in [0,0,100,100]") << path << QPointF(99.99, 0) << true; + QTest::newRow("[0,99.99] in [0,0,100,100]") << path << QPointF(0, 99.99) << true; + QTest::newRow("[99.99,99.99] in [0,0,100,100]") << path << QPointF(99.99, 99.99) << true; + + QTest::newRow("[0.01,0.01] in [0,0,100,100]") << path << QPointF(0.01, 0.01) << true; + QTest::newRow("[0,0.01] in [0,0,100,100]") << path << QPointF(0, 0.01) << true; + QTest::newRow("[0.01,0] in [0,0,100,100]") << path << QPointF(0.01, 0) << true; + + QTest::newRow("[-0.01,-0.01] in [0,0,100,100]") << path << QPointF(-0.01, -0.01) << false; + QTest::newRow("[-0,-0.01] in [0,0,100,100]") << path << QPointF(0, -0.01) << false; + QTest::newRow("[-0.01,0] in [0,0,100,100]") << path << QPointF(-0.01, 0) << false; + + + QTest::newRow("[-10,0] in [0,0,100,100]") << path << QPointF(-10, 0) << false; + QTest::newRow("[100,0] in [0,0,100,100]") << path << QPointF(100, 0) << false; + + QTest::newRow("[0,-10] in [0,0,100,100]") << path << QPointF(0, -10) << false; + QTest::newRow("[0,100] in [0,0,100,100]") << path << QPointF(0, 100) << false; + + QTest::newRow("[100.1,0] in [0,0,100,100]") << path << QPointF(100.1, 0) << false; + QTest::newRow("[0,100.1] in [0,0,100,100]") << path << QPointF(0, 100.1) << false; + + path.addRect(50, 50, 100, 100); + + // ##### + // # # + // # ##### + // # # # # + // ##### # + // # # + // ##### + + QTest::newRow("[49,49] in 2 rects") << path << QPointF(49,49) << true; + QTest::newRow("[50,50] in 2 rects") << path << QPointF(50,50) << false; + QTest::newRow("[100,100] in 2 rects") << path << QPointF(100,100) << true; + + path.setFillRule(Qt::WindingFill); + QTest::newRow("[50,50] in 2 rects (winding)") << path << QPointF(50,50) << true; + + path.addEllipse(0, 0, 150, 150); + + // ##### + // ## ## + // # ##### + // # # # # + // ##### # + // ## ## + // ##### + + QTest::newRow("[50,50] in complex (winding)") << path << QPointF(50, 50) << true; + + path.setFillRule(Qt::OddEvenFill); + QTest::newRow("[50,50] in complex (windinf)") << path << QPointF(50, 50) << true; + QTest::newRow("[49,49] in complex") << path << QPointF(49,49) << false; + QTest::newRow("[100,100] in complex") << path << QPointF(49,49) << false; + + + // unclosed triangle + path = QPainterPath(); + path.moveTo(100, 100); + path.lineTo(130, 70); + path.lineTo(150, 110); + + QTest::newRow("[100,100] in triangle") << path << QPointF(100, 100) << true; + QTest::newRow("[140,100] in triangle") << path << QPointF(140, 100) << true; + QTest::newRow("[130,80] in triangle") << path << QPointF(130, 80) << true; + + QTest::newRow("[110,80] in triangle") << path << QPointF(110, 80) << false; + QTest::newRow("[150,100] in triangle") << path << QPointF(150, 100) << false; + QTest::newRow("[120,110] in triangle") << path << QPointF(120, 110) << false; + + QRectF base_rect(0, 0, 20, 20); + + path = QPainterPath(); + path.addEllipse(base_rect); + + // not strictly precise, but good enougth to verify fair precision. + QPainterPath inside; + inside.addEllipse(base_rect.adjusted(5, 5, -5, -5)); + QPolygonF inside_poly = inside.toFillPolygon(); + for (int i=0; i<inside_poly.size(); ++i) + QTest::newRow("inside_ellipse") << path << inside_poly.at(i) << true; + + QPainterPath outside; + outside.addEllipse(base_rect.adjusted(-5, -5, 5, 5)); + QPolygonF outside_poly = outside.toFillPolygon(); + for (int i=0; i<outside_poly.size(); ++i) + QTest::newRow("outside_ellipse") << path << outside_poly.at(i) << false; + + path = QPainterPath(); + base_rect = QRectF(50, 50, 200, 200); + path.addEllipse(base_rect); + path.setFillRule(Qt::WindingFill); + + QTest::newRow("topleft outside ellipse") << path << base_rect.topLeft() << false; + QTest::newRow("topright outside ellipse") << path << base_rect.topRight() << false; + QTest::newRow("bottomright outside ellipse") << path << base_rect.bottomRight() << false; + QTest::newRow("bottomleft outside ellipse") << path << base_rect.bottomLeft() << false; + + // Test horizontal curve segment + path = QPainterPath(); + path.moveTo(100, 100); + path.cubicTo(120, 100, 180, 100, 200, 100); + path.lineTo(150, 200); + path.closeSubpath(); + + QTest::newRow("horizontal cubic, out left") << path << QPointF(0, 100) << false; + QTest::newRow("horizontal cubic, out right") << path << QPointF(300, 100) <<false; + QTest::newRow("horizontal cubic, in mid") << path << QPointF(150, 100) << true; + + path = QPainterPath(); + path.addEllipse(QRectF(-5000.0, -5000.0, 1500000.0, 1500000.0)); + QTest::newRow("huge ellipse, qreal=float crash") << path << QPointF(1100000.35, 1098000.2) << true; + +} + +void tst_QPainterPath::contains_QPointF() +{ + QFETCH(QPainterPath, path); + QFETCH(QPointF, pt); + QFETCH(bool, contained); + + QCOMPARE(path.contains(pt), contained); +} + +void tst_QPainterPath::contains_QRectF_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<QRectF>("rect"); + QTest::addColumn<bool>("contained"); + + QPainterPath path; + path.addRect(0, 0, 100, 100); + + QTest::newRow("same rect") << path << QRectF(0.1, 0.1, 99, 99) << true; // ### + QTest::newRow("outside") << path << QRectF(-1, -1, 100, 100) << false; + QTest::newRow("covers") << path << QRectF(-1, -1, 102, 102) << false; + QTest::newRow("left") << path << QRectF(-10, 50, 5, 5) << false; + QTest::newRow("top") << path << QRectF(50, -10, 5, 5) << false; + QTest::newRow("right") << path << QRectF(110, 50, 5, 5) << false; + QTest::newRow("bottom") << path << QRectF(50, 110, 5, 5) << false; + + path.addRect(50, 50, 100, 100); + + QTest::newRow("r1 top") << path << QRectF(0.1, 0.1, 99, 49) << true; + QTest::newRow("r1 left") << path << QRectF(0.1, 0.1, 49, 99) << true; + QTest::newRow("r2 right") << path << QRectF(100.01, 50.1, 49, 99) << true; + QTest::newRow("r2 bottom") << path << QRectF(50.1, 100.1, 99, 49) << true; + QTest::newRow("inside 2 rects") << path << QRectF(51, 51, 48, 48) << false; + QTest::newRow("topRight 2 rects") << path << QRectF(100, 0, 49, 49) << false; + QTest::newRow("bottomLeft 2 rects") << path << QRectF(0, 100, 49, 49) << false; + + path.setFillRule(Qt::WindingFill); + QTest::newRow("inside 2 rects (winding)") << path << QRectF(51, 51, 48, 48) << true; + + path.addEllipse(0, 0, 150, 150); + QTest::newRow("topRight 2 rects") << path << QRectF(100, 25, 24, 24) << true; + QTest::newRow("bottomLeft 2 rects") << path << QRectF(25, 100, 24, 24) << true; + + path.setFillRule(Qt::OddEvenFill); + QTest::newRow("inside 2 rects") << path << QRectF(50, 50, 49, 49) << false; +} + +void tst_QPainterPath::contains_QRectF() +{ + QFETCH(QPainterPath, path); + QFETCH(QRectF, rect); + QFETCH(bool, contained); + + QCOMPARE(path.contains(rect), contained); +} + +static inline QPainterPath rectPath(qreal x, qreal y, qreal w, qreal h) +{ + QPainterPath path; + path.addRect(x, y, w, h); + path.closeSubpath(); + return path; +} + +static inline QPainterPath ellipsePath(qreal x, qreal y, qreal w, qreal h) +{ + QPainterPath path; + path.addEllipse(x, y, w, h); + path.closeSubpath(); + return path; +} + +static inline QPainterPath linePath(qreal x1, qreal y1, qreal x2, qreal y2) +{ + QPainterPath path; + path.moveTo(x1, y1); + path.lineTo(x2, y2); + return path; +} + +void tst_QPainterPath::intersects_QRectF_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<QRectF>("rect"); + QTest::addColumn<bool>("intersects"); + + QPainterPath path; + path.addRect(0, 0, 100, 100); + + QTest::newRow("same rect") << path << QRectF(0.1, 0.1, 99, 99) << true; // ### + QTest::newRow("outside") << path << QRectF(-1, -1, 100, 100) << true; + QTest::newRow("covers") << path << QRectF(-1, -1, 102, 102) << true; + QTest::newRow("left") << path << QRectF(-10, 50, 5, 5) << false; + QTest::newRow("top") << path << QRectF(50, -10, 5, 5) << false; + QTest::newRow("right") << path << QRectF(110, 50, 5, 5) << false; + QTest::newRow("bottom") << path << QRectF(50, 110, 5, 5) << false; + + path.addRect(50, 50, 100, 100); + + QTest::newRow("r1 top") << path << QRectF(0.1, 0.1, 99, 49) << true; + QTest::newRow("r1 left") << path << QRectF(0.1, 0.1, 49, 99) << true; + QTest::newRow("r2 right") << path << QRectF(100.01, 50.1, 49, 99) << true; + QTest::newRow("r2 bottom") << path << QRectF(50.1, 100.1, 99, 49) << true; + QTest::newRow("inside 2 rects") << path << QRectF(51, 51, 48, 48) << false; + + path.setFillRule(Qt::WindingFill); + QTest::newRow("inside 2 rects (winding)") << path << QRectF(51, 51, 48, 48) << true; + + path.addEllipse(0, 0, 150, 150); + QTest::newRow("topRight 2 rects") << path << QRectF(100, 25, 24, 24) << true; + QTest::newRow("bottomLeft 2 rects") << path << QRectF(25, 100, 24, 24) << true; + + QTest::newRow("horizontal line") << linePath(0, 0, 10, 0) << QRectF(1, -1, 2, 2) << true; + QTest::newRow("vertical line") << linePath(0, 0, 0, 10) << QRectF(-1, 1, 2, 2) << true; + + path = QPainterPath(); + path.addEllipse(QRectF(-5000.0, -5000.0, 1500000.0, 1500000.0)); + QTest::newRow("huge ellipse, qreal=float crash") << path << QRectF(1100000.35, 1098000.2, 1500000.0, 1500000.0) << true; +} + +void tst_QPainterPath::intersects_QRectF() +{ + QFETCH(QPainterPath, path); + QFETCH(QRectF, rect); + QFETCH(bool, intersects); + + QCOMPARE(path.intersects(rect), intersects); +} + + +void tst_QPainterPath::testContainsAndIntersects_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<QPainterPath>("candidate"); + QTest::addColumn<bool>("contained"); + QTest::addColumn<bool>("intersects"); + + QTest::newRow("rect vs small ellipse (upper left)") << rectPath(0, 0, 100, 100) << ellipsePath(0, 0, 50, 50) << false << true; + QTest::newRow("rect vs small ellipse (upper right)") << rectPath(0, 0, 100, 100) << ellipsePath(50, 0, 50, 50) << false << true; + QTest::newRow("rect vs small ellipse (lower right)") << rectPath(0, 0, 100, 100) << ellipsePath(50, 50, 50, 50) << false << true; + QTest::newRow("rect vs small ellipse (lower left)") << rectPath(0, 0, 100, 100) << ellipsePath(0, 50, 50, 50) << false << true; + QTest::newRow("rect vs small ellipse (centered)") << rectPath(0, 0, 100, 100) << ellipsePath(25, 25, 50, 50) << true << true; + QTest::newRow("rect vs equal ellipse") << rectPath(0, 0, 100, 100) << ellipsePath(0, 0, 100, 100) << false << true; + QTest::newRow("rect vs big ellipse") << rectPath(0, 0, 100, 100) << ellipsePath(-10, -10, 120, 120) << false << true; + + QPainterPath twoEllipses = ellipsePath(0, 0, 100, 100).united(ellipsePath(200, 0, 100, 100)); + + QTest::newRow("rect vs two small ellipses") << rectPath(0, 0, 100, 100) << ellipsePath(25, 25, 50, 50).united(ellipsePath(225, 25, 50, 50)) << false << true; + QTest::newRow("rect vs two equal ellipses") << rectPath(0, 0, 100, 100) << twoEllipses << false << true; + + QTest::newRow("rect vs self") << rectPath(0, 0, 100, 100) << rectPath(0, 0, 100, 100) << false << true; + QTest::newRow("ellipse vs self") << ellipsePath(0, 0, 100, 100) << ellipsePath(0, 0, 100, 100) << false << true; + + QPainterPath twoRects = rectPath(0, 0, 100, 100).united(rectPath(200, 0, 100, 100)); + QTest::newRow("two rects vs small ellipse (upper left)") << twoRects << ellipsePath(0, 0, 50, 50) << false << true; + QTest::newRow("two rects vs small ellipse (upper right)") << twoRects << ellipsePath(50, 0, 50, 50) << false << true; + QTest::newRow("two rects vs small ellipse (lower right)") << twoRects << ellipsePath(50, 50, 50, 50) << false << true; + QTest::newRow("two rects vs small ellipse (lower left)") << twoRects << ellipsePath(0, 50, 50, 50) << false << true; + QTest::newRow("two rects vs small ellipse (centered)") << twoRects << ellipsePath(25, 25, 50, 50) << true << true; + QTest::newRow("two rects vs equal ellipse") << twoRects << ellipsePath(0, 0, 100, 100) << false << true; + QTest::newRow("two rects vs big ellipse") << twoRects << ellipsePath(-10, -10, 120, 120) << false << true; + + QTest::newRow("two rects vs two small ellipses") << twoRects << ellipsePath(25, 25, 50, 50).united(ellipsePath(225, 25, 50, 50)) << true << true; + QTest::newRow("two rects vs two equal ellipses") << twoRects << ellipsePath(0, 0, 100, 100).united(ellipsePath(200, 0, 100, 100)) << false << true; + + QTest::newRow("two rects vs self") << twoRects << twoRects << false << true; + QTest::newRow("two ellipses vs self") << twoEllipses << twoEllipses << false << true; + + QPainterPath windingRect = rectPath(0, 0, 100, 100); + windingRect.addRect(25, 25, 100, 50); + windingRect.setFillRule(Qt::WindingFill); + + QTest::newRow("rect with winding rule vs tall rect") << windingRect << rectPath(40, 20, 20, 60) << true << true; + QTest::newRow("rect with winding rule vs self") << windingRect << windingRect << false << true; + + QPainterPath thickFrame = rectPath(0, 0, 100, 100).subtracted(rectPath(25, 25, 50, 50)); + QPainterPath thinFrame = rectPath(10, 10, 80, 80).subtracted(rectPath(15, 15, 70, 70)); + + QTest::newRow("thin frame in thick frame") << thickFrame << thinFrame << true << true; + QTest::newRow("rect in thick frame") << thickFrame << rectPath(40, 40, 20, 20) << false << false; + QTest::newRow("rect in thin frame") << thinFrame << rectPath(40, 40, 20, 20) << false << false; + + QPainterPath ellipses; + ellipses.addEllipse(0, 0, 10, 10); + ellipses.addEllipse(4, 4, 2, 2); + ellipses.setFillRule(Qt::WindingFill); + + // the definition of QPainterPath::intersects() and contains() is fill-area based, + QTest::newRow("line in rect") << rectPath(0, 0, 100, 100) << linePath(10, 10, 90, 90) << true << true; + QTest::newRow("horizontal line in rect") << rectPath(0, 0, 100, 100) << linePath(10, 50, 90, 50) << true << true; + QTest::newRow("vertical line in rect") << rectPath(0, 0, 100, 100) << linePath(50, 10, 50, 90) << true << true; + + QTest::newRow("line through rect") << rectPath(0, 0, 100, 100) << linePath(-10, -10, 110, 110) << false << true; + QTest::newRow("line through rect 2") << rectPath(0, 0, 100, 100) << linePath(-10, 0, 110, 100) << false << true; + QTest::newRow("line through rect 3") << rectPath(0, 0, 100, 100) << linePath(5, 10, 110, 100) << false << true; + QTest::newRow("line through rect 4") << rectPath(0, 0, 100, 100) << linePath(-10, 0, 90, 90) << false << true; + + QTest::newRow("horizontal line through rect") << rectPath(0, 0, 100, 100) << linePath(-10, 50, 110, 50) << false << true; + QTest::newRow("vertical line through rect") << rectPath(0, 0, 100, 100) << linePath(50, -10, 50, 110) << false << true; + + QTest::newRow("line vs line") << linePath(0, 0, 10, 10) << linePath(10, 0, 0, 10) << false << true; + + QTest::newRow("line in rect with hole") << rectPath(0, 0, 10, 10).subtracted(rectPath(2, 2, 6, 6)) << linePath(4, 4, 6, 6) << false << false; + QTest::newRow("line in ellipse") << ellipses << linePath(3, 5, 7, 5) << false << true; + QTest::newRow("line in ellipse 2") << ellipses << linePath(4.5, 5, 5.5, 5) << true << true; + + QTest::newRow("winding ellipse") << ellipses << ellipsePath(4, 4, 2, 2) << false << true; + QTest::newRow("winding ellipse 2") << ellipses << ellipsePath(4.5, 4.5, 1, 1) << true << true; + ellipses.setFillRule(Qt::OddEvenFill); + QTest::newRow("odd even ellipse") << ellipses << ellipsePath(4, 4, 2, 2) << false << true; + QTest::newRow("odd even ellipse 2") << ellipses << ellipsePath(4.5, 4.5, 1, 1) << false << false; +} + +void tst_QPainterPath::testContainsAndIntersects() +{ + QFETCH(QPainterPath, path); + QFETCH(QPainterPath, candidate); + QFETCH(bool, contained); + QFETCH(bool, intersects); + + QCOMPARE(path.intersects(candidate), intersects); + QCOMPARE(path.contains(candidate), contained); +} + +void tst_QPainterPath::testSimplified_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<int>("elements"); + + QTest::newRow("rect") << rectPath(0, 0, 10, 10) << 5; + + QPainterPath twoRects = rectPath(0, 0, 10, 10); + twoRects.addPath(rectPath(5, 0, 10, 10)); + QTest::newRow("two rects (odd)") << twoRects << 10; + + twoRects.setFillRule(Qt::WindingFill); + QTest::newRow("two rects (winding)") << twoRects << 5; + + QPainterPath threeSteps = rectPath(0, 0, 10, 10); + threeSteps.addPath(rectPath(0, 10, 20, 10)); + threeSteps.addPath(rectPath(0, 20, 30, 10)); + + QTest::newRow("three rects (steps)") << threeSteps << 9; +} + +void tst_QPainterPath::testSimplified() +{ + QFETCH(QPainterPath, path); + QFETCH(int, elements); + + QPainterPath simplified = path.simplified(); + + QCOMPARE(simplified.elementCount(), elements); + + QVERIFY(simplified.subtracted(path).isEmpty()); + QVERIFY(path.subtracted(simplified).isEmpty()); +} + +void tst_QPainterPath::testStroker_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<QPen>("pen"); + QTest::addColumn<QPainterPath>("stroke"); + + QTest::newRow("line 1") << linePath(2, 2, 10, 2) << QPen(Qt::black, 2, Qt::SolidLine, Qt::FlatCap) << rectPath(2, 1, 8, 2); + QTest::newRow("line 2") << linePath(2, 2, 10, 2) << QPen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap) << rectPath(1, 1, 10, 2); + + QTest::newRow("rect") << rectPath(1, 1, 8, 8) << QPen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin) << rectPath(0, 0, 10, 10).subtracted(rectPath(2, 2, 6, 6)); + + QTest::newRow("dotted line") << linePath(0, 0, 10, 0) << QPen(Qt::black, 2, Qt::DotLine) << rectPath(-1, -1, 4, 2).united(rectPath(5, -1, 4, 2)); +} + +void tst_QPainterPath::testStroker() +{ + QFETCH(QPainterPath, path); + QFETCH(QPen, pen); + QFETCH(QPainterPath, stroke); + + QPainterPathStroker stroker; + stroker.setWidth(pen.widthF()); + stroker.setCapStyle(pen.capStyle()); + stroker.setJoinStyle(pen.joinStyle()); + stroker.setMiterLimit(pen.miterLimit()); + stroker.setDashPattern(pen.style()); + stroker.setDashOffset(pen.dashOffset()); + + QPainterPath result = stroker.createStroke(path); + + // check if stroke == result + QVERIFY(result.subtracted(stroke).isEmpty()); + QVERIFY(stroke.subtracted(result).isEmpty()); +} + +void tst_QPainterPath::testOperatorEquals() +{ + QPainterPath empty1; + QPainterPath empty2; + QVERIFY(empty1 == empty2); + + QPainterPath rect1; + rect1.addRect(100, 100, 100, 100); + QVERIFY(rect1 == rect1); + QVERIFY(rect1 != empty1); + + QPainterPath rect2; + rect2.addRect(100, 100, 100, 100); + QVERIFY(rect1 == rect2); + + rect2.setFillRule(Qt::WindingFill); + QVERIFY(rect1 != rect2); + + QPainterPath ellipse1; + ellipse1.addEllipse(50, 50, 100, 100); + QVERIFY(rect1 != ellipse1); + + QPainterPath ellipse2; + ellipse2.addEllipse(50, 50, 100, 100); + QVERIFY(ellipse1 == ellipse2); +} + +void tst_QPainterPath::testOperatorEquals_fuzzy() +{ + // if operator== returns true for two paths it should + // also return true when the same transform is applied to both paths + { + QRectF a(100, 100, 100, 50); + QRectF b = a.translated(1e-14, 1e-14); + + QPainterPath pa; + pa.addRect(a); + QPainterPath pb; + pb.addRect(b); + + QVERIFY(pa == pb); + + QTransform transform; + transform.translate(-100, -100); + + QVERIFY(transform.map(pa) == transform.map(pb)); + } + + // higher tolerance for error when path's bounding rect is big + { + QRectF a(1, 1, 1e6, 0.5e6); + QRectF b = a.translated(1e-7, 1e-7); + + QPainterPath pa; + pa.addRect(a); + QPainterPath pb; + pb.addRect(b); + + QVERIFY(pa == pb); + + QTransform transform; + transform.translate(-1, -1); + + QVERIFY(transform.map(pa) == transform.map(pb)); + } + + // operator== should return true for a path that has + // been transformed and then inverse transformed + { + QPainterPath a; + a.addRect(0, 0, 100, 100); + + QTransform transform; + transform.translate(100, 20); + transform.scale(1.5, 1.5); + + QPainterPath b = transform.inverted().map(transform.map(a)); + + QVERIFY(a == b); + } + + { + QPainterPath a; + a.lineTo(10, 0); + a.lineTo(10, 10); + a.lineTo(0, 10); + + QPainterPath b; + b.lineTo(10, 0); + b.moveTo(10, 10); + b.lineTo(0, 10); + + QVERIFY(a != b); + } +} + +void tst_QPainterPath::testOperatorDatastream() +{ + QPainterPath path; + path.addEllipse(0, 0, 100, 100); + path.addRect(0, 0, 100, 100); + path.setFillRule(Qt::WindingFill); + + // Write out + { + QFile data("data"); + bool ok = data.open(QFile::WriteOnly); + QVERIFY(ok); + QDataStream stream(&data); + stream << path; + } + + QPainterPath other; + // Read in + { + QFile data("data"); + bool ok = data.open(QFile::ReadOnly); + QVERIFY(ok); + QDataStream stream(&data); + stream >> other; + } + + QVERIFY(other == path); +} + +void tst_QPainterPath::closing() +{ + // lineto's + { + QPainterPath triangle(QPoint(100, 100)); + + triangle.lineTo(200, 100); + triangle.lineTo(200, 200); + QCOMPARE(triangle.elementCount(), 3); + + triangle.closeSubpath(); + QCOMPARE(triangle.elementCount(), 4); + QCOMPARE(triangle.elementAt(3).type, QPainterPath::LineToElement); + + triangle.moveTo(300, 300); + QCOMPARE(triangle.elementCount(), 5); + QCOMPARE(triangle.elementAt(4).type, QPainterPath::MoveToElement); + + triangle.lineTo(400, 300); + triangle.lineTo(400, 400); + QCOMPARE(triangle.elementCount(), 7); + + triangle.closeSubpath(); + QCOMPARE(triangle.elementCount(), 8); + + // this will should trigger implicit moveto... + triangle.lineTo(600, 300); + QCOMPARE(triangle.elementCount(), 10); + QCOMPARE(triangle.elementAt(8).type, QPainterPath::MoveToElement); + QCOMPARE(triangle.elementAt(9).type, QPainterPath::LineToElement); + + triangle.lineTo(600, 700); + QCOMPARE(triangle.elementCount(), 11); + } + + // curveto's + { + QPainterPath curves(QPoint(100, 100)); + + curves.cubicTo(200, 100, 100, 200, 200, 200); + QCOMPARE(curves.elementCount(), 4); + + curves.closeSubpath(); + QCOMPARE(curves.elementCount(), 5); + QCOMPARE(curves.elementAt(4).type, QPainterPath::LineToElement); + + curves.moveTo(300, 300); + QCOMPARE(curves.elementCount(), 6); + QCOMPARE(curves.elementAt(5).type, QPainterPath::MoveToElement); + + curves.cubicTo(400, 300, 300, 400, 400, 400); + QCOMPARE(curves.elementCount(), 9); + + curves.closeSubpath(); + QCOMPARE(curves.elementCount(), 10); + + // should trigger implicit moveto.. + curves.cubicTo(100, 800, 800, 100, 800, 800); + QCOMPARE(curves.elementCount(), 14); + QCOMPARE(curves.elementAt(10).type, QPainterPath::MoveToElement); + QCOMPARE(curves.elementAt(11).type, QPainterPath::CurveToElement); + } + + { + QPainterPath rects; + rects.addRect(100, 100, 100, 100); + + QCOMPARE(rects.elementCount(), 5); + QCOMPARE(rects.elementAt(0).type, QPainterPath::MoveToElement); + QCOMPARE(rects.elementAt(4).type, QPainterPath::LineToElement); + + rects.addRect(300, 100, 100,100); + QCOMPARE(rects.elementCount(), 10); + QCOMPARE(rects.elementAt(5).type, QPainterPath::MoveToElement); + QCOMPARE(rects.elementAt(9).type, QPainterPath::LineToElement); + + rects.lineTo(0, 0); + QCOMPARE(rects.elementCount(), 12); + QCOMPARE(rects.elementAt(10).type, QPainterPath::MoveToElement); + QCOMPARE(rects.elementAt(11).type, QPainterPath::LineToElement); + } + + { + QPainterPath ellipses; + ellipses.addEllipse(100, 100, 100, 100); + + QCOMPARE(ellipses.elementCount(), 13); + QCOMPARE(ellipses.elementAt(0).type, QPainterPath::MoveToElement); + QCOMPARE(ellipses.elementAt(10).type, QPainterPath::CurveToElement); + + ellipses.addEllipse(300, 100, 100,100); + QCOMPARE(ellipses.elementCount(), 26); + QCOMPARE(ellipses.elementAt(13).type, QPainterPath::MoveToElement); + QCOMPARE(ellipses.elementAt(23).type, QPainterPath::CurveToElement); + + ellipses.lineTo(0, 0); + QCOMPARE(ellipses.elementCount(), 28); + QCOMPARE(ellipses.elementAt(26).type, QPainterPath::MoveToElement); + QCOMPARE(ellipses.elementAt(27).type, QPainterPath::LineToElement); + } + + { + QPainterPath path; + path.moveTo(10, 10); + path.lineTo(40, 10); + path.lineTo(25, 20); + path.lineTo(10 + 1e-13, 10 + 1e-13); + QCOMPARE(path.elementCount(), 4); + path.closeSubpath(); + QCOMPARE(path.elementCount(), 4); + } +} + +void tst_QPainterPath::testArcMoveTo_data() +{ + QTest::addColumn<QRectF>("rect"); + QTest::addColumn<qreal>("angle"); + + QList<QRectF> rects; + rects << QRectF(100, 100, 100, 100) + << QRectF(100, 100, -100, 100) + << QRectF(100, 100, 100, -100) + << QRectF(100, 100, -100, -100); + + for (int domain=0; domain<rects.size(); ++domain) { + for (int i=-360; i<=360; ++i) { + QTest::newRow("test") << rects.at(domain) << (qreal) i; + } + + // test low angles + QTest::newRow("test") << rects.at(domain) << (qreal) 1e-10; + QTest::newRow("test") << rects.at(domain) << (qreal)-1e-10; + } +} + +void tst_QPainterPath::operators_data() +{ + QTest::addColumn<QPainterPath>("test"); + QTest::addColumn<QPainterPath>("expected"); + + QPainterPath a; + QPainterPath b; + a.addRect(0, 0, 100, 100); + b.addRect(50, 50, 100, 100); + + QTest::newRow("a & b") << (a & b) << a.intersected(b); + QTest::newRow("a | b") << (a | b) << a.united(b); + QTest::newRow("a + b") << (a + b) << a.united(b); + QTest::newRow("a - b") << (a - b) << a.subtracted(b); + + QPainterPath c = a; + QTest::newRow("a &= b") << (a &= b) << a.intersected(b); + c = a; + QTest::newRow("a |= b") << (a |= b) << a.united(b); + c = a; + QTest::newRow("a += b") << (a += b) << a.united(b); + c = a; + QTest::newRow("a -= b") << (a -= b) << a.subtracted(b); +} + +void tst_QPainterPath::operators() +{ + QFETCH(QPainterPath, test); + QFETCH(QPainterPath, expected); + + QCOMPARE(test, expected); +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#define ANGLE(t) ((t) * 2 * M_PI / 360.0) + + +static inline bool pathFuzzyCompare(double p1, double p2) +{ + return qAbs(p1 - p2) < 0.001; +} + + +static inline bool pathFuzzyCompare(float p1, float p2) +{ + return qAbs(p1 - p2) < 0.001; +} + + +void tst_QPainterPath::testArcMoveTo() +{ + QFETCH(QRectF, rect); + QFETCH(qreal, angle); + + QPainterPath path; + path.arcMoveTo(rect, angle); + path.arcTo(rect, angle, 30); + path.arcTo(rect, angle + 30, 30); + + QPointF pos = path.elementAt(0); + + QVERIFY((path.elementCount()-1) % 3 == 0); + + qreal x_radius = rect.width() / 2.0; + qreal y_radius = rect.height() / 2.0; + + QPointF shouldBe = rect.center() + + QPointF(x_radius * cos(ANGLE(angle)), -y_radius * sin(ANGLE(angle))); + + qreal iw = 1 / rect.width(); + qreal ih = 1 / rect.height(); + + QVERIFY(pathFuzzyCompare(pos.x() * iw, shouldBe.x() * iw)); + QVERIFY(pathFuzzyCompare(pos.y() * ih, shouldBe.y() * ih)); +} + +void tst_QPainterPath::testOnPath_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<qreal>("start"); + QTest::addColumn<qreal>("middle"); + QTest::addColumn<qreal>("end"); + + QPainterPath path = QPainterPath(QPointF(153, 199)); + path.cubicTo(QPointF(147, 61), QPointF(414, 18), + QPointF(355, 201)); + + QTest::newRow("First case") << path + << qreal(93.0) + << qreal(4.0) + << qreal(252.13); + + path = QPainterPath(QPointF(328, 197)); + path.cubicTo(QPointF(150, 50), QPointF(401, 50), + QPointF(225, 197)); + QTest::newRow("Second case") << path + << qreal(140.0) + << qreal(0.0) + << qreal(220.0); + + path = QPainterPath(QPointF(328, 197)); + path.cubicTo(QPointF(101 , 153), QPointF(596, 151), + QPointF(353, 197)); + QTest::newRow("Third case") << path + << qreal(169.0) + << qreal(0.22) + << qreal(191.0); + + path = QPainterPath(QPointF(153, 199)); + path.cubicTo(QPointF(59, 53), QPointF(597, 218), + QPointF(355, 201)); + QTest::newRow("Fourth case") << path + << qreal(122.0) + << qreal(348.0) + << qreal(175.0); + +} + +#define SIGN(x) ((x < 0)?-1:1) +void tst_QPainterPath::testOnPath() +{ + QFETCH(QPainterPath, path); + QFETCH(qreal, start); + QFETCH(qreal, middle); + QFETCH(qreal, end); + + int signStart = SIGN(start); + int signMid = SIGN(middle); + int signEnd = SIGN(end); + + static const qreal diff = 3; + + qreal angle = path.angleAtPercent(0); + QCOMPARE(SIGN(angle), signStart); + QVERIFY(qAbs(angle-start) < diff); + + angle = path.angleAtPercent(0.5); + QCOMPARE(SIGN(angle), signMid); + QVERIFY(qAbs(angle-middle) < diff); + + angle = path.angleAtPercent(1); + QCOMPARE(SIGN(angle), signEnd); + QVERIFY(qAbs(angle-end) < diff); +} + +void tst_QPainterPath::pointAtPercent_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<qreal>("percent"); + QTest::addColumn<QPointF>("point"); + + QPainterPath path; + path.lineTo(100, 0); + + QTest::newRow("Case 1") << path << qreal(0.2) << QPointF(20, 0); + QTest::newRow("Case 2") << path << qreal(0.5) << QPointF(50, 0); + QTest::newRow("Case 3") << path << qreal(0.0) << QPointF(0, 0); + QTest::newRow("Case 4") << path << qreal(1.0) << QPointF(100, 0); + + path = QPainterPath(); + path.lineTo(0, 100); + + QTest::newRow("Case 5") << path << qreal(0.2) << QPointF(0, 20); + QTest::newRow("Case 6") << path << qreal(0.5) << QPointF(0, 50); + QTest::newRow("Case 7") << path << qreal(0.0) << QPointF(0, 0); + QTest::newRow("Case 8") << path << qreal(1.0) << QPointF(0, 100); + + path.lineTo(300, 100); + + QTest::newRow("Case 9") << path << qreal(0.25) << QPointF(0, 100); + QTest::newRow("Case 10") << path << qreal(0.5) << QPointF(100, 100); + QTest::newRow("Case 11") << path << qreal(0.75) << QPointF(200, 100); + + path = QPainterPath(); + path.addEllipse(0, 0, 100, 100); + + QTest::newRow("Case 12") << path << qreal(0.0) << QPointF(100, 50); + QTest::newRow("Case 13") << path << qreal(0.25) << QPointF(50, 100); + QTest::newRow("Case 14") << path << qreal(0.5) << QPointF(0, 50); + QTest::newRow("Case 15") << path << qreal(0.75) << QPointF(50, 0); + QTest::newRow("Case 16") << path << qreal(1.0) << QPointF(100, 50); + + path = QPainterPath(); + QRectF rect(241, 273, 185, 228); + path.addEllipse(rect); + QTest::newRow("Case 17") << path << qreal(1.0) << QPointF(rect.right(), qreal(0.5) * (rect.top() + rect.bottom())); + + path = QPainterPath(); + path.moveTo(100, 100); + QTest::newRow("Case 18") << path << qreal(0.0) << QPointF(100, 100); + QTest::newRow("Case 19") << path << qreal(1.0) << QPointF(100, 100); +} + +void tst_QPainterPath::pointAtPercent() +{ + QFETCH(QPainterPath, path); + QFETCH(qreal, percent); + QFETCH(QPointF, point); + + QPointF result = path.pointAtPercent(percent); + QVERIFY(pathFuzzyCompare(point.x() , result.x())); + QVERIFY(pathFuzzyCompare(point.y() , result.y())); +} + +void tst_QPainterPath::setElementPositionAt() +{ + QPainterPath path(QPointF(42., 42.)); + QCOMPARE(path.elementCount(), 1); + QVERIFY(path.elementAt(0).type == QPainterPath::MoveToElement); + QCOMPARE(path.elementAt(0).x, qreal(42.)); + QCOMPARE(path.elementAt(0).y, qreal(42.)); + + QPainterPath copy = path; + copy.setElementPositionAt(0, qreal(0), qreal(0)); + QCOMPARE(copy.elementCount(), 1); + QVERIFY(copy.elementAt(0).type == QPainterPath::MoveToElement); + QCOMPARE(copy.elementAt(0).x, qreal(0)); + QCOMPARE(copy.elementAt(0).y, qreal(0)); + + QCOMPARE(path.elementCount(), 1); + QVERIFY(path.elementAt(0).type == QPainterPath::MoveToElement); + QCOMPARE(path.elementAt(0).x, qreal(42.)); + QCOMPARE(path.elementAt(0).y, qreal(42.)); +} + +void tst_QPainterPath::angleAtPercent() +{ + for (int angle = 0; angle < 360; ++angle) { + QLineF line = QLineF::fromPolar(100, angle); + QPainterPath path; + path.moveTo(line.p1()); + path.lineTo(line.p2()); + + QCOMPARE(path.angleAtPercent(0.5), line.angle()); + } +} + +void tst_QPainterPath::arcWinding_data() +{ + QTest::addColumn<QPainterPath>("path"); + QTest::addColumn<QPointF>("point"); + QTest::addColumn<bool>("inside"); + + QPainterPath a; + a.addEllipse(0, 0, 100, 100); + a.addRect(50, 50, 100, 100); + + QTest::newRow("Case A (oddeven)") << a << QPointF(55, 55) << false; + a.setFillRule(Qt::WindingFill); + QTest::newRow("Case A (winding)") << a << QPointF(55, 55) << true; + + QPainterPath b; + b.arcMoveTo(0, 0, 100, 100, 10); + b.arcTo(0, 0, 100, 100, 10, 360); + b.addRect(50, 50, 100, 100); + + QTest::newRow("Case B (oddeven)") << b << QPointF(55, 55) << false; + b.setFillRule(Qt::WindingFill); + QTest::newRow("Case B (winding)") << b << QPointF(55, 55) << false; + + QPainterPath c; + c.arcMoveTo(0, 0, 100, 100, 0); + c.arcTo(0, 0, 100, 100, 0, 360); + c.addRect(50, 50, 100, 100); + + QTest::newRow("Case C (oddeven)") << c << QPointF(55, 55) << false; + c.setFillRule(Qt::WindingFill); + QTest::newRow("Case C (winding)") << c << QPointF(55, 55) << false; + + QPainterPath d; + d.arcMoveTo(0, 0, 100, 100, 10); + d.arcTo(0, 0, 100, 100, 10, -360); + d.addRect(50, 50, 100, 100); + + QTest::newRow("Case D (oddeven)") << d << QPointF(55, 55) << false; + d.setFillRule(Qt::WindingFill); + QTest::newRow("Case D (winding)") << d << QPointF(55, 55) << true; + + QPainterPath e; + e.arcMoveTo(0, 0, 100, 100, 0); + e.arcTo(0, 0, 100, 100, 0, -360); + e.addRect(50, 50, 100, 100); + + QTest::newRow("Case E (oddeven)") << e << QPointF(55, 55) << false; + e.setFillRule(Qt::WindingFill); + QTest::newRow("Case E (winding)") << e << QPointF(55, 55) << true; +} + +void tst_QPainterPath::arcWinding() +{ + QFETCH(QPainterPath, path); + QFETCH(QPointF, point); + QFETCH(bool, inside); + + QCOMPARE(path.contains(point), inside); +} + +void tst_QPainterPath::testToFillPolygons() +{ + QPainterPath path; + path.lineTo(QPointF(0, 50)); + path.lineTo(QPointF(50, 50)); + + path.moveTo(QPointF(70, 50)); + path.lineTo(QPointF(70, 100)); + path.lineTo(QPointF(40, 100)); + + const QList<QPolygonF> polygons = path.toFillPolygons(); + QCOMPARE(polygons.size(), 2); + QCOMPARE(polygons.first().count(QPointF(70, 50)), 0); +} + +void tst_QPainterPath::testNaNandInfinites() +{ + QPainterPath path1; + QPainterPath path2 = path1; + + QPointF p1 = QPointF(qSNaN(), 1); + QPointF p2 = QPointF(qQNaN(), 1); + QPointF p3 = QPointF(qQNaN(), 1); + QPointF pInf = QPointF(qInf(), 1); + + // all these operations with NaN/Inf should be ignored + // can't test operator>> reliably, as we can't create a path with NaN to << later + + path1.moveTo(p1); + path1.moveTo(qSNaN(), qQNaN()); + path1.moveTo(pInf); + + path1.lineTo(p1); + path1.lineTo(qSNaN(), qQNaN()); + path1.lineTo(pInf); + + path1.cubicTo(p1, p2, p3); + path1.cubicTo(p1, QPointF(1, 1), QPointF(2, 2)); + path1.cubicTo(pInf, QPointF(10, 10), QPointF(5, 1)); + + path1.quadTo(p1, p2); + path1.quadTo(QPointF(1, 1), p3); + path1.quadTo(QPointF(1, 1), pInf); + + path1.arcTo(QRectF(p1, p2), 5, 5); + path1.arcTo(QRectF(pInf, QPointF(1, 1)), 5, 5); + + path1.addRect(QRectF(p1, p2)); + path1.addRect(QRectF(pInf, QPointF(1, 1))); + + path1.addEllipse(QRectF(p1, p2)); + path1.addEllipse(QRectF(pInf, QPointF(1, 1))); + + QCOMPARE(path1, path2); + + path1.lineTo(QPointF(1, 1)); + QVERIFY(path1 != path2); +} + +void tst_QPainterPath::connectPathDuplicatePoint() +{ + QPainterPath a; + a.moveTo(10, 10); + a.lineTo(20, 20); + + QPainterPath b; + b.moveTo(20, 20); + b.lineTo(30, 10); + + a.connectPath(b); + + QPainterPath c; + c.moveTo(10, 10); + c.lineTo(20, 20); + c.lineTo(30, 10); + + QCOMPARE(c, a); +} + +void tst_QPainterPath::connectPathMoveTo() +{ + QPainterPath path1; + QPainterPath path2; + QPainterPath path3; + QPainterPath path4; + + path1.moveTo(1,1); + + path2.moveTo(4,4); + path2.lineTo(5,6); + path2.lineTo(6,7); + + path3.connectPath(path2); + + path4.lineTo(5,5); + + path1.connectPath(path2); + + QVERIFY(path1.elementAt(0).type == QPainterPath::MoveToElement); + QVERIFY(path2.elementAt(0).type == QPainterPath::MoveToElement); + QVERIFY(path3.elementAt(0).type == QPainterPath::MoveToElement); + QVERIFY(path4.elementAt(0).type == QPainterPath::MoveToElement); +} + +void tst_QPainterPath::translate() +{ + QPainterPath path; + + // Path with no elements. + QCOMPARE(path.currentPosition(), QPointF()); + path.translate(50.5, 50.5); + QCOMPARE(path.currentPosition(), QPointF()); + QCOMPARE(path.translated(50.5, 50.5).currentPosition(), QPointF()); + + // path.isEmpty(), but we have one MoveTo element that should be translated. + path.moveTo(50, 50); + QCOMPARE(path.currentPosition(), QPointF(50, 50)); + path.translate(99.9, 99.9); + QCOMPARE(path.currentPosition(), QPointF(149.9, 149.9)); + path.translate(-99.9, -99.9); + QCOMPARE(path.currentPosition(), QPointF(50, 50)); + QCOMPARE(path.translated(-50, -50).currentPosition(), QPointF(0, 0)); + + // Complex path. + QRegion shape(100, 100, 300, 200, QRegion::Ellipse); + shape -= QRect(225, 175, 50, 50); + QPainterPath complexPath; + complexPath.addRegion(shape); + QVector<QPointF> untranslatedElements; + for (int i = 0; i < complexPath.elementCount(); ++i) + untranslatedElements.append(QPointF(complexPath.elementAt(i))); + + const QPainterPath untranslatedComplexPath(complexPath); + const QPointF offset(100, 100); + complexPath.translate(offset); + + for (int i = 0; i < complexPath.elementCount(); ++i) + QCOMPARE(QPointF(complexPath.elementAt(i)) - offset, untranslatedElements.at(i)); + + QCOMPARE(complexPath.translated(-offset), untranslatedComplexPath); +} + + +void tst_QPainterPath::lineWithinBounds() +{ + const int iteration_count = 3; + volatile const qreal yVal = 0.5; + QPointF a(0.0, yVal); + QPointF b(1000.0, yVal); + QPointF c(2000.0, yVal); + QPointF d(3000.0, yVal); + QPainterPath path; + path.moveTo(QPointF(0, yVal)); + path.cubicTo(QPointF(1000.0, yVal), QPointF(2000.0, yVal), QPointF(3000.0, yVal)); + for(int i=0; i<=iteration_count; i++) { + qreal actual = path.pointAtPercent(qreal(i) / iteration_count).y(); + QVERIFY(actual == yVal); // don't use QCOMPARE, don't want fuzzy comparison + } +} + + +QTEST_APPLESS_MAIN(tst_QPainterPath) + +#include "tst_qpainterpath.moc" diff --git a/tests/auto/gui/painting/qpainterpathstroker/.gitignore b/tests/auto/gui/painting/qpainterpathstroker/.gitignore new file mode 100644 index 0000000000..e171c5da31 --- /dev/null +++ b/tests/auto/gui/painting/qpainterpathstroker/.gitignore @@ -0,0 +1 @@ +tst_qpainterpathstroker diff --git a/tests/auto/gui/painting/qpainterpathstroker/qpainterpathstroker.pro b/tests/auto/gui/painting/qpainterpathstroker/qpainterpathstroker.pro new file mode 100644 index 0000000000..b6f62a2eee --- /dev/null +++ b/tests/auto/gui/painting/qpainterpathstroker/qpainterpathstroker.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qpainterpathstroker.cpp + + + diff --git a/tests/auto/gui/painting/qpainterpathstroker/tst_qpainterpathstroker.cpp b/tests/auto/gui/painting/qpainterpathstroker/tst_qpainterpathstroker.cpp new file mode 100644 index 0000000000..288263e5d7 --- /dev/null +++ b/tests/auto/gui/painting/qpainterpathstroker/tst_qpainterpathstroker.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qfile.h> +#include <QPainterPathStroker> + +#define _USE_MATH_DEFINES +#include <math.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPainterPathStroker : public QObject +{ + Q_OBJECT + +public: + +private slots: + void strokeEmptyPath(); +}; + +void tst_QPainterPathStroker::strokeEmptyPath() +{ + QPainterPath path; + path.moveTo(10, 10); + path.lineTo(10, 10); + QPainterPathStroker stroker; + QCOMPARE(stroker.createStroke(path), path); +} + +QTEST_APPLESS_MAIN(tst_QPainterPathStroker) + +#include "tst_qpainterpathstroker.moc" diff --git a/tests/auto/gui/painting/qpathclipper/.gitignore b/tests/auto/gui/painting/qpathclipper/.gitignore new file mode 100644 index 0000000000..a689eef0f6 --- /dev/null +++ b/tests/auto/gui/painting/qpathclipper/.gitignore @@ -0,0 +1 @@ +tst_qpathclipper diff --git a/tests/auto/gui/painting/qpathclipper/pathcompare.h b/tests/auto/gui/painting/qpathclipper/pathcompare.h new file mode 100644 index 0000000000..d80c189665 --- /dev/null +++ b/tests/auto/gui/painting/qpathclipper/pathcompare.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef PATHCOMPARE_H +#define PATHCOMPARE_H + +#include <qmath.h> + +namespace QPathCompare { + +static const int precision = 8; +static const qreal epsilon = qPow(0.1, precision); + +static inline bool fuzzyIsZero(qreal x, qreal relative) +{ + if (qAbs(relative) < epsilon) + return qAbs(x) < epsilon; + else + return qAbs(x / relative) < epsilon; +} + +static bool fuzzyCompare(const QPointF &a, const QPointF &b) +{ + const QPointF delta = a - b; + + const qreal x = qMax(qAbs(a.x()), qAbs(b.x())); + const qreal y = qMax(qAbs(a.y()), qAbs(b.y())); + + return fuzzyIsZero(delta.x(), x) && fuzzyIsZero(delta.y(), y); +} + +static bool isClosed(const QPainterPath &path) +{ + if (path.elementCount() == 0) + return false; + + QPointF first = path.elementAt(0); + QPointF last = path.elementAt(path.elementCount() - 1); + + return fuzzyCompare(first, last); +} + +// rotation and direction independent path comparison +// allows paths to be shifted or reversed relative to each other +static bool comparePaths(const QPainterPath &actual, const QPainterPath &expected) +{ + const int endActual = isClosed(actual) ? actual.elementCount() - 1 : actual.elementCount(); + const int endExpected = isClosed(expected) ? expected.elementCount() - 1 : expected.elementCount(); + + if (endActual != endExpected) + return false; + + for (int i = 0; i < endActual; ++i) { + int k = 0; + for (k = 0; k < endActual; ++k) { + int i1 = k; + int i2 = (i + k) % endActual; + + QPointF a = actual.elementAt(i1); + QPointF b = expected.elementAt(i2); + + if (!fuzzyCompare(a, b)) + break; + } + + if (k == endActual) + return true; + + for (k = 0; k < endActual; ++k) { + int i1 = k; + int i2 = (i + endActual - k) % endActual; + + QPointF a = actual.elementAt(i1); + QPointF b = expected.elementAt(i2); + + if (!fuzzyCompare(a, b)) + break; + } + + if (k == endActual) + return true; + } + + return false; +} + +} + +#endif diff --git a/tests/auto/gui/painting/qpathclipper/paths.cpp b/tests/auto/gui/painting/qpathclipper/paths.cpp new file mode 100644 index 0000000000..950c34614e --- /dev/null +++ b/tests/auto/gui/painting/qpathclipper/paths.cpp @@ -0,0 +1,734 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "paths.h" + +QPainterPath Paths::rect() +{ + QPainterPath path; + + path.moveTo(45.885571, 62.857143); + path.lineTo(154.11442, 62.857143); + path.cubicTo(162.1236, 62.857143, + 168.57142, 70.260744, + 168.57142, 79.457144); + path.lineTo(168.57142, 123.4); + path.cubicTo(168.57142, 132.5964, + 162.1236, 140, + 154.11442, 140); + path.lineTo(45.885571, 140); + path.cubicTo(37.876394, 140, + 31.428572, 132.5964, + 31.428572, 123.4); + path.lineTo(31.428572, 79.457144); + path.cubicTo(31.428572,70.260744, + 37.876394,62.857143, + 45.885571,62.857143); + path.closeSubpath(); + return path; +} + +QPainterPath Paths::rect6() +{ + QPainterPath path; + + path.moveTo(45.885571, 62.857143); + path.lineTo(154.11442, 62.857143); + path.cubicTo(162.1236, 62.857143, + 168.57142, 70.260744, + 168.57142, 79.457144); + path.lineTo(168.57142, 123.4); + path.cubicTo(168.57142, 132.5964, + 162.1236, 140, + 154.11442, 140); + path.lineTo(45.885571, 140); + path.closeSubpath(); + return path; +} + + +QPainterPath Paths::heart() +{ + QPainterPath path; + path.moveTo(263.41570, 235.14588); + path.cubicTo(197.17570,235.14588, + 143.41575,288.90587, + 143.41575,355.14588); + path.cubicTo(143.41575, 489.90139, + 279.34890, 525.23318, + 371.97820, 658.45392); + path.cubicTo(459.55244,526.05056, + 600.54070,485.59932, + 600.54070,355.14588); + path.cubicTo(600.54070,288.90588, 546.78080,235.14587, 480.54070,235.14588); + path.cubicTo(432.49280,235.14588, 391.13910,263.51631, 371.97820,304.33338); + path.cubicTo(352.81740,263.51630, 311.46370,235.14587, 263.41570,235.14588); + path.closeSubpath(); + return path; +} + + +QPainterPath Paths::body() +{ + QPainterPath path; + path.moveTo(62.500000,15.531250); + path.cubicTo(48.633197,15.531250, 37.374999,26.789445, 37.375000,40.656250); + path.cubicTo(37.375000,54.523053, 48.633195,65.781252, 62.500000,65.781250); + path.cubicTo(76.366803,65.781250, 87.624998,54.523052, 87.625000,40.656250); + path.cubicTo(87.625000,26.789447, 76.366802,15.531250, 62.500000,15.531250); + path.closeSubpath(); + path.moveTo(54.437500,65.812500); + path.cubicTo(35.184750,65.812499, 19.687500,81.341002, 19.687500,100.59375); + path.lineTo(19.687500,155.68750); + path.cubicTo(19.687501,167.50351, 25.539122,177.88308, 34.500000,184.15625); + path.lineTo(34.500000,254.03125); + path.cubicTo(34.499999,257.03306, 46.990615,259.43748, 62.500000,259.43750); + path.cubicTo(78.009381,259.43751, 90.468750,257.03307, 90.468750,254.03125); + path.lineTo(90.468750,184.15625); + path.cubicTo(99.429633,177.88307, 105.28125,167.50352, 105.28125,155.68750); + path.lineTo(105.28125,100.59375); + path.cubicTo(105.28125,81.341000, 89.784000,65.812500, 70.531250,65.812500); + path.lineTo(54.437500,65.812500); + path.closeSubpath(); + + return path; +} + + +QPainterPath Paths::mailbox() +{ + QPainterPath path; + path.moveTo(355.22951,136.82424); + path.lineTo(332.03629,112.56585); + path.lineTo(325.71086,57.501867); + path.cubicTo(325.71086,57.501867, 410.12308,19.428758, 427.45202,29.094560); + path.cubicTo(444.78096,38.760366, 443.62570,54.289660, 443.62570,54.289660); + path.lineTo(443.62570,100.11509); + path.lineTo(355.22951,136.82424); + path.closeSubpath(); + + return path; +} + + +QPainterPath Paths::deer() +{ + QPainterPath path; + + path.moveTo(39.88,31.658); + path.cubicTo(35.632,31.658, 31.398,31.004, 27.871,32.82); + path.cubicTo(25.015,34.29, 19.608,34.158, 16.297,34.158); + path.cubicTo(14.722,34.158, 17.755,37.718, 17.709,38.922); + path.cubicTo(17.578,42.396, 24.612,43.15, 26.755,44.058); + path.cubicTo(30.062,45.46, 28.682,47.701, 28.963,50.574); + path.cubicTo(29.715,58.243, 26.887,63.745, 24.182,70.589); + path.cubicTo(23.365,72.657, 21.772,75.56, 21.972,77.866); + path.cubicTo(22.333,82.029, 15.803,77.207, 13.894,76.535); + path.cubicTo(10.977,75.508, 5.507,74.071, 2.424,75.331); + path.cubicTo(-1.532,76.947, 0.076,80.491, 2.169,82.806); + path.cubicTo(6.17,87.234, 2.703,90.713, 3.895,95.363); + path.cubicTo(4.321,97.026, 11.682,104.683, 12.858,103.668); + path.cubicTo(16.706,100.347, 11.464,98.692, 10.105,96.164); + path.cubicTo(9.487,95.015, 8.616,83.742, 8.866,83.759); + path.cubicTo(10.018,83.837, 12.591,85.867, 13.671,86.392); + path.cubicTo(16.889,87.954, 20.066,89.63, 22.963,91.741); + path.cubicTo(29.156,94.47, 35.543,96.965, 42.102,98.676); + path.cubicTo(51.085,101.02, 59.407,102.003, 68.009,106.005); + path.cubicTo(72.92,108.289, 72.05,113.282, 75.744,117.004); + path.cubicTo(79.422,120.709, 84.733,123.053, 88.978,126.053); + path.cubicTo(92.402,128.473, 95.422,132.308, 97.334,135.998); + path.cubicTo(99.551,140.279, 99.071,146.004, 99.838,150.674); + path.cubicTo(100.369,153.91, 104.378,156.321, 106.302,158.859); + path.cubicTo(110.471,164.355, 109.86,155.112, 108.163,154.412); + path.cubicTo(104.97,153.094, 103.991,146.625, 103.812,143.439); + path.cubicTo(103.525,138.336, 105.568,134.331, 101.918,130.346); + path.cubicTo(95.104,122.907, 89.488,114.182, 94.711,103.742); + path.cubicTo(96.889,99.388, 91.191,95.497, 96.94,94.368); + path.cubicTo(99.551,93.856, 102.49,94.367, 104.326,92.034); + path.cubicTo(106.639,89.095, 105.063,85.343, 102.943,82.798); + path.cubicTo(102.686,82.417, 102.359,82.121, 101.962,81.909); + path.cubicTo(102.331,81.909, 101.923,86.98, 100.981,87.628); + path.cubicTo(98.868,89.082, 95.569,91.586, 92.88,91.672); + path.cubicTo(90.569,91.745, 86.738,89.184, 85.212,87.658); + path.cubicTo(84.092,86.538, 80.176,86.157, 78.598,85.83); + path.cubicTo(74.737,85.031, 71.741,84.326, 68.012,82.806); + path.cubicTo(63.318,80.893, 58.687,78.672, 54.555,75.71); + path.cubicTo(44.573,68.555, 42.755,56.146, 44.022,44.495); + path.cubicTo(44.295,41.987, 43.169,38.057, 44.617,35.915); + path.cubicTo(44.961,35.406, 46.52,35.553, 47.119,35.024); + path.cubicTo(47.882,34.35, 49.574,31.822, 49.878,30.792); + path.cubicTo(51.126,26.569, 44.36,32.002, 45.336,31.938); + path.cubicTo(43.861,32.036, 47.011,22.934, 47.191,22.574); + path.cubicTo(47.555,21.846, 52.489,13.123, 49.511,13.222); + path.cubicTo(47.643,13.284, 48.563,18.667, 46.354,18.227); + path.cubicTo(43.964,17.751, 40.522,11.396, 41.566,9.011); + path.cubicTo(43.4,4.819, 39.743,3.905, 39.214,7.564); + path.cubicTo(39.112,8.269, 40.893,13.438, 38.159,12.665); + path.cubicTo(35.335,11.866, 35.748,-0.125, 34.38,-8.0352391e-15); + path.cubicTo(31.991,0.219, 34.074,10.836, 33.361,12.176); + path.cubicTo(33.144,12.584, 29.68,8.66, 29.459,7.718); + path.cubicTo(28.48,3.558, 28.031,5.106, 26.87,7.752); + path.cubicTo(25.333,11.254, 37.159,17.423, 39.292,18.663); + path.cubicTo(40.993,19.651, 42.39,20.504, 42.973,22.48); + path.cubicTo(43.482,24.205, 44.098,26.568, 42.926,28.191); + path.cubicTo(42.092,29.346, 39.88,29.982, 39.88,31.658); + return path; +} + + +QPainterPath Paths::fire() +{ + QPainterPath path; + + path.moveTo(362.83759,116.70426); + path.cubicTo(342.56574,131.59686, 300.71403,161.23127, 311.38454,218.12635); + path.cubicTo(322.05506,275.02144, 358.53432,301.66527, 328.90674,328.73285); + path.cubicTo(299.27916,355.80044, 251.48877,339.59410, 255.46042,288.61972); + path.cubicTo(258.22374,253.15368, 278.34141,205.10942, 278.34141,205.10942); + path.cubicTo(278.34141,205.10942, 234.02455,233.13427, 219.68939,254.01270); + path.cubicTo(205.35424,274.89113, 189.71452,330.07842, 208.58356,373.33974); + path.cubicTo(227.45261,416.60109, 316.46286,456.33444, 351.12048,514.32780); + path.cubicTo(374.10258,552.78425, 355.05815,613.59741, 310.80422,636.59310); + path.cubicTo(256.63287,664.74219, 299.16588,580.49238, 285.22551,523.86186); + path.cubicTo(273.46790,476.09839, 265.70022,445.12001, 188.03132,432.51681); + path.cubicTo(233.72591,465.34901, 242.16068,495.04075, 241.45928,524.11772); + path.cubicTo(240.78648,552.00862, 214.39595,634.57293, 177.39967,596.79021); + path.cubicTo(140.72642,559.33737, 214.27071,512.68654, 170.92945,471.62081); + path.cubicTo(174.73284,501.40284, 145.30515,514.98828, 131.55318,544.54392); + path.cubicTo(118.22673,573.18509, 123.55251,610.30651, 139.07596,645.41379); + path.cubicTo(181.14122,740.38745, 266.95518,726.23964, 208.75321,797.88229); + path.cubicTo(164.01134,852.95649, 162.90150,907.45084, 205.60384,970.81121); + path.cubicTo(240.06795,1021.9479, 371.11663,1060.7652, 432.20697,960.93460); + path.cubicTo(501.87852,820.00694, 357.14883,780.33174, 386.29974,732.84721); + path.cubicTo(405.70205,701.24238, 472.56601,668.86516, 501.09199,644.21233); + path.cubicTo(564.18184,587.55421, 561.84437,497.32621, 522.74229,471.25817); + path.cubicTo(530.19030,501.05022, 514.99952,542.79339, 483.67099,551.29691); + path.cubicTo(423.41173,567.65308, 458.18351,411.79373, 564.02075,393.61925); + path.cubicTo(530.91135,366.44998, 501.31413,367.33484, 454.91711,379.11707); + path.cubicTo(397.61736,393.57908, 407.64322,315.40944, 494.34643,262.67861); + path.cubicTo(549.19500,229.32101, 499.11573,147.63302, 491.66772,136.46100); + path.cubicTo(485.38713,213.93294, 435.43515,233.35601, 409.98053,235.72292); + path.cubicTo(375.27049,238.95043, 377.84554,214.33812, 396.75003,178.92950); + path.cubicTo(416.21172,142.47722, 448.15395,89.429942, 376.51366,44.060977); + path.cubicTo(388.13560,71.270572, 395.93673,94.012962, 362.83759,116.70426); + path.closeSubpath(); + return path; +} + + +QPainterPath Paths::lips() +{ + QPainterPath path; + + path.moveTo(177.02257,176.65905); + path.cubicTo(154.11895,176.65905, 136.56711,174.32266, 110.41800,155.61729); + path.cubicTo(83.894106,136.64382, 70.456540,123.78263, 44.264608,101.00195); + path.cubicTo(36.985036,94.670475, 11.607987,76.421189, 0.62503194,72.562763); + path.cubicTo(22.778258,60.937514, 46.738237,46.430325, 55.325084,40.325054); + path.cubicTo(79.128700,23.400628, 99.203004,0.53294656, 116.15033,0.61582047); + path.cubicTo(129.59137,0.68308215, 144.54744,18.524567, 177.02257,18.524567); + path.cubicTo(210.04060,18.524567, 224.45379,0.68308215, 237.89483,0.61582047); + path.cubicTo(254.84216,0.53294656, 274.91646,23.400628, 298.72008,40.325054); + path.cubicTo(307.30692,46.430325, 331.26690,60.937514, 353.42013,72.562763); + path.cubicTo(342.43717,76.421189, 317.06013,94.670475, 309.78055,101.00195); + path.cubicTo(283.58862,123.78263, 270.15105,136.64382, 243.62716,155.61729); + path.cubicTo(217.47805,174.32266, 199.38332,176.65905, 177.02257,176.65905); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::bezier1() +{ + QPainterPath path; + path.moveTo(50, 50); + path.cubicTo(100, 100, + 520, 90, + 400,400); + return path; +} + +QPainterPath Paths::bezier2() +{ + QPainterPath path; + path.moveTo(200,200); + path.cubicTo(200,125, 500,100, 500,500); + + return path; +} + +QPainterPath Paths::random1() +{ + QPainterPath path; + + path.moveTo(65.714286,91.428571); + path.lineTo(217.14286, 102.85714); + path.cubicTo(219.04762, 106.66666, + 220.95238, 110.47619, + 222.85714,114.28571); + path.cubicTo(231.2679, 131.10723, + 214.72525, 138.24185, + 211.42857,151.42857); + path.cubicTo(207.25902, 168.10676, + 213.24674, 175.8441, + 217.14286,191.42857); + path.cubicTo(221.088, 207.20915, + 201.21538,205.71429, + 188.57143,205.71429); + path.cubicTo(170.18303, 205.71429, + 161.42918, 197.50045, + 145.71429,185.71429); + path.cubicTo(113.93441, 161.87938, + 132.73699, 182.37652, + 137.14286, 200); + path.cubicTo(140.37884, 212.94392, + 128.50252, 217.16009, + 117.14286, 220); + path.cubicTo(98.323209, 224.70491, + 91.206108, 205.41767, + 82.857143, 194.28571); + path.cubicTo(77.307286, 186.8859, + 84.541768, 158.97578, + 85.714286, 154.28571); + path.cubicTo(87.843677, 145.76815, + 67.066253, 132.78054, + 60 , 125.71429); + path.cubicTo(54.074503, 119.78879, + 64.646395, 95.700137, + 65.714286, 91.428571); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::random2() +{ + QPainterPath path; + + path.moveTo(314.28571,160); + path.cubicTo(434.28571,125.71429, + 505.71429,200, + 505.71429,200); + path.lineTo(454.28571, 305.71429); + path.lineTo(337.14286, 302.85714); + path.cubicTo(337.14286, 302.85714, + 308.57143, 340, + 337.14286, 302.85714); + path.cubicTo(365.71429, 265.71429, + 200, 420, + 300, 291.42857); + path.cubicTo(400, 162.85714, + 254.28571, 240, + 254.28571, 240); + path.cubicTo(254.28571,240, + 240,71.428571, + 288.57143,134.28571); + path.cubicTo(337.14286,197.14286, + 314.28571,162.85714, + 314.28571,160); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::bezier3() +{ + QPainterPath path; + path.moveTo(295, 217); + path.cubicTo(364, 57, + 377, 34, + 456, 222); + return path; +} + +QPainterPath Paths::bezier4() +{ + QPainterPath path; + path.moveTo(200, 125); + path.cubicTo(200, 125, + 623, 126, + 623, 126); + return path; +} + +QPainterPath Paths::heart2() +{ + QPainterPath path; + path.moveTo(263.41570, 235.14588); + path.cubicTo(197.17570,235.14588, + 143.41575,288.90587, + 143.41575,355.14588); + path.cubicTo(143.41575, 489.90139, + 279.34890, 525.23318, + 371.97820, 658.45392); + return path; +} + +QPainterPath Paths::rect2() +{ + QPainterPath path; + + path.addRect(80, 80, 100, 100); + + return path; +} + + +QPainterPath Paths::rect3() +{ + QPainterPath path; + + path.addRect(100, 40, 100, 100); + + return path; +} + + +QPainterPath Paths::rect4() +{ + QPainterPath path; + + path.addRect(100, 0, 200, 200); + + path.addRect(120, 20, 80, 80); + + return path; +} + +QPainterPath Paths::simpleCurve() +{ + QPainterPath path; + path.moveTo(74, 160); + path.cubicTo( 74, 160, + 274, 406, + 425, 166); + path.cubicTo(577, -73, + 77, 160, + 74, 160); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::simpleCurve2() +{ + QPainterPath path; + path.moveTo(54, 140); + path.cubicTo( 54, 140, + 254, 386, + 405, 146); + path.cubicTo(557, -93, + 57, 140, + 54, 140); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::frame1() +{ + QPainterPath path; + path.moveTo(190.71429, 40.933613); + path.lineTo(683.57141, 40.933613); + path.cubicTo(697.42141, 40.933613, + 708.57141, 52.083613, + 708.57141, 65.933613); + path.lineTo(708.57141, 375.93361); + path.cubicTo(708.57141, 389.78361, + 697.42141, 400.93361, + 683.57141, 400.93361); + path.lineTo(190.71429, 400.93361); + path.cubicTo(176.86429, 400.93361, + 165.71429, 389.78361, + 165.71429,375.93361); + path.lineTo(165.71429, 65.933613); + path.cubicTo(165.71429,52.083613, + 176.86429,40.933613, + 190.71429,40.933613); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::frame2() +{ + QPainterPath path; + path.moveTo(55.114286, 103.79076); + path.lineTo(187.74288, 103.79076); + path.cubicTo(192.95048, 103.79076, + 197.14288, 107.88102, + 197.14288, 112.96176); + path.lineTo(197.14288, 131.76261); + path.cubicTo(197.14288, 136.84335, + 192.95048, 140.93361, + 187.74288, 140.93361); + path.lineTo(55.114286, 140.93361); + path.cubicTo(49.906687, 140.93361, + 45.714287, 136.84335, + 45.714287, 131.76261); + path.lineTo(45.714287, 112.96176); + path.cubicTo(45.714287, 107.88102, + 49.906687, 103.79076, + 55.114286, 103.79076); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::frame3() +{ + QPainterPath path; + path.moveTo(200,80.933609); + path.lineTo(682.85715,80.933609); + path.lineTo(682.85715,446.6479); + path.lineTo(200,446.6479); + path.lineTo(200,80.933609); + path.closeSubpath(); + return path; +} + +QPainterPath Paths::frame4() +{ + QPainterPath path; + + path.moveTo(88.571434,206.64789); + path.lineTo(231.42858,206.64789); + path.lineTo(231.42858,246.64789); + path.lineTo(88.571434,246.64789); + path.lineTo(88.571434,206.64789); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::simpleCurve3() +{ + QPainterPath path; + + path.moveTo(0, 0); + path.cubicTo(400,0, + 0,400, + 0,0); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::rect5() +{ + QPainterPath path; + + path.addRect(0, 0, 200, 200); + + return path; +} + +QPainterPath Paths::triangle1() +{ + QPainterPath path; + + path.moveTo(0, 0); + path.lineTo(60, 0); + path.lineTo(60, 60); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::triangle2() +{ + QPainterPath path; + + path.moveTo(0, 120); + path.lineTo(60, 120); + path.lineTo(60, 60); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::node() +{ + QRectF m_rect; + m_rect.setWidth(150); + m_rect.setHeight(100); + + QPainterPath shape; + shape.addRoundRect(m_rect, 25); + + const int conWidth = 10; + const int xOffset = 7; + + QRectF rect(xOffset, + conWidth + 20, + conWidth, conWidth); + shape.addEllipse(rect); + //shape.addRect(rect); + + rect = QRectF(m_rect.right() - conWidth - xOffset, + conWidth + 20, + conWidth, conWidth); + shape.addEllipse(rect); + //shape.addRect(rect); + return shape; +} + +QPainterPath Paths::interRect() +{ + QPainterPath path; + path.addRect(132, 42, 1, 1); + return path; +} + +QPainterPath Paths::bezierFlower() +{ + QPainterPath path; + path.moveTo(0, 0); + path.cubicTo(0, 50, -25, 75, -50, 100); + path.closeSubpath(); + path.moveTo(0, 0); + path.cubicTo(0, 50, 25, 75, 50, 100); + path.closeSubpath(); + + path.moveTo(0, 0); + path.cubicTo(0, -50, -25, -75, -50, -100); + path.closeSubpath(); + path.moveTo(0, 0); + path.cubicTo(0, -50, 25, -75, 50, -100); + path.closeSubpath(); + + path.moveTo(0, 0); + path.cubicTo(-50, 0, -75, -25, -100, -50); + path.closeSubpath(); + path.moveTo(0, 0); + path.cubicTo(-50, 0, -75, 25, -100, 50); + path.closeSubpath(); + + path.moveTo(0, 0); + path.cubicTo(50, 0, 75, -25, 100, -50); + path.closeSubpath(); + path.moveTo(0, 0); + path.cubicTo(50, 0, 75, 25, 100, 50); + path.closeSubpath(); + + return path; +} + +QPainterPath Paths::clover() +{ + QPainterPath path; + path.moveTo(50, 50); + path.lineTo(100, 25); + path.lineTo(100, 75); + path.lineTo(0, 25); + path.lineTo(0, 75); + path.lineTo(50, 50); + path.lineTo(75, 0); + path.lineTo(25, 0); + path.lineTo(75, 100); + path.lineTo(25, 100); + path.lineTo(50, 50); + return path; +} + +QPainterPath Paths::ellipses() +{ + QPainterPath path; + path.addEllipse(0, 0, 100, 100); + path.addEllipse(0, 20, 100, 60); + path.addEllipse(0, 40, 100, 20); + return path; +} + +QPainterPath Paths::windingFill() +{ + QPainterPath path; + path.addRect(0, 0, 100, 100); + path.addRect(50, 25, 100, 50); + path.setFillRule(Qt::WindingFill); + return path; +} + +QPainterPath Paths::oddEvenFill() +{ + QPainterPath path; + path.addRect(0, 0, 100, 100); + path.moveTo(50, 25); + path.lineTo(50, 75); + path.lineTo(150, 75); + path.lineTo(150, 25); + path.lineTo(50, 25); + path.setFillRule(Qt::OddEvenFill); + return path; +} + +QPainterPath Paths::squareWithHole() +{ + QPainterPath path; + path.addRect(0, 0, 100, 100); + path.addRect(30, 30, 40, 40); + return path; +} + +QPainterPath Paths::circleWithHole() +{ + QPainterPath path; + path.addEllipse(0, 0, 100, 100); + path.addEllipse(30, 30, 40, 40); + return path; +} + +QPainterPath Paths::bezierQuadrant() +{ + QPainterPath path; + int d = 1; + for (int i = 25; i <= 85; i += 10) { + path.moveTo(50, 100); + path.cubicTo(50, i, 50 + i* d / 2, 0, 50 + 50 * d, 0); + path.lineTo(50 + 50 * d, 100); + path.closeSubpath(); + } + + QMatrix m(2, 0, + 0, 2, + 0, 0); + + return path; +} diff --git a/tests/auto/gui/painting/qpathclipper/paths.h b/tests/auto/gui/painting/qpathclipper/paths.h new file mode 100644 index 0000000000..89ef785857 --- /dev/null +++ b/tests/auto/gui/painting/qpathclipper/paths.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef PATHS_H +#define PATHS_H + +#include <QPainterPath> + +namespace Paths +{ + QPainterPath rect(); + QPainterPath heart(); + QPainterPath body(); + QPainterPath mailbox(); + QPainterPath deer(); + QPainterPath fire(); + QPainterPath lips(); + + QPainterPath bezier1(); + QPainterPath bezier2(); + QPainterPath bezier3(); + QPainterPath bezier4(); + + QPainterPath random1(); + QPainterPath random2(); + + QPainterPath heart2(); + QPainterPath rect2(); + QPainterPath rect3(); + QPainterPath rect4(); + QPainterPath rect5(); + QPainterPath rect6(); + + QPainterPath simpleCurve(); + QPainterPath simpleCurve2(); + QPainterPath simpleCurve3(); + + QPainterPath frame1(); + QPainterPath frame2(); + QPainterPath frame3(); + QPainterPath frame4(); + + QPainterPath triangle1(); + QPainterPath triangle2(); + + QPainterPath node(); + QPainterPath interRect(); + + QPainterPath bezierFlower(); + QPainterPath clover(); + QPainterPath ellipses(); + QPainterPath windingFill(); + QPainterPath oddEvenFill(); + QPainterPath squareWithHole(); + QPainterPath circleWithHole(); + QPainterPath bezierQuadrant(); +} +#endif diff --git a/tests/auto/gui/painting/qpathclipper/qpathclipper.pro b/tests/auto/gui/painting/qpathclipper/qpathclipper.pro new file mode 100644 index 0000000000..85f4a58dcd --- /dev/null +++ b/tests/auto/gui/painting/qpathclipper/qpathclipper.pro @@ -0,0 +1,11 @@ +load(qttest_p4) +INCLUDEPATH += . +HEADERS += paths.h +SOURCES += tst_qpathclipper.cpp paths.cpp +QT += gui-private + +requires(contains(QT_CONFIG,private_tests)) + +unix:!mac:!symbian:LIBS+=-lm + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/gui/painting/qpathclipper/tst_qpathclipper.cpp b/tests/auto/gui/painting/qpathclipper/tst_qpathclipper.cpp new file mode 100644 index 0000000000..57a56b2d1a --- /dev/null +++ b/tests/auto/gui/painting/qpathclipper/tst_qpathclipper.cpp @@ -0,0 +1,1334 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "private/qpathclipper_p.h" +#include "paths.h" +#include "pathcompare.h" + +#include <QtTest/QtTest> + +#include <qpainterpath.h> +#include <qpolygon.h> +#include <qdebug.h> +#include <qpainter.h> + +#include <math.h> + +class tst_QPathClipper : public QObject +{ + Q_OBJECT + +public: + tst_QPathClipper(); + virtual ~tst_QPathClipper(); + +private: + void clipTest(int subjectIndex, int clipIndex, QPathClipper::Operation op); + + QList<QPainterPath> paths; + +public slots: + void initTestCase(); + +private slots: + void testWingedEdge(); + + void testComparePaths(); + + void clip_data(); + void clip(); + + void clip2(); + void clip3(); + + void testIntersections(); + void testIntersections2(); + void testIntersections3(); + void testIntersections4(); + void testIntersections5(); + void testIntersections6(); + void testIntersections7(); + void testIntersections8(); + void testIntersections9(); + + void zeroDerivativeCurves(); + + void task204301_data(); + void task204301(); + + void task209056(); + void task251909(); + + void qtbug3778(); +}; + +Q_DECLARE_METATYPE(QPainterPath) +Q_DECLARE_METATYPE(QPathClipper::Operation) + +tst_QPathClipper::tst_QPathClipper() +{ +} + +tst_QPathClipper::~tst_QPathClipper() +{ +} + +void tst_QPathClipper::initTestCase() +{ + paths << Paths::rect(); + paths << Paths::heart(); + paths << Paths::body(); + paths << Paths::mailbox(); + paths << Paths::deer(); + paths << Paths::fire(); + + paths << Paths::random1(); + paths << Paths::random2(); + + paths << Paths::heart2(); + paths << Paths::rect2(); + paths << Paths::rect3(); + paths << Paths::rect4(); + paths << Paths::rect5(); + paths << Paths::rect6(); + + paths << Paths::frame1(); + paths << Paths::frame2(); + paths << Paths::frame3(); + paths << Paths::frame4(); + + paths << Paths::triangle1(); + paths << Paths::triangle2(); + + paths << Paths::node(); + paths << Paths::interRect(); + + paths << Paths::simpleCurve(); + paths << Paths::simpleCurve2(); + paths << Paths::simpleCurve3(); + + paths << Paths::bezier1(); + paths << Paths::bezier2(); + paths << Paths::bezier3(); + paths << Paths::bezier4(); + + paths << Paths::bezierFlower(); + paths << Paths::lips(); + paths << Paths::clover(); + paths << Paths::ellipses(); + paths << Paths::windingFill(); + paths << Paths::oddEvenFill(); + paths << Paths::squareWithHole(); + paths << Paths::circleWithHole(); + paths << Paths::bezierQuadrant(); + + // make sure all the bounding rects are centered at the origin + for (int i = 0; i < paths.size(); ++i) { + QRectF bounds = paths[i].boundingRect(); + + QMatrix m(1, 0, + 0, 1, + -bounds.center().x(), -bounds.center().y()); + + paths[i] = m.map(paths[i]); + } +} + +static QPainterPath samplePath1() +{ + QPainterPath path; + path.moveTo(QPointF(200, 246.64789)); + path.lineTo(QPointF(200, 206.64789)); + path.lineTo(QPointF(231.42858, 206.64789)); + path.lineTo(QPointF(231.42858, 246.64789)); + path.lineTo(QPointF(200, 246.64789)); + return path; +} + +static QPainterPath samplePath2() +{ + QPainterPath path; + path.moveTo(QPointF(200, 146.64789)); + path.lineTo(QPointF(200, 106.64789)); + path.lineTo(QPointF(231.42858, 106.64789)); + path.lineTo(QPointF(231.42858, 146.64789)); + path.lineTo(QPointF(200, 146.64789)); + return path; +} + +static QPainterPath samplePath3() +{ + QPainterPath path; + path.moveTo(QPointF(231.42858, 80.933609)); + path.lineTo(QPointF(200, 80.933609)); + path.lineTo(QPointF(200, 96.64788999999999)); + path.lineTo(QPointF(231.42858, 96.64788999999999)); + path.lineTo(QPointF(231.42858, 80.933609)); + return path; +} + +static QPainterPath samplePath4() +{ + QPainterPath path; + path.moveTo(QPointF(288.571434, 80.933609)); + path.lineTo(QPointF(431.42858, 80.933609)); + path.lineTo(QPointF(431.42858, 96.64788999999999)); + path.lineTo(QPointF(288.571434, 96.64788999999999)); + path.lineTo(QPointF(288.571434, 80.933609)); + return path; +} + +static QPainterPath samplePath5() +{ + QPainterPath path; + path.moveTo(QPointF(588.571434, 80.933609)); + path.lineTo(QPointF(682.85715, 80.933609)); + path.lineTo(QPointF(682.85715, 96.64788999999999)); + path.lineTo(QPointF(588.571434, 96.64788999999999)); + path.lineTo(QPointF(588.571434, 80.933609)); + return path; +} + +static QPainterPath samplePath6() +{ + QPainterPath path; + path.moveTo(QPointF(588.571434, 80.933609)); + path.lineTo(QPointF(200, 80.933609)); + path.lineTo(QPointF(200, 446.6479)); + path.lineTo(QPointF(682.85715, 446.6479)); + path.lineTo(QPointF(682.85715, 96.64788999999999)); + path.lineTo(QPointF(731.42858, 96.64788999999999)); + path.lineTo(QPointF(731.42858, 56.64788999999999)); + path.lineTo(QPointF(588.571434, 56.64788999999999)); + path.lineTo(QPointF(588.571434, 80.933609)); + return path; +} + +static QPainterPath samplePath7() +{ + QPainterPath path; + path.moveTo(QPointF(682.85715, 206.64789)); + path.lineTo(QPointF(682.85715, 246.64789)); + path.lineTo(QPointF(588.571434, 246.64789)); + path.lineTo(QPointF(588.571434, 206.64789)); + path.lineTo(QPointF(682.85715, 206.64789)); + return path; +} + +static QPainterPath samplePath8() +{ + QPainterPath path; + path.moveTo(QPointF(682.85715, 406.64789)); + path.lineTo(QPointF(682.85715, 446.64789)); + path.lineTo(QPointF(588.571434, 446.64789)); + path.lineTo(QPointF(588.571434, 406.64789)); + path.lineTo(QPointF(682.85715, 406.64789)); + return path; +} + +static QPainterPath samplePath9() +{ + QPainterPath path; + path.moveTo(QPointF(682.85715, 426.64789)); + path.lineTo(QPointF(682.85715, 446.6479)); + path.lineTo(QPointF(568.571434, 446.6479)); + path.lineTo(QPointF(568.571434, 426.64789)); + path.lineTo(QPointF(682.85715, 426.64789)); + return path; +} + +static QPainterPath samplePath10() +{ + QPainterPath path; + path.moveTo(QPointF(511.42858, 446.6479)); + path.lineTo(QPointF(368.571434, 446.6479)); + path.lineTo(QPointF(368.571434, 426.64789)); + path.lineTo(QPointF(511.42858, 426.64789)); + path.lineTo(QPointF(511.42858, 446.6479)); + return path; +} + +static QPainterPath samplePath13() +{ + QPainterPath path; + path.moveTo(QPointF(160, 200)); + path.lineTo(QPointF(100, 200)); + path.lineTo(QPointF(100, 130)); + path.lineTo(QPointF(160, 130)); + path.lineTo(QPointF(160, 200)); + return path; +} + +static QPainterPath samplePath14() +{ + QPainterPath path; + + path.moveTo(160, 80); + path.lineTo(160, 180); + path.lineTo(100, 180); + path.lineTo(100, 80); + path.lineTo(160, 80); + path.moveTo(160, 80); + path.lineTo(160, 100); + path.lineTo(120, 100); + path.lineTo(120, 80); + + return path; +} + +void tst_QPathClipper::clip_data() +{ + //create the testtable instance and define the elements + QTest::addColumn<QPainterPath>("subject"); + QTest::addColumn<QPainterPath>("clip"); + QTest::addColumn<QPathClipper::Operation>("op"); + QTest::addColumn<QPainterPath>("result"); + + //next we fill it with data + QTest::newRow( "simple1" ) << Paths::frame3() + << Paths::frame4() + << QPathClipper::BoolAnd + << samplePath1(); + + QTest::newRow( "simple2" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(0, -100) + << QPathClipper::BoolAnd + << samplePath2(); + + QTest::newRow( "simple3" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(0, -150) + << QPathClipper::BoolAnd + << samplePath3(); + + QTest::newRow( "simple4" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(200, -150) + << QPathClipper::BoolAnd + << samplePath4(); + + QTest::newRow( "simple5" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(500, -150) + << QPathClipper::BoolAnd + << samplePath5(); + + QTest::newRow( "simple6" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(500, -150) + << QPathClipper::BoolOr + << samplePath6(); + + QTest::newRow( "simple7" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(500, 0) + << QPathClipper::BoolAnd + << samplePath7(); + + QTest::newRow( "simple8" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(500, 200) + << QPathClipper::BoolAnd + << samplePath8(); + + QTest::newRow( "simple9" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(480, 220) + << QPathClipper::BoolAnd + << samplePath9(); + + QTest::newRow( "simple10" ) << Paths::frame3() + << Paths::frame4() * QTransform().translate(280, 220) + << QPathClipper::BoolAnd + << samplePath10(); + + QTest::newRow( "simple_move_to1" ) << Paths::rect4() + << Paths::rect2() * QTransform().translate(-20, 50) + << QPathClipper::BoolAnd + << samplePath13(); + + QTest::newRow( "simple_move_to2" ) << Paths::rect4() + << Paths::rect2() * QTransform().translate(-20, 0) + << QPathClipper::BoolAnd + << samplePath14(); +} + +// sanity check to make sure comparePaths declared above works +void tst_QPathClipper::testComparePaths() +{ + QPainterPath a; + QPainterPath b; + + a.addRect(0, 0, 10, 10); + b.addRect(0, 0, 10.00001, 10.00001); + + QVERIFY(!QPathCompare::comparePaths(a, b)); + + b = QPainterPath(); + b.addRect(0, 0, 10.00000000001, 10.00000000001); + + QVERIFY(QPathCompare::comparePaths(a, b)); + + b = QPainterPath(); + b.moveTo(10, 0); + b.lineTo(0, 0); + b.lineTo(0, 10); + b.lineTo(10, 10); + + QVERIFY(QPathCompare::comparePaths(a, b)); + b.lineTo(10, 0); + QVERIFY(QPathCompare::comparePaths(a, b)); + + b = QPainterPath(); + b.moveTo(10, 0); + b.lineTo(0, 10); + b.lineTo(0, 0); + b.lineTo(10, 10); + + QVERIFY(!QPathCompare::comparePaths(a, b)); +} + +void tst_QPathClipper::clip() +{ + if (sizeof(double) != sizeof(qreal)) { + QSKIP("This test only works for qreal=double, otherwise ends in rounding errors", SkipAll); + } + QFETCH( QPainterPath, subject ); + QFETCH( QPainterPath, clip ); + QFETCH( QPathClipper::Operation, op ); + QFETCH( QPainterPath, result); + QPathClipper clipper(subject, clip); + QPainterPath x = clipper.clip(op); + + QVERIFY(QPathCompare::comparePaths(x, result)); +} + +static inline QPointF randomPointInRect(const QRectF &rect) +{ + qreal rx = qrand() / (RAND_MAX + 1.); + qreal ry = qrand() / (RAND_MAX + 1.); + + return QPointF(rect.left() + rx * rect.width(), + rect.top() + ry * rect.height()); +} + +void tst_QPathClipper::clipTest(int subjectIndex, int clipIndex, QPathClipper::Operation op) +{ + const QPainterPath &subject = paths[subjectIndex]; + const QPainterPath &clip = paths[clipIndex]; + const int count = 40; + + QRectF bounds = subject.boundingRect().united(clip.boundingRect()); + + const qreal adjustX = bounds.width() * 0.01; + const qreal adjustY = bounds.height() * 0.01; + + // make sure we test some points that are outside both paths as well + bounds = bounds.adjusted(-adjustX, -adjustY, adjustX, adjustY); + + const int dim = 256; + const qreal scale = qMin(dim / bounds.width(), dim / bounds.height()); + + QPathClipper clipper(subject, clip); + QPainterPath result = clipper.clip(op); + + // using the image here is a bit of a hacky way to make sure we don't test points that + // are too close to the path edges to avoid test fails that are due to numerical errors + QImage img(dim, dim, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + QPainter p(&img); + p.setRenderHint(QPainter::Antialiasing); + p.scale(scale, scale); + p.translate(-bounds.topLeft()); + p.setPen(Qt::black); + p.drawPath(subject); + p.setPen(Qt::red); + p.drawPath(clip); + p.end(); + + for (int i = 0; i < count; ++i) { + QPointF point; + QRgb pixel; + do { + point = randomPointInRect(bounds); + const QPointF imagePoint = (point - bounds.topLeft()) * scale; + + pixel = img.pixel(int(imagePoint.x()), int(imagePoint.y())); + } while (qAlpha(pixel) > 0); + + const bool inSubject = subject.contains(point); + const bool inClip = clip.contains(point); + + const bool inResult = result.contains(point); + + bool expected = false; + switch (op) { + case QPathClipper::BoolAnd: + expected = inSubject && inClip; + break; + case QPathClipper::BoolOr: + expected = inSubject || inClip; + break; + case QPathClipper::BoolSub: + expected = inSubject && !inClip; + break; + default: + break; + } + + if (expected != inResult) { + char str[256]; + const char *opStr = + op == QPathClipper::BoolAnd ? "and" : + op == QPathClipper::BoolOr ? "or" : "sub"; + sprintf(str, "Expected: %d, actual: %d, subject: %d, clip: %d, op: %s\n", + int(expected), int(inResult), subjectIndex, clipIndex, opStr); + + // debugging +#if 0 + QRect rect = bounds.toAlignedRect(); + + QPainter p(&img); + p.scale(scale, scale); + p.translate(-bounds.topLeft()); + + p.setPen(Qt::NoPen); + p.setBrush(QColor(0x700ff00)); + p.drawPath(result); + + p.setPen(Qt::blue); + p.drawPoint(point); + p.end(); + + char str2[256]; + sprintf(str2, "fail-%d-%d-%s.png", subjectIndex, clipIndex, opStr); + img.save(str2); +#endif + QFAIL(str); + } + } +} + +void tst_QPathClipper::clip2() +{ + if (sizeof(double) != sizeof(qreal)) + QSKIP("This test only works for qreal=double, otherwise ends in rounding errors", SkipAll); + + int operation = 0; + + for (int i = 0; i < paths.size(); ++i) { + for (int j = 0; j <= i; ++j) { + QPathClipper::Operation op = QPathClipper::Operation((operation++) % 3); + clipTest(i, j, op); + } + } +} + +void tst_QPathClipper::clip3() +{ + int operation = 0; + + // this subset should work correctly for qreal = float + for (int i = 0; i < 20; ++i) { + for (int j = 0; j <= i; ++j) { + QPathClipper::Operation op = QPathClipper::Operation((operation++) % 3); + clipTest(i, j, op); + } + } +} + +void tst_QPathClipper::testIntersections() +{ + QPainterPath path1; + QPainterPath path2; + + path1.addRect(0, 0, 100, 100); + path2.addRect(20, 20, 20, 20); + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + QVERIFY(path1.contains(path2)); + QVERIFY(!path2.contains(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addEllipse(0, 0, 100, 100); + path2.addEllipse(200, 200, 100, 100); + QVERIFY(!path1.intersects(path2)); + QVERIFY(!path2.intersects(path1)); + QVERIFY(!path1.contains(path2)); + QVERIFY(!path2.contains(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addEllipse(0, 0, 100, 100); + path2.addEllipse(50, 50, 100, 100); + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + QVERIFY(!path1.contains(path2)); + QVERIFY(!path2.contains(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(100, 100, 100, 100); + path2.addRect(50, 100, 100, 20); + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + QVERIFY(!path1.contains(path2)); + QVERIFY(!path2.contains(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(100, 100, 100, 100); + path2.addRect(110, 201, 100, 20); + QVERIFY(!path1.intersects(path2)); + QVERIFY(!path2.intersects(path1)); + QVERIFY(!path1.contains(path2)); + QVERIFY(!path2.contains(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(0, 0, 100, 100); + path2.addRect(20, 20, 20, 20); + path2.addRect(25, 25, 5, 5); + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + QVERIFY(path1.contains(path2)); + QVERIFY(!path2.contains(path1)); +} + +void tst_QPathClipper::testIntersections2() +{ + QPainterPath path1; + QPainterPath path2; + + path1 = QPainterPath(); + path2 = QPainterPath(); + + path1.moveTo(-8,-8); + path1.lineTo(107,-8); + path1.lineTo(107,107); + path1.lineTo(-8,107); + + path2.moveTo(0,0); + path2.lineTo(100,0); + path2.lineTo(100,100); + path2.lineTo(0,100); + path2.lineTo(0,0); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + QVERIFY(path1.contains(path2)); + QVERIFY(!path2.contains(path1)); + + path1.closeSubpath(); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + QVERIFY(path1.contains(path2)); + QVERIFY(!path2.contains(path1)); +} + +void tst_QPathClipper::testIntersections3() +{ + QPainterPath path1 = Paths::node(); + QPainterPath path2 = Paths::interRect(); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); +} + +void tst_QPathClipper::testIntersections4() +{ + QPainterPath path1; + QPainterPath path2; + + path1.moveTo(-5, 0); + path1.lineTo(5, 0); + + path2.moveTo(0, -5); + path2.lineTo(0, 5); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); +} + +void tst_QPathClipper::testIntersections5() +{ + QPainterPath path1; + QPainterPath path2; + + path1.addRect(0, 0, 4, 4); + path1.addRect(2, 1, 1, 1); + path2.addRect(0.5, 2, 1, 1); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); +} + +void tst_QPathClipper::testIntersections6() +{ + QPainterPath path1; + QPainterPath path2; + + path1.moveTo(QPointF(-115.567, -98.3254)); + path1.lineTo(QPointF(-45.9007, -98.3254)); + path1.lineTo(QPointF(-45.9007, -28.6588)); + path1.lineTo(QPointF(-115.567, -28.6588)); + + path2.moveTo(QPointF(-110, -110)); + path2.lineTo(QPointF(110, -110)); + path2.lineTo(QPointF(110, 110)); + path2.lineTo(QPointF(-110, 110)); + path2.lineTo(QPointF(-110, -110)); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); +} + + +void tst_QPathClipper::testIntersections7() +{ + QPainterPath path1; + QPainterPath path2; + + path1.addRect(0, 0, 10, 10); + path2.addRect(5, 0, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(0, 0, 10, 10); + path2.addRect(0, 5, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(0, 0, 10, 10); + path2.addRect(0, 0, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + /// + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(1, 1, 10, 10); + path2.addRect(5, 1, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(1, 1, 10, 10); + path2.addRect(1, 5, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(1, 1, 10, 10); + path2.addRect(1, 1, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(1, 1, 10, 10); + path2.addRect(5, 5, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(1, 1, 10, 10); + path2.addRect(9, 9, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(1, 1, 10, 10); + path2.addRect(10, 10, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(1, 1, 9, 9); + path2.addRect(11, 11, 10, 10); + + QVERIFY(!path1.intersects(path2)); + QVERIFY(!path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(1, 1, 10, 10); + path2.addRect(12, 12, 10, 10); + + QVERIFY(!path1.intersects(path2)); + QVERIFY(!path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(11, 11, 10, 10); + path2.addRect(12, 12, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath(); + path2 = QPainterPath(); + path1.addRect(11, 11, 10, 10); + path2.addRect(10, 10, 10, 10); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); +} + + +void tst_QPathClipper::testIntersections8() +{ + QPainterPath path1 = Paths::node() * QTransform().translate(100, 50); + QPainterPath path2 = Paths::node() * QTransform().translate(150, 50);; + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = Paths::node(); + path2 = Paths::node(); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = Paths::node(); + path2 = Paths::node() * QTransform().translate(0, 30); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = Paths::node(); + path2 = Paths::node() * QTransform().translate(30, 0); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = Paths::node(); + path2 = Paths::node() * QTransform().translate(30, 30); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = Paths::node(); + path2 = Paths::node() * QTransform().translate(1, 1); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); +} + + +void tst_QPathClipper::testIntersections9() +{ + QPainterPath path1; + QPainterPath path2; + + path1.addRect(QRectF(-1,143, 146, 106)); + path2.addRect(QRectF(-9,145, 150, 100)); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath();; + path2 = QPainterPath(); + + path1.addRect(QRectF(-1,191, 136, 106)); + path2.addRect(QRectF(-19,194, 150, 100)); + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); + + path1 = QPainterPath();; + path2 = QPainterPath(); + + path1.moveTo(-1 , 143); + path1.lineTo(148 , 143); + path1.lineTo(148 , 250); + path1.lineTo(-1 , 250); + + path2.moveTo(-5 , 146); + path2.lineTo(145 , 146); + path2.lineTo(145 , 246); + path2.lineTo(-5 , 246); + path2.lineTo(-5 , 146); + + QVERIFY(path1.intersects(path2)); + QVERIFY(path2.intersects(path1)); +} + +QPainterPath pathFromRect(qreal x, qreal y, qreal w, qreal h) +{ + QPainterPath path; + path.addRect(QRectF(x, y, w, h)); + return path; +} + +QPainterPath pathFromLine(qreal x1, qreal y1, qreal x2, qreal y2) +{ + QPainterPath path; + path.moveTo(x1, y1); + path.lineTo(x2, y2); + return path; +} + +static int loopLength(const QWingedEdge &list, QWingedEdge::TraversalStatus status) +{ + int start = status.edge; + + int length = 0; + do { + ++length; + status = list.next(status); + } while (status.edge != start); + + return length; +} + +void tst_QPathClipper::testWingedEdge() +{ + { + QWingedEdge list; + int e1 = list.addEdge(QPointF(0, 0), QPointF(10, 0)); + int e2 = list.addEdge(QPointF(0, 0), QPointF(0, 10)); + int e3 = list.addEdge(QPointF(0, 0), QPointF(-10, 0)); + int e4 = list.addEdge(QPointF(0, 0), QPointF(0, -10)); + + QCOMPARE(list.edgeCount(), 4); + QCOMPARE(list.vertexCount(), 5); + + QWingedEdge::TraversalStatus status = { e1, QPathEdge::RightTraversal, QPathEdge::Forward }; + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e1); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e4); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e4); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e3); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e3); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e2); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e2); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e1); + } + { + QWingedEdge list; + int e1 = list.addEdge(QPointF(5, 0), QPointF(5, 10)); + int e2 = list.addEdge(QPointF(5, 0), QPointF(10, 5)); + int e3 = list.addEdge(QPointF(10, 5), QPointF(5, 10)); + int e4 = list.addEdge(QPointF(5, 0), QPointF(0, 5)); + int e5 = list.addEdge(QPointF(0, 5), QPointF(5, 10)); + + QCOMPARE(list.edgeCount(), 5); + QCOMPARE(list.vertexCount(), 4); + + QWingedEdge::TraversalStatus status = { e1, QPathEdge::RightTraversal, QPathEdge::Forward }; + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e5); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e4); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e1); + + QCOMPARE(loopLength(list, status), 3); + + status.flip(); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(loopLength(list, status), 3); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e2); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e3); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e1); + + status = list.next(status); + status.flip(); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e2); + QCOMPARE(loopLength(list, status), 4); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e4); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Forward); + QCOMPARE(status.traversal, QPathEdge::RightTraversal); + QCOMPARE(status.edge, e5); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e3); + + status = list.next(status); + QCOMPARE(status.direction, QPathEdge::Backward); + QCOMPARE(status.traversal, QPathEdge::LeftTraversal); + QCOMPARE(status.edge, e2); + } + { + QPainterPath path = pathFromRect(0, 0, 20, 20); + QWingedEdge list(path, QPainterPath()); + + QCOMPARE(list.edgeCount(), 4); + QCOMPARE(list.vertexCount(), 4); + + QWingedEdge::TraversalStatus status = { 0, QPathEdge::RightTraversal, QPathEdge::Forward }; + + QPathEdge *edge = list.edge(status.edge); + QCOMPARE(QPointF(*list.vertex(edge->first)), QPointF(0, 0)); + QCOMPARE(QPointF(*list.vertex(edge->second)), QPointF(20, 0)); + + status = list.next(status); + QCOMPARE(status.edge, 1); + + status = list.next(status); + QCOMPARE(status.edge, 2); + + status = list.next(status); + QCOMPARE(status.edge, 3); + + status = list.next(status); + QCOMPARE(status.edge, 0); + + status.flipDirection(); + status = list.next(status); + QCOMPARE(status.edge, 3); + + status = list.next(status); + QCOMPARE(status.edge, 2); + + status = list.next(status); + QCOMPARE(status.edge, 1); + + status = list.next(status); + QCOMPARE(status.edge, 0); + + QWingedEdge list2(path, pathFromRect(10, 5, 20, 10)); + + QCOMPARE(list2.edgeCount(), 12); + QCOMPARE(list2.vertexCount(), 10); + + status.flipDirection(); + QCOMPARE(loopLength(list2, status), 8); + + status = list2.next(status); + edge = list2.edge(status.edge); + QCOMPARE(QPointF(*list2.vertex(edge->first)), QPointF(20, 0)); + QCOMPARE(QPointF(*list2.vertex(edge->second)), QPointF(20, 5)); + + status = list2.next(status); + status.flipTraversal(); + + edge = list2.edge(status.edge); + QCOMPARE(QPointF(*list2.vertex(edge->first)), QPointF(10, 5)); + QCOMPARE(QPointF(*list2.vertex(edge->second)), QPointF(20, 5)); + + QCOMPARE(loopLength(list2, status), 4); + + status.flipDirection(); + status = list2.next(status); + status.flipTraversal(); + + edge = list2.edge(status.edge); + QCOMPARE(QPointF(*list2.vertex(edge->first)), QPointF(20, 5)); + QCOMPARE(QPointF(*list2.vertex(edge->second)), QPointF(20, 15)); + + QCOMPARE(loopLength(list2, status), 4); + status = list2.next(status); + status = list2.next(status); + + edge = list2.edge(status.edge); + QCOMPARE(QPointF(*list2.vertex(edge->first)), QPointF(30, 5)); + QCOMPARE(QPointF(*list2.vertex(edge->second)), QPointF(30, 15)); + } +} + +void tst_QPathClipper::zeroDerivativeCurves() +{ + // zero derivative at end + { + QPainterPath a; + a.cubicTo(100, 0, 100, 100, 100, 100); + a.lineTo(100, 200); + a.lineTo(0, 200); + + QPainterPath b; + b.moveTo(50, 100); + b.lineTo(150, 100); + b.lineTo(150, 150); + b.lineTo(50, 150); + + QPainterPath c = a.united(b); + QVERIFY(c.contains(QPointF(25, 125))); + QVERIFY(c.contains(QPointF(75, 125))); + QVERIFY(c.contains(QPointF(125, 125))); + } + + // zero derivative at start + { + QPainterPath a; + a.cubicTo(100, 0, 100, 100, 100, 100); + a.lineTo(100, 200); + a.lineTo(0, 200); + + QPainterPath b; + b.moveTo(50, 100); + b.lineTo(150, 100); + b.lineTo(150, 150); + b.lineTo(50, 150); + + QPainterPath c = a.united(b); + QVERIFY(c.contains(QPointF(25, 125))); + QVERIFY(c.contains(QPointF(75, 125))); + QVERIFY(c.contains(QPointF(125, 125))); + } +} + +static bool strictContains(const QPainterPath &a, const QPainterPath &b) +{ + return b.subtracted(a) == QPainterPath(); +} + +Q_DECLARE_METATYPE(QPolygonF) + +void tst_QPathClipper::task204301_data() +{ + QTest::addColumn<QPolygonF>("points"); + + { + QPointF a(51.09013255685567855835, 31.30814891308546066284); + QPointF b(98.39898971840739250183, 11.02079074829816818237); + QPointF c(91.23911846894770860672, 45.86981737054884433746); + QPointF d(66.58616356085985898972, 63.10526528395712375641); + QPointF e(82.08219456479714892794, 94.90238165489137145414); + QPointF f(16.09013040543221251255, 105.66263409332729850121); + QPointF g(10.62811442650854587555, 65.09154842235147953033); + QPointF h(5.16609844751656055450, 24.52046275138854980469); + QPolygonF v; + v << a << b << c << d << e << f << g << h; + QTest::newRow("failed_on_linux") << v; + } + + { + QPointF a(50.014648437500000, 24.392089843750000); + QPointF b(92.836303710937500, 5.548706054687500); + QPointF c(92.145690917968750, 54.390258789062500); + QPointF d(65.402221679687500, 74.345092773437500); + QPointF e(80.789794921787347, 124.298095703129690); + QPointF f(34.961242675812954, 87.621459960852135); + QPointF g(18.305969238281250, 57.426757812500000); + QPointF h(1.650695800781250, 27.232055664062500); + QPolygonF v; + v << a << b << c << d << e << f << g << h; + QTest::newRow("failed_on_windows") << v; + } +} + +void tst_QPathClipper::task204301() +{ + QFETCH(QPolygonF, points); + + QPointF a = points[0]; + QPointF b = points[1]; + QPointF c = points[2]; + QPointF d = points[3]; + QPointF e = points[4]; + QPointF f = points[5]; + QPointF g = points[6]; + QPointF h = points[7]; + + QPainterPath subA; + subA.addPolygon(QPolygonF() << a << b << c << d); + subA.closeSubpath(); + + QPainterPath subB; + subB.addPolygon(QPolygonF() << f << e << d << g); + subB.closeSubpath(); + + QPainterPath subC; + subC.addPolygon(QPolygonF() << h << a << d << g); + subC.closeSubpath(); + + QPainterPath path; + path.addPath(subA); + path.addPath(subB); + path.addPath(subC); + + QPainterPath simplified = path.simplified(); + + QVERIFY(strictContains(simplified, subA)); + QVERIFY(strictContains(simplified, subB)); + QVERIFY(strictContains(simplified, subC)); +} + +void tst_QPathClipper::task209056() +{ + QPainterPath p1; + p1.moveTo( QPointF(188.506, 287.793) ); + p1.lineTo( QPointF(288.506, 287.793) ); + p1.lineTo( QPointF(288.506, 387.793) ); + p1.lineTo( QPointF(188.506, 387.793) ); + p1.lineTo( QPointF(188.506, 287.793) ); + + QPainterPath p2; + p2.moveTo( QPointF(419.447, 164.383) ); + p2.cubicTo( QPointF(419.447, 69.5486), QPointF(419.447, 259.218),QPointF(419.447, 164.383) ); + + p2.cubicTo( QPointF(48.9378, 259.218), QPointF(131.879, 336.097),QPointF(234.192, 336.097) ); + p2.cubicTo( QPointF(336.506, 336.097), QPointF(419.447, 259.218),QPointF(419.447, 164.383) ); + + QPainterPath p3 = p1.intersected(p2); + + QVERIFY(p3 != QPainterPath()); +} + +void tst_QPathClipper::task251909() +{ + QPainterPath p1; + p1.moveTo(0, -10); + p1.lineTo(10, -10); + p1.lineTo(10, 0); + p1.lineTo(0, 0); + + QPainterPath p2; + p2.moveTo(0, 8e-14); + p2.lineTo(10, -8e-14); + p2.lineTo(10, 10); + p2.lineTo(0, 10); + + QPainterPath result = p1.united(p2); + + QVERIFY(result.elementCount() <= 5); +} + +void tst_QPathClipper::qtbug3778() +{ + if (sizeof(double) != sizeof(qreal)) { + QSKIP("This test only works for qreal=double, otherwise ends in rounding errors", SkipAll); + } + QPainterPath path1; + path1.moveTo(200, 3.22409e-5); + // e-5 and higher leads to a bug + // Using 3.22409e-4 starts to work correctly + path1.lineTo(0, 0); + path1.lineTo(1.07025e-13, 1450); + path1.lineTo(750, 950); + path1.lineTo(950, 750); + path1.lineTo(200, 3.22409e-13); + + QPainterPath path2; + path2.moveTo(0, 0); + path2.lineTo(200, 800); + path2.lineTo(600, 1500); + path2.lineTo(1500, 1400); + path2.lineTo(1900, 1200); + path2.lineTo(2000, 1000); + path2.lineTo(1400, 0); + path2.lineTo(0, 0); + + QPainterPath p12 = path1.intersected(path2); + + QVERIFY(p12.contains(QPointF(100, 100))); +} + +QTEST_APPLESS_MAIN(tst_QPathClipper) + + +#include "tst_qpathclipper.moc" diff --git a/tests/auto/gui/painting/qpen/.gitignore b/tests/auto/gui/painting/qpen/.gitignore new file mode 100644 index 0000000000..a9187367dc --- /dev/null +++ b/tests/auto/gui/painting/qpen/.gitignore @@ -0,0 +1 @@ +tst_qpen diff --git a/tests/auto/gui/painting/qpen/qpen.pro b/tests/auto/gui/painting/qpen/qpen.pro new file mode 100644 index 0000000000..53bd5e2b6e --- /dev/null +++ b/tests/auto/gui/painting/qpen/qpen.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qpen.cpp + + + diff --git a/tests/auto/gui/painting/qpen/tst_qpen.cpp b/tests/auto/gui/painting/qpen/tst_qpen.cpp new file mode 100644 index 0000000000..64d725bc50 --- /dev/null +++ b/tests/auto/gui/painting/qpen/tst_qpen.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include "qpen.h" +#include "qbrush.h" + +#include <qdebug.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPen : public QObject +{ + Q_OBJECT + +public: + tst_QPen(); + +private slots: + void getSetCheck(); + void swap(); + void operator_eq_eq(); + void operator_eq_eq_data(); + + void stream(); + void stream_data(); + + void constructor(); + void constructor_data(); +}; + +// Testing get/set functions +void tst_QPen::getSetCheck() +{ + QPen obj1; + // qreal QPen::miterLimit() + // void QPen::setMiterLimit(qreal) + obj1.setMiterLimit(0.0); + QCOMPARE(0.0, obj1.miterLimit()); + obj1.setMiterLimit(qreal(1.1)); + QCOMPARE(qreal(1.1), obj1.miterLimit()); + + // qreal QPen::widthF() + // void QPen::setWidthF(qreal) + obj1.setWidthF(0.0); + QCOMPARE(0.0, obj1.widthF()); + obj1.setWidthF(qreal(1.1)); + QCOMPARE(qreal(1.1), obj1.widthF()); + + // int QPen::width() + // void QPen::setWidth(int) + for (int i = 0; i < 100; ++i) { + obj1.setWidth(i); + QCOMPARE(i, obj1.width()); + } +} + +void tst_QPen::swap() +{ + QPen p1(Qt::black), p2(Qt::white); + p1.swap(p2); + QCOMPARE(p1.color(), QColor(Qt::white)); + QCOMPARE(p2.color(), QColor(Qt::black)); +} + +Q_DECLARE_METATYPE(QPen) +Q_DECLARE_METATYPE(QBrush) + +tst_QPen::tst_QPen() + +{ +} + +void tst_QPen::operator_eq_eq_data() +{ + QTest::addColumn<QPen>("pen1"); + QTest::addColumn<QPen>("pen2"); + QTest::addColumn<bool>("isEqual"); + + QTest::newRow("differentColor") << QPen(Qt::red) + << QPen(Qt::blue) + << bool(FALSE); + QTest::newRow("differentWidth") << QPen(Qt::red, 2) + << QPen(Qt::red, 3) + << bool(FALSE); + QTest::newRow("differentPenStyle") << QPen(Qt::red, 2, Qt::DashLine) + << QPen(Qt::red, 2, Qt::DotLine) + << bool(FALSE); + QTest::newRow("differentCapStyle") << QPen(Qt::red, 2, Qt::DashLine, Qt::RoundCap, Qt::BevelJoin) + << QPen(Qt::red, 2, Qt::DashLine, Qt::SquareCap, Qt::BevelJoin) + << bool(FALSE); + QTest::newRow("differentJoinStyle") << QPen(Qt::red, 2, Qt::DashLine, Qt::RoundCap, Qt::BevelJoin) + << QPen(Qt::red, 2, Qt::DashLine, Qt::RoundCap, Qt::MiterJoin) + << bool(FALSE); + QTest::newRow("same") << QPen(Qt::red, 2, Qt::DashLine, Qt::RoundCap, Qt::BevelJoin) + << QPen(Qt::red, 2, Qt::DashLine, Qt::RoundCap, Qt::BevelJoin) + << bool(TRUE); + +} + +void tst_QPen::operator_eq_eq() +{ + QFETCH(QPen, pen1); + QFETCH(QPen, pen2); + QFETCH(bool, isEqual); + QCOMPARE(pen1 == pen2, isEqual); +} + + +void tst_QPen::constructor_data() +{ + QTest::addColumn<QPen>("pen"); + QTest::addColumn<QBrush>("brush"); + QTest::addColumn<double>("width"); + QTest::addColumn<int>("style"); + QTest::addColumn<int>("capStyle"); + QTest::addColumn<int>("joinStyle"); + + QTest::newRow("solid_black") << QPen() << QBrush(Qt::black) << 0. << (int)Qt::SolidLine + << (int) Qt::SquareCap << (int)Qt::BevelJoin; + QTest::newRow("solid_red") << QPen(Qt::red) << QBrush(Qt::red) << 0. << (int)Qt::SolidLine + << (int)Qt::SquareCap << (int)Qt::BevelJoin; + QTest::newRow("full") << QPen(QBrush(QLinearGradient(0, 0, 100, 100)), 10, + Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin) + << QBrush(QLinearGradient(0, 0, 100, 100)) << 10. << (int)Qt::SolidLine + << (int)Qt::RoundCap << (int)Qt::MiterJoin; + +} + + +void tst_QPen::constructor() +{ + QFETCH(QPen, pen); + QFETCH(QBrush, brush); + QFETCH(double, width); + QFETCH(int, style); + QFETCH(int, capStyle); + QFETCH(int, joinStyle); + + QCOMPARE(pen.style(), Qt::PenStyle(style)); + QCOMPARE(pen.capStyle(), Qt::PenCapStyle(capStyle)); + QCOMPARE(pen.joinStyle(), Qt::PenJoinStyle(joinStyle)); + QCOMPARE(pen.widthF(), width); + QCOMPARE(pen.brush(), brush); +} + + +void tst_QPen::stream_data() +{ + QTest::addColumn<QPen>("pen"); + + QTest::newRow("solid_black") << QPen(); + QTest::newRow("solid_red") << QPen(Qt::red); + QTest::newRow("full") << QPen(QBrush(QLinearGradient(0, 0, 100, 100)), 10, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin); +} + + +void tst_QPen::stream() +{ + QFETCH(QPen, pen); + + QByteArray bytes; + + { + QDataStream stream(&bytes, QIODevice::WriteOnly); + stream << pen; + } + + QPen cmp; + { + QDataStream stream(&bytes, QIODevice::ReadOnly); + stream >> cmp; + } + + QCOMPARE(pen.widthF(), cmp.widthF()); + QCOMPARE(pen.style(), cmp.style()); + QCOMPARE(pen.capStyle(), cmp.capStyle()); + QCOMPARE(pen.joinStyle(), cmp.joinStyle()); + QCOMPARE(pen.brush(), cmp.brush()); + + QCOMPARE(pen, cmp); +} + +QTEST_APPLESS_MAIN(tst_QPen) +#include "tst_qpen.moc" diff --git a/tests/auto/gui/painting/qpolygon/.gitignore b/tests/auto/gui/painting/qpolygon/.gitignore new file mode 100644 index 0000000000..7c9d48c848 --- /dev/null +++ b/tests/auto/gui/painting/qpolygon/.gitignore @@ -0,0 +1 @@ +tst_qpointarray diff --git a/tests/auto/gui/painting/qpolygon/qpolygon.pro b/tests/auto/gui/painting/qpolygon/qpolygon.pro new file mode 100644 index 0000000000..186b704d17 --- /dev/null +++ b/tests/auto/gui/painting/qpolygon/qpolygon.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qpolygon.cpp + +unix:!mac:!symbian:LIBS+=-lm + + diff --git a/tests/auto/gui/painting/qpolygon/tst_qpolygon.cpp b/tests/auto/gui/painting/qpolygon/tst_qpolygon.cpp new file mode 100644 index 0000000000..f47073a048 --- /dev/null +++ b/tests/auto/gui/painting/qpolygon/tst_qpolygon.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qpolygon.h> +#include <qpainterpath.h> +#include <math.h> + +#include <qpainter.h> +#include <qdialog.h> + + + +//TESTED_CLASS= +//TESTED_FILES=gui/painting/qpolygon.h gui/painting/qpolygon.cpp + +class tst_QPolygon : public QObject +{ + Q_OBJECT + +public: + tst_QPolygon(); + +private slots: + void makeEllipse(); + void swap(); +}; + +tst_QPolygon::tst_QPolygon() +{ +} + +void tst_QPolygon::makeEllipse() +{ + // create an ellipse with R1 = R2 = R, i.e. a circle + QPolygon pa; + const int R = 50; // radius + QPainterPath path; + path.addEllipse(0, 0, 2*R, 2*R); + pa = path.toSubpathPolygons().at(0).toPolygon(); + + int i; + // make sure that all points are R+-1 away from the center + bool err = FALSE; + for (i = 1; i < pa.size(); i++) { + QPoint p = pa.at( i ); + double r = sqrt( pow( double(p.x() - R), 2.0 ) + pow( double(p.y() - R), 2.0 ) ); + // ### too strict ? at least from visual inspection it looks + // quite odd around the main axes. 2.0 passes easily. + err |= ( qAbs( r - double(R) ) > 2.0 ); + } + QVERIFY( !err ); +} + +void tst_QPolygon::swap() +{ + QPolygon p1(QVector<QPoint>() << QPoint(0,0) << QPoint(10,10) << QPoint(-10,10)); + QPolygon p2(QVector<QPoint>() << QPoint(0,0) << QPoint( 0,10) << QPoint( 10,10) << QPoint(10,0)); + p1.swap(p2); + QCOMPARE(p1.count(),4); + QCOMPARE(p2.count(),3); +} + +QTEST_APPLESS_MAIN(tst_QPolygon) +#include "tst_qpolygon.moc" diff --git a/tests/auto/gui/painting/qprinter/.gitignore b/tests/auto/gui/painting/qprinter/.gitignore new file mode 100644 index 0000000000..85de0e9675 --- /dev/null +++ b/tests/auto/gui/painting/qprinter/.gitignore @@ -0,0 +1,4 @@ +tqpluginloader/st_qprinter +silly +test.pdf + diff --git a/tests/auto/gui/painting/qprinter/qprinter.pro b/tests/auto/gui/painting/qprinter/qprinter.pro new file mode 100644 index 0000000000..da02bdd7d6 --- /dev/null +++ b/tests/auto/gui/painting/qprinter/qprinter.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += printsupport widgets +SOURCES += tst_qprinter.cpp + +mac*:CONFIG+=insignificant_test +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/gui/painting/qprinter/tst_qprinter.cpp b/tests/auto/gui/painting/qprinter/tst_qprinter.cpp new file mode 100644 index 0000000000..a6b6895981 --- /dev/null +++ b/tests/auto/gui/painting/qprinter/tst_qprinter.cpp @@ -0,0 +1,1044 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <qprinter.h> +#include <qpagesetupdialog.h> +#include <qpainter.h> +#include <qprintdialog.h> +#include <qprinterinfo.h> +#include <qvariant.h> +#include <qpainter.h> +#include <qprintengine.h> + +#include <math.h> + +#ifdef Q_WS_WIN +#include <windows.h> +#endif + +Q_DECLARE_METATYPE(QRect) + +QT_FORWARD_DECLARE_CLASS(QPrinter) + +//TESTED_CLASS= +//TESTED_FILES= + +#ifndef QT_NO_PRINTER + +class tst_QPrinter : public QObject +{ + Q_OBJECT + +public: + tst_QPrinter(); + virtual ~tst_QPrinter(); + + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); +private slots: + void getSetCheck(); +// Add your testfunctions and testdata create functions here + void testPageSize(); + void testPageRectAndPaperRect(); + void testPageRectAndPaperRect_data(); + void testSetOptions(); + void testMargins_data(); + void testMargins(); + void testNonExistentPrinter(); + void testPageSetupDialog(); + void testMulitpleSets_data(); + void testMulitpleSets(); + void testPageMargins_data(); + void testPageMargins(); + void changingOutputFormat(); + void outputFormatFromSuffix(); + void setGetPaperSize(); + void valuePreservation(); + void errorReporting(); + void testCustomPageSizes(); + void printDialogCompleter(); + + void testCopyCount(); + void testCurrentPage(); + + void taskQTBUG4497_reusePrinterOnDifferentFiles(); + void testPdfTitle(); + +private: +}; + +// Testing get/set functions +void tst_QPrinter::getSetCheck() +{ + QPrinter obj1; + // OutputFormat QPrinter::outputFormat() + // void QPrinter::setOutputFormat(OutputFormat) + obj1.setOutputFormat(QPrinter::OutputFormat(QPrinter::PdfFormat)); + QCOMPARE(QPrinter::OutputFormat(QPrinter::PdfFormat), obj1.outputFormat()); + + // bool QPrinter::collateCopies() + // void QPrinter::setCollateCopies(bool) + obj1.setCollateCopies(false); + QCOMPARE(false, obj1.collateCopies()); + obj1.setCollateCopies(true); + QCOMPARE(true, obj1.collateCopies()); + + obj1.setColorMode(QPrinter::GrayScale); + QCOMPARE(obj1.colorMode(), QPrinter::GrayScale); + obj1.setColorMode(QPrinter::Color); + QCOMPARE(obj1.colorMode(), QPrinter::Color); + + obj1.setCreator(QString::fromLatin1("RandomQtUser")); + QCOMPARE(obj1.creator(), QString::fromLatin1("RandomQtUser")); + + obj1.setDocName(QString::fromLatin1("RandomQtDocument")); + QCOMPARE(obj1.docName(), QString::fromLatin1("RandomQtDocument")); + + obj1.setDoubleSidedPrinting(true); + QCOMPARE(obj1.doubleSidedPrinting(), true); + obj1.setDoubleSidedPrinting(false); + QCOMPARE(obj1.doubleSidedPrinting(), false); + + obj1.setFromTo(1, 4); + QCOMPARE(obj1.fromPage(), 1); + QCOMPARE(obj1.toPage(), 4); + + obj1.setFullPage(true); + QCOMPARE(obj1.fullPage(), true); + obj1.setFullPage(false); + QCOMPARE(obj1.fullPage(), false); + + obj1.setOrientation(QPrinter::Landscape); + QCOMPARE(obj1.orientation(), QPrinter::Landscape); + obj1.setOrientation(QPrinter::Portrait); + QCOMPARE(obj1.orientation(), QPrinter::Portrait); + + obj1.setOutputFileName(QString::fromLatin1("RandomQtName")); + QCOMPARE(obj1.outputFileName(), QString::fromLatin1("RandomQtName")); + + obj1.setPageOrder(QPrinter::FirstPageFirst); + QCOMPARE(obj1.pageOrder(), QPrinter::FirstPageFirst); + obj1.setPageOrder(QPrinter::LastPageFirst); + QCOMPARE(obj1.pageOrder(), QPrinter::LastPageFirst); + + obj1.setPaperSource(QPrinter::Cassette); + QCOMPARE(obj1.paperSource(), QPrinter::Cassette); + obj1.setPaperSource(QPrinter::Middle); + QCOMPARE(obj1.paperSource(), QPrinter::Middle); + +#ifdef Q_OS_UNIX + obj1.setPrintProgram(QString::fromLatin1("/bin/true")); + QCOMPARE(obj1.printProgram(), QString::fromLatin1("/bin/true")); + + obj1.setPrinterSelectionOption(QString::fromLatin1("--option")); + QCOMPARE(obj1.printerSelectionOption(), QString::fromLatin1("--option")); +#endif + + obj1.setPrinterName(QString::fromLatin1("myPrinter")); + QCOMPARE(obj1.printerName(), QString::fromLatin1("myPrinter")); + + // bool QPrinter::fontEmbeddingEnabled() + // void QPrinter::setFontEmbeddingEnabled(bool) + obj1.setFontEmbeddingEnabled(false); + QCOMPARE(false, obj1.fontEmbeddingEnabled()); + obj1.setFontEmbeddingEnabled(true); + QCOMPARE(true, obj1.fontEmbeddingEnabled()); + + // PageSize QPrinter::pageSize() + // void QPrinter::setPageSize(PageSize) + obj1.setPageSize(QPrinter::PageSize(QPrinter::A4)); + QCOMPARE(QPrinter::PageSize(QPrinter::A4), obj1.pageSize()); + obj1.setPageSize(QPrinter::PageSize(QPrinter::Letter)); + QCOMPARE(QPrinter::PageSize(QPrinter::Letter), obj1.pageSize()); + obj1.setPageSize(QPrinter::PageSize(QPrinter::Legal)); + QCOMPARE(QPrinter::PageSize(QPrinter::Legal), obj1.pageSize()); + + // PrintRange QPrinter::printRange() + // void QPrinter::setPrintRange(PrintRange) + obj1.setPrintRange(QPrinter::PrintRange(QPrinter::AllPages)); + QCOMPARE(QPrinter::PrintRange(QPrinter::AllPages), obj1.printRange()); + obj1.setPrintRange(QPrinter::PrintRange(QPrinter::Selection)); + QCOMPARE(QPrinter::PrintRange(QPrinter::Selection), obj1.printRange()); + obj1.setPrintRange(QPrinter::PrintRange(QPrinter::PageRange)); + QCOMPARE(QPrinter::PrintRange(QPrinter::PageRange), obj1.printRange()); +} + +tst_QPrinter::tst_QPrinter() +{ +} + +tst_QPrinter::~tst_QPrinter() +{ +} + +// initTestCase will be executed once before the first testfunction is executed. +void tst_QPrinter::initTestCase() +{ +// TODO: Add testcase generic initialization code here. +// suggestion: +// testWidget = new QPrinter(0,"testWidget"); +// testWidget->setFixedSize(200, 200); +// qApp->setMainWidget(testWidget); +// testWidget->show(); +} + +// cleanupTestCase will be executed once after the last testfunction is executed. +void tst_QPrinter::cleanupTestCase() +{ +// TODO: Add testcase generic cleanup code here. +// suggestion: +// testWidget->hide(); +// qApp->setMainWidget(0); +// delete testWidget; +} + +// init() will be executed immediately before each testfunction is run. +void tst_QPrinter::init() +{ +// TODO: Add testfunction specific initialization code here. +} + +// cleanup() will be executed immediately after each testfunction is run. +void tst_QPrinter::cleanup() +{ +// TODO: Add testfunction specific cleanup code here. +} + +#define MYCOMPARE(a, b) QCOMPARE(QVariant((int)a), QVariant((int)b)) + +void tst_QPrinter::testPageSetupDialog() +{ + // Make sure this doesn't crash at least + { + QPrinter printer; + QPageSetupDialog dialog(&printer); + } +} + +void tst_QPrinter::testPageSize() +{ +#if defined (Q_WS_WIN) + QPrinter prn; + + prn.setPageSize(QPrinter::Letter); + MYCOMPARE(prn.pageSize(), QPrinter::Letter); + MYCOMPARE(prn.winPageSize(), DMPAPER_LETTER); + + prn.setPageSize(QPrinter::A4); + MYCOMPARE(prn.pageSize(), QPrinter::A4); + MYCOMPARE(prn.winPageSize(), DMPAPER_A4); + + prn.setWinPageSize(DMPAPER_LETTER); + MYCOMPARE(prn.winPageSize(), DMPAPER_LETTER); + MYCOMPARE(prn.pageSize(), QPrinter::Letter); + + prn.setWinPageSize(DMPAPER_A4); + MYCOMPARE(prn.winPageSize(), DMPAPER_A4); + MYCOMPARE(prn.pageSize(), QPrinter::A4); +#else + QSKIP("QPrinter::winPageSize() does not exist for nonwindows platforms", SkipAll); +#endif +} + +void tst_QPrinter::testPageRectAndPaperRect_data() +{ + QTest::addColumn<int>("orientation"); + QTest::addColumn<bool>("withPainter"); + QTest::addColumn<int>("resolution"); + QTest::addColumn<bool>("doPaperRect"); + + // paperrect + QTest::newRow("paperRect0") << int(QPrinter::Portrait) << true << 300 << true; + QTest::newRow("paperRect1") << int(QPrinter::Portrait) << false << 300 << true; + QTest::newRow("paperRect2") << int(QPrinter::Landscape) << true << 300 << true; + QTest::newRow("paperRect3") << int(QPrinter::Landscape) << false << 300 << true; + QTest::newRow("paperRect4") << int(QPrinter::Portrait) << true << 600 << true; + QTest::newRow("paperRect5") << int(QPrinter::Portrait) << false << 600 << true; + QTest::newRow("paperRect6") << int(QPrinter::Landscape) << true << 600 << true; + QTest::newRow("paperRect7") << int(QPrinter::Landscape) << false << 600 << true; + QTest::newRow("paperRect8") << int(QPrinter::Portrait) << true << 1200 << true; + QTest::newRow("paperRect9") << int(QPrinter::Portrait) << false << 1200 << true; + QTest::newRow("paperRect10") << int(QPrinter::Landscape) << true << 1200 << true; + QTest::newRow("paperRect11") << int(QPrinter::Landscape) << false << 1200 << true; + + // page rect + QTest::newRow("pageRect0") << int(QPrinter::Portrait) << true << 300 << false; + QTest::newRow("pageRect1") << int(QPrinter::Portrait) << false << 300 << false; + QTest::newRow("pageRect2") << int(QPrinter::Landscape) << true << 300 << false; + QTest::newRow("pageRect3") << int(QPrinter::Landscape) << false << 300 << false; + QTest::newRow("pageRect4") << int(QPrinter::Portrait) << true << 600 << false; + QTest::newRow("pageRect5") << int(QPrinter::Portrait) << false << 600 << false; + QTest::newRow("pageRect6") << int(QPrinter::Landscape) << true << 600 << false; + QTest::newRow("pageRect7") << int(QPrinter::Landscape) << false << 600 << false; + QTest::newRow("pageRect8") << int(QPrinter::Portrait) << true << 1200 << false; + QTest::newRow("pageRect9") << int(QPrinter::Portrait) << false << 1200 << false; + QTest::newRow("pageRect10") << int(QPrinter::Landscape) << true << 1200 << false; + QTest::newRow("pageRect11") << int(QPrinter::Landscape) << false << 1200 << false; +} + +void tst_QPrinter::testPageRectAndPaperRect() +{ + QFETCH(bool, withPainter); + QFETCH(int, orientation); + QFETCH(int, resolution); + QFETCH(bool, doPaperRect); + + QPainter *painter = 0; + QPrinter printer(QPrinter::HighResolution); + printer.setOrientation(QPrinter::Orientation(orientation)); + printer.setOutputFileName("silly"); + + QRect pageRect = doPaperRect ? printer.paperRect() : printer.pageRect(); + float inchesX = float(pageRect.width()) / float(printer.resolution()); + float inchesY = float(pageRect.height()) / float(printer.resolution()); + printer.setResolution(resolution); + if (withPainter) + painter = new QPainter(&printer); + + QRect otherRect = doPaperRect ? printer.paperRect() : printer.pageRect(); + float otherInchesX = float(otherRect.width()) / float(printer.resolution()); + float otherInchesY = float(otherRect.height()) / float(printer.resolution()); + if (painter != 0) + delete painter; + + QVERIFY(qAbs(otherInchesX - inchesX) < 0.01); + QVERIFY(qAbs(otherInchesY - inchesY) < 0.01); + + QVERIFY(printer.orientation() == QPrinter::Portrait || pageRect.width() > pageRect.height()); + QVERIFY(printer.orientation() != QPrinter::Portrait || pageRect.width() < pageRect.height()); +} + +void tst_QPrinter::testSetOptions() +{ + QPrinter prn; + QPrintDialog dlg(&prn); + + // Verify default values + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), TRUE); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), FALSE); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), TRUE); + + dlg.setEnabledOptions(QAbstractPrintDialog::PrintPageRange); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), FALSE); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), FALSE); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), TRUE); + + dlg.setEnabledOptions((QAbstractPrintDialog::PrintDialogOptions(QAbstractPrintDialog::PrintSelection + | QAbstractPrintDialog::PrintPageRange))); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), FALSE); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), TRUE); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), TRUE); + + dlg.setEnabledOptions(QAbstractPrintDialog::PrintSelection); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), FALSE); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), TRUE); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), FALSE); +} + +void tst_QPrinter::testMargins_data() +{ + QTest::addColumn<int>("orientation"); + QTest::addColumn<bool>("fullpage"); + QTest::addColumn<int>("pagesize"); + QTest::addColumn<int>("width"); + QTest::addColumn<int>("height"); + QTest::addColumn<bool>("withPainter"); + + QTest::newRow("data0") << int(QPrinter::Portrait) << true << int(QPrinter::A4) << 210 << 297 << false; + QTest::newRow("data1") << int(QPrinter::Landscape) << true << int(QPrinter::A4) << 297 << 210 << false; + QTest::newRow("data2") << int(QPrinter::Landscape) << false << int(QPrinter::A4) << 297 << 210 << false; + QTest::newRow("data3") << int(QPrinter::Portrait) << false << int(QPrinter::A4) << 210 << 297 << false; + QTest::newRow("data4") << int(QPrinter::Portrait) << true << int(QPrinter::A4) << 210 << 297 << true; + QTest::newRow("data5") << int(QPrinter::Landscape) << true << int(QPrinter::A4) << 297 << 210 << true; + QTest::newRow("data6") << int(QPrinter::Landscape) << false << int(QPrinter::A4) << 297 << 210 << true; + QTest::newRow("data7") << int(QPrinter::Portrait) << false << int(QPrinter::A4) << 210 << 297 << true; +} + +void tst_QPrinter::testMargins() +{ + QFETCH(bool, withPainter); + QFETCH(int, orientation); + QFETCH(int, pagesize); + QFETCH(int, width); + QFETCH(int, height); + QFETCH(bool, fullpage); + Q_UNUSED(width); + Q_UNUSED(height); + QPrinter printer; + QPainter *painter = 0; + printer.setOutputFileName("silly"); + printer.setOrientation((QPrinter::Orientation)orientation); + printer.setFullPage(fullpage); + printer.setPageSize((QPrinter::PageSize)pagesize); + if (withPainter) + painter = new QPainter(&printer); + + if (painter) + delete painter; +} + +void tst_QPrinter::testNonExistentPrinter() +{ +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_QPA) || defined(Q_OS_MAC) + QSKIP("QPrinter::testNonExistentPrinter() is not relevant for this platform", SkipAll); +#else + QPrinter printer; + QPainter painter; + + // Make sure it doesn't crash on setting or getting properties + printer.setPrinterName("some non existing printer"); + printer.setPageSize(QPrinter::A4); + printer.setOrientation(QPrinter::Portrait); + printer.setFullPage(true); + printer.pageSize(); + printer.orientation(); + printer.fullPage(); + printer.setCopyCount(1); + printer.printerName(); + + // nor metrics + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmWidth), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmHeight), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmWidthMM), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmHeightMM), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmNumColors), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDepth), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDpiX), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDpiY), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmPhysicalDpiX), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmPhysicalDpiY), 0); + + QVERIFY(!painter.begin(&printer)); +#endif +} + + +void tst_QPrinter::testMulitpleSets_data() +{ + QTest::addColumn<int>("resolution"); + QTest::addColumn<int>("pageSize"); + QTest::addColumn<int>("widthMMAfter"); + QTest::addColumn<int>("heightMMAfter"); + + + QTest::newRow("lowRes") << int(QPrinter::ScreenResolution) << int(QPrinter::A4) << 210 << 297; + QTest::newRow("lowResLetter") << int(QPrinter::ScreenResolution) << int(QPrinter::Letter) << 216 << 279; + QTest::newRow("lowResA5") << int(QPrinter::ScreenResolution) << int(QPrinter::A5) << 148 << 210; + QTest::newRow("midRes") << int(QPrinter::PrinterResolution) << int(QPrinter::A4) << 210 << 297; + QTest::newRow("midResLetter") << int(QPrinter::PrinterResolution) << int(QPrinter::Letter) << 216 << 279; + QTest::newRow("midResA5") << int(QPrinter::PrinterResolution) << int(QPrinter::A5) << 148 << 210; + QTest::newRow("highRes") << int(QPrinter::HighResolution) << int(QPrinter::A4) << 210 << 297; + QTest::newRow("highResLetter") << int(QPrinter::HighResolution) << int(QPrinter::Letter) << 216 << 279; + QTest::newRow("highResA5") << int(QPrinter::HighResolution) << int(QPrinter::A5) << 148 << 210; +} + +static void computePageValue(const QPrinter &printer, int &retWidth, int &retHeight) +{ + const double Inch2MM = 25.4; + + double width = double(printer.paperRect().width()) / printer.logicalDpiX() * Inch2MM; + double height = double(printer.paperRect().height()) / printer.logicalDpiY() * Inch2MM; + retWidth = qRound(width); + retHeight = qRound(height); +} + +void tst_QPrinter::testMulitpleSets() +{ + // A very simple test, but Mac needs to have its format "validated" if the format is changed + // This takes care of that. + QFETCH(int, resolution); + QFETCH(int, pageSize); + QFETCH(int, widthMMAfter); + QFETCH(int, heightMMAfter); + + + QPrinter::PrinterMode mode = QPrinter::PrinterMode(resolution); + QPrinter::PageSize printerPageSize = QPrinter::PageSize(pageSize); + QPrinter printer(mode); + printer.setFullPage(true); + + int paperWidth, paperHeight; + //const int Tolerance = 2; + + computePageValue(printer, paperWidth, paperHeight); + printer.setPageSize(printerPageSize); + + if (printer.pageSize() != printerPageSize) { + QSKIP("Current page size is not supported on this printer", SkipSingle); + return; + } + + QCOMPARE(printer.widthMM(), widthMMAfter); + QCOMPARE(printer.heightMM(), heightMMAfter); + + computePageValue(printer, paperWidth, paperHeight); + + QVERIFY(qAbs(paperWidth - widthMMAfter) <= 2); + QVERIFY(qAbs(paperHeight - heightMMAfter) <= 2); + + // Set it again and see if it still works. + printer.setPageSize(printerPageSize); + QCOMPARE(printer.widthMM(), widthMMAfter); + QCOMPARE(printer.heightMM(), heightMMAfter); + + printer.setOrientation(QPrinter::Landscape); + computePageValue(printer, paperWidth, paperHeight); + QVERIFY(qAbs(paperWidth - heightMMAfter) <= 2); + QVERIFY(qAbs(paperHeight - widthMMAfter) <= 2); +} + +void tst_QPrinter::changingOutputFormat() +{ +#if QT_VERSION < 0x050000 + QPrinter p; + p.setOutputFormat(QPrinter::PostScriptFormat); + p.setPageSize(QPrinter::A8); + p.setOutputFormat(QPrinter::PdfFormat); + QCOMPARE(p.pageSize(), QPrinter::A8); +#endif +} + +void tst_QPrinter::outputFormatFromSuffix() +{ + if (QPrinterInfo::availablePrinters().size() == 0) + QSKIP("No printers available.", SkipAll); + QPrinter p; + QVERIFY(p.outputFormat() == QPrinter::NativeFormat); + p.setOutputFileName("test.pdf"); + QVERIFY(p.outputFormat() == QPrinter::PdfFormat); + p.setOutputFileName(QString()); + QVERIFY(p.outputFormat() == QPrinter::NativeFormat); +} + +void tst_QPrinter::setGetPaperSize() +{ + QPrinter p; + p.setOutputFormat(QPrinter::PdfFormat); + QSizeF size(500, 10); + p.setPaperSize(size, QPrinter::Millimeter); + QCOMPARE(p.paperSize(QPrinter::Millimeter), size); + QSizeF ptSize = p.paperSize(QPrinter::Point); + //qDebug() << ptSize; + QVERIFY(qAbs(ptSize.width() - size.width() * (72/25.4)) < 1E-4); + QVERIFY(qAbs(ptSize.height() - size.height() * (72/25.4)) < 1E-4); +} + +void tst_QPrinter::testPageMargins_data() +{ + QTest::addColumn<qreal>("left"); + QTest::addColumn<qreal>("top"); + QTest::addColumn<qreal>("right"); + QTest::addColumn<qreal>("bottom"); + QTest::addColumn<int>("unit"); + + QTest::newRow("data0") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast<int>(QPrinter::Millimeter); + QTest::newRow("data1") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast<int>(QPrinter::Point); + QTest::newRow("data2") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast<int>(QPrinter::Inch); + QTest::newRow("data3") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast<int>(QPrinter::Pica); + QTest::newRow("data4") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast<int>(QPrinter::Didot); + QTest::newRow("data5") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast<int>(QPrinter::Cicero); +} + +void tst_QPrinter::testPageMargins() +{ + QPrinter obj1; + + qreal toMillimeters[6]; + toMillimeters[QPrinter::Millimeter] = 1; + toMillimeters[QPrinter::Point] = 0.352777778; + toMillimeters[QPrinter::Inch] = 25.4; + toMillimeters[QPrinter::Pica] = 4.23333333; + toMillimeters[QPrinter::Didot] = 0.376; + toMillimeters[QPrinter::Cicero] = 4.51166667; + + QFETCH(qreal, left); + QFETCH(qreal, top); + QFETCH(qreal, right); + QFETCH(qreal, bottom); + QFETCH(int, unit); + + qreal nLeft, nTop, nRight, nBottom; + + obj1.setPageMargins(left, top, right, bottom, static_cast<QPrinter::Unit>(unit)); + + qreal tolerance = 0.05; + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Millimeter); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Millimeter]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Millimeter]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Millimeter]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Millimeter]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Point); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Point]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Point]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Point]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Point]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Inch); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Inch]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Inch]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Inch]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Inch]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Pica); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Pica]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Pica]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Pica]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Pica]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Didot); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Didot]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Didot]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Didot]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Didot]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Cicero); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Cicero]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Cicero]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Cicero]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Cicero]) < tolerance); +} + +void tst_QPrinter::valuePreservation() +{ + QPrinter::OutputFormat oldFormat = QPrinter::PdfFormat; + QPrinter::OutputFormat newFormat = QPrinter::NativeFormat; // TODO: Correct? + + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + bool status = printer.collateCopies(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.collateCopies(), status); + + printer.setCollateCopies(!status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.collateCopies(), !status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.collateCopies(), !status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::ColorMode status = printer.colorMode(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.colorMode(), status); + + printer.setColorMode(QPrinter::ColorMode(!status)); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.colorMode(), QPrinter::ColorMode(!status)); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.colorMode(), QPrinter::ColorMode(!status)); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.creator(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.creator(), status); + + status = QString::fromLatin1("Mr. Test"); + printer.setCreator(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.creator(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.creator(), status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.docName(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.docName(), status); + + status = QString::fromLatin1("Test document"); + printer.setDocName(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.docName(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.docName(), status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + bool status = printer.doubleSidedPrinting(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.doubleSidedPrinting(), status); + + printer.setDoubleSidedPrinting(!status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.doubleSidedPrinting(), !status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.doubleSidedPrinting(), !status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + bool status = printer.fontEmbeddingEnabled(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.fontEmbeddingEnabled(), status); + + printer.setFontEmbeddingEnabled(!status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.fontEmbeddingEnabled(), !status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.fontEmbeddingEnabled(), !status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + bool status = printer.fullPage(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.fullPage(), status); + + printer.setFullPage(!status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.fullPage(), !status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.fullPage(), !status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::Orientation status = printer.orientation(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.orientation(), status); + + printer.setOrientation(QPrinter::Orientation(!status)); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.orientation(), QPrinter::Orientation(!status)); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.orientation(), QPrinter::Orientation(!status)); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.outputFileName(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.outputFileName(), status); + + status = QString::fromLatin1("Test file"); + printer.setOutputFileName(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.outputFileName(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.outputFileName(), status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::PageOrder status = printer.pageOrder(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.pageOrder(), status); + + printer.setPageOrder(QPrinter::PageOrder(!status)); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.pageOrder(), QPrinter::PageOrder(!status)); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.pageOrder(), QPrinter::PageOrder(!status)); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::PageSize status = printer.pageSize(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.pageSize(), status); + + printer.setPageSize(QPrinter::B5); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.pageSize(), QPrinter::B5); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.pageSize(), QPrinter::B5); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::PaperSource status = printer.paperSource(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.paperSource(), status); + + printer.setPaperSource(QPrinter::Manual); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.paperSource(), QPrinter::Manual); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.paperSource(), QPrinter::Manual); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.printProgram(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printProgram(), status); + + status = QString::fromLatin1("/usr/local/bin/lpr"); + printer.setPrintProgram(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.printProgram(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printProgram(), status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::PrintRange status = printer.printRange(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printRange(), status); + + printer.setPrintRange(QPrinter::PrintRange(!status)); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.printRange(), QPrinter::PrintRange(!status)); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printRange(), QPrinter::PrintRange(!status)); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.printerName(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printerName(), status); + + status = QString::fromLatin1("SuperDuperPrinter"); + printer.setPrinterName(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.printerName(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printerName(), status); + } +#ifndef Q_OS_WIN + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.printerSelectionOption(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printerSelectionOption(), status); + + status = QString::fromLatin1("Optional option"); + printer.setPrinterSelectionOption(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.printerSelectionOption(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printerSelectionOption(), status); + } +#endif + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + int status = printer.resolution(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.resolution(), status); + + printer.setResolution(status-150); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.resolution(), status-150); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.resolution(), status-150); + } +} + +void tst_QPrinter::errorReporting() +{ + QPrinter p; + p.setOutputFormat(QPrinter::PdfFormat); + QCOMPARE(p.isValid(), true); + QPainter painter; +#ifndef Q_WS_WIN + // not sure how to choose a never-writable file on windows. But its QFile behavior anyway, so lets rely on it failing elsewhere + p.setOutputFileName("/foobar/nonwritable.pdf"); + QCOMPARE(painter.begin(&p), false); // it should check the output file is writable +#endif + p.setOutputFileName("test.pdf"); + QCOMPARE(painter.begin(&p), true); // it should check the output + QCOMPARE(p.isValid(), true); + painter.end(); +} + +void tst_QPrinter::testCustomPageSizes() +{ + QPrinter p; + + QSizeF customSize(8.5, 11.0); + p.setPaperSize(customSize, QPrinter::Inch); + + QSizeF paperSize = p.paperSize(QPrinter::Inch); + QCOMPARE(paperSize, customSize); + + QPrinter p2(QPrinter::HighResolution); + p2.setPaperSize(customSize, QPrinter::Inch); + paperSize = p.paperSize(QPrinter::Inch); + QCOMPARE(paperSize, customSize); +} + +void tst_QPrinter::printDialogCompleter() +{ +#if defined(QT_NO_COMPLETER) || defined(QT_NO_FILEDIALOG) + QSKIP("QT_NO_COMPLETER || QT_NO_FILEDIALOG: Auto-complete turned off in QPrinterDialog.", QTest::SkipAll); +#else + QPrintDialog dialog; + dialog.printer()->setOutputFileName("file.pdf"); + dialog.setEnabledOptions(QAbstractPrintDialog::PrintToFile); + dialog.show(); + + QTest::qWait(100); + + QTest::keyClick(&dialog, Qt::Key_Tab); + QTest::keyClick(&dialog, 'P'); + // The test passes if it doesn't crash. +#endif +} + +void tst_QPrinter::testCopyCount() +{ + QPrinter p; + p.setCopyCount(15); + QCOMPARE(p.copyCount(), 15); +} + +static void printPage(QPainter *painter) +{ + painter->setPen(QPen(Qt::black, 4)); + painter->drawRect(50, 60, 70, 80); +} + +void tst_QPrinter::taskQTBUG4497_reusePrinterOnDifferentFiles() +{ + QPrinter printer; + { + + printer.setOutputFileName("out1.ps"); + QPainter painter(&printer); + printPage(&painter); + + } + { + + printer.setOutputFileName("out2.ps"); + QPainter painter(&printer); + printPage(&painter); + + } + QFile file1("out1.ps"); + QVERIFY(file1.open(QIODevice::ReadOnly)); + + QFile file2("out2.ps"); + QVERIFY(file2.open(QIODevice::ReadOnly)); + + QCOMPARE(file1.readAll(), file2.readAll()); +} + +void tst_QPrinter::testCurrentPage() +{ + QPrinter printer; + printer.setFromTo(1, 10); + + // Test set print range + printer.setPrintRange(QPrinter::CurrentPage); + QCOMPARE(printer.printRange(), QPrinter::CurrentPage); + QCOMPARE(printer.fromPage(), 1); + QCOMPARE(printer.toPage(), 10); + + QPrintDialog dialog(&printer); + + // Test default Current Page option to off + QCOMPARE(dialog.isOptionEnabled(QPrintDialog::PrintCurrentPage), false); + + // Test enable Current Page option + dialog.setOption(QPrintDialog::PrintCurrentPage); + QCOMPARE(dialog.isOptionEnabled(QPrintDialog::PrintCurrentPage), true); + +} + +void tst_QPrinter::testPdfTitle() +{ + // Check the document name is represented correctly in produced pdf + { + QPainter painter; + QPrinter printer; + // This string is just the UTF-8 encoding of the string: \()f ø hiragana o + const char title[]={0x5c, 0x28, 0x29, 0x66, 0xc3, 0xb8, 0xe3, 0x81, 0x8a, 0x00}; + printer.setOutputFileName("file.pdf"); + printer.setDocName(QString::fromUtf8(title)); + painter.begin(&printer); + painter.end(); + } + QFile file("file.pdf"); + QVERIFY(file.open(QIODevice::ReadOnly)); + // The we expect the title to appear in the PDF as: + // ASCII('\title (') UTF16(\\\(\)f ø hiragana o) ASCII(')'). + // which has the following binary representation + const char expected[] = { + 0x2f, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x28, 0xfe, + 0xff, 0x00, 0x5c, 0x5c, 0x00, 0x5c, 0x28, 0x00, 0x5c, + 0x29, 0x00, 0x66, 0x00, 0xf8, 0x30, 0x4a, 0x29}; + QVERIFY(file.readAll().contains(QByteArray(expected, 26))); +} + +QTEST_MAIN(tst_QPrinter) +#include "tst_qprinter.moc" + +#else //QT_NO_PRINTER + +QTEST_NOOP_MAIN + +#endif //QT_NO_PRINTER diff --git a/tests/auto/gui/painting/qprinterinfo/.gitignore b/tests/auto/gui/painting/qprinterinfo/.gitignore new file mode 100644 index 0000000000..fcef7c1997 --- /dev/null +++ b/tests/auto/gui/painting/qprinterinfo/.gitignore @@ -0,0 +1 @@ +tst_qprinterinfo diff --git a/tests/auto/gui/painting/qprinterinfo/qprinterinfo.pro b/tests/auto/gui/painting/qprinterinfo/qprinterinfo.pro new file mode 100644 index 0000000000..8c96e2dcb7 --- /dev/null +++ b/tests/auto/gui/painting/qprinterinfo/qprinterinfo.pro @@ -0,0 +1,8 @@ +load(qttest_p4) +SOURCES += tst_qprinterinfo.cpp + +QT += printsupport network + +DEFINES += QT_USE_USING_NAMESPACE + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/gui/painting/qprinterinfo/tst_qprinterinfo.cpp b/tests/auto/gui/painting/qprinterinfo/tst_qprinterinfo.cpp new file mode 100644 index 0000000000..7e5da4a6f8 --- /dev/null +++ b/tests/auto/gui/painting/qprinterinfo/tst_qprinterinfo.cpp @@ -0,0 +1,401 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtGlobal> +#include <QtAlgorithms> +#include <QtNetwork/QHostInfo> + +#ifndef QT_NO_PRINTER +#include <qprinterinfo.h> + +#ifdef Q_OS_UNIX +# include <unistd.h> +# include <sys/types.h> +# include <sys/wait.h> +#endif + +Q_DECLARE_METATYPE(QRect) + + +#if defined(Q_OS_WIN32) +# define ACCEPTABLE_WINDOWS +#endif + + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QPrinterInfo : public QObject +{ + Q_OBJECT + +public: + //tst_QPrinterInfo(); + //virtual ~tst_QPrinterInfo(); + + +public slots: + //void initTestCase(); + //void cleanupTestCase(); + //void init(); + //void cleanup(); +private slots: + void testForDefaultPrinter(); + void testForPrinters(); + void testForPaperSizes(); + void testConstructors(); + void testAssignment(); + +private: + void macFixNameFormat(QString *printerName); + QString getDefaultPrinterFromSystem(); + QStringList getPrintersFromSystem(); + + QString getOutputFromCommand(const QStringList& command); +}; + +void tst_QPrinterInfo::macFixNameFormat(QString *printerName) +{ +// Modify the format of the printer name to match Qt, lpstat returns +// foo___domain_no, Qt returns foo @ domain.no +#ifdef Q_WS_MAC + printerName->replace(QLatin1String("___"), QLatin1String(" @ ")); + printerName->replace(QLatin1String("_"), QLatin1String(".")); +#else + Q_UNUSED(printerName); +#endif +} + +QString tst_QPrinterInfo::getDefaultPrinterFromSystem() +{ + QStringList command; + command << "lpstat" << "-d"; + QString output = getOutputFromCommand(command); + + QRegExp noDefaultReg("[^:]*no .*default"); + int pos = noDefaultReg.indexIn(output); + if (pos >= 0) { + return QString(); + } + + QRegExp defaultReg("default.*: *([a-zA-Z0-9_]+)"); + defaultReg.indexIn(output); + QString printer = defaultReg.cap(1); + macFixNameFormat(&printer); + return printer; +} + +QStringList tst_QPrinterInfo::getPrintersFromSystem() +{ + QStringList ans; + + QStringList command; + command << "lpstat" << "-p"; + QString output = getOutputFromCommand(command); + QStringList list = output.split(QChar::fromLatin1('\n')); + + QRegExp reg("^[Pp]rinter ([.a-zA-Z0-9-_@]+)"); + for (int c = 0; c < list.size(); ++c) { + if (reg.indexIn(list[c]) >= 0) { + QString printer = reg.cap(1); + macFixNameFormat(&printer); + ans << printer; + } + } + + return ans; +} + +// This function does roughly the same as the `command substitution` in +// the shell. +QString tst_QPrinterInfo::getOutputFromCommand(const QStringList& command) +{ +// The command execution does nothing on non-unix systems. +#ifdef Q_OS_UNIX + int pid; + int status = 0; + int pipePtr[2]; + + // Create a pipe that is shared between parent and child process. + if (pipe(pipePtr) < 0) { + return QString(); + } + pid = fork(); + if (pid < 0) { + close(pipePtr[0]); + close(pipePtr[1]); + return QString(); + } else if (pid == 0) { + // In child. + // Close the reading end. + close(pipePtr[0]); + // Redirect stdout to the pipe. + if (dup2(pipePtr[1], 1) < 0) { + exit(1); + } + + char** argv = new char*[command.size()+1]; + for (int c = 0; c < command.size(); ++c) { + argv[c] = new char[command[c].size()+1]; + strcpy(argv[c], command[c].toLatin1().data()); + } + argv[command.size()] = NULL; + execvp(argv[0], argv); + // Shouldn't get here, but it's possible if command is not found. + close(pipePtr[1]); + close(1); + for (int c = 0; c < command.size(); ++c) { + delete [] argv[c]; + } + delete [] argv; + exit(1); + } else { + // In parent. + // Close the writing end. + close(pipePtr[1]); + + QFile pipeRead; + if (!pipeRead.open(pipePtr[0], QIODevice::ReadOnly)) { + close(pipePtr[0]); + return QString(); + } + QByteArray array; + array = pipeRead.readAll(); + pipeRead.close(); + close(pipePtr[0]); + wait(&status); + return QString(array); + } +#else + return QString(); +#endif // Q_OS_UNIX +} + +void tst_QPrinterInfo::testForDefaultPrinter() +{ +#if defined(Q_OS_UNIX) || defined(ACCEPTABLE_WINDOWS) +# ifdef ACCEPTABLE_WINDOWS + if (QHostInfo::localHostName() == "fantomet" || QHostInfo::localHostName() == "bobo") { + QWARN("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows and may fail"); + } else { + QSKIP("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows", SkipAll); + } + QString defSysPrinter; + if (QHostInfo::localHostName() == "fantomet") { + defSysPrinter = "Yacc (Lexmark Optra T610 PS3)"; + } else if (QHostInfo::localHostName() == "bobo") { + defSysPrinter = "press"; + } +# else + QString defSysPrinter = getDefaultPrinterFromSystem(); +# endif + if (defSysPrinter == "") return; + + QList<QPrinterInfo> list = QPrinterInfo::availablePrinters(); + bool found = false; + for (int c = 0; c < list.size(); ++c) { + if (list[c].isDefault()) { + QVERIFY(list.at(c).printerName() == defSysPrinter); + QVERIFY(!list.at(c).isNull()); + found = true; + } else { + QVERIFY(list.at(c).printerName() != defSysPrinter); + QVERIFY(!list.at(c).isNull()); + } + } + + if (!found && defSysPrinter != "") QFAIL("No default printer reported by Qt, although there is one"); +#else + QSKIP("Test doesn't work on non-Unix", SkipAll); +#endif // defined(Q_OS_UNIX) || defined(ACCEPTABLE_WINDOWS) +} + +void tst_QPrinterInfo::testForPrinters() +{ +#if defined(Q_OS_UNIX) || defined(ACCEPTABLE_WINDOWS) +# ifdef ACCEPTABLE_WINDOWS + if (QHostInfo::localHostName() == "fantomet" || QHostInfo::localHostName() == "bobo") { + QWARN("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows and may fail"); + } else { + QSKIP("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows", SkipAll); + } + QStringList sysPrinters; + if (QHostInfo::localHostName() == "fantomet") { + sysPrinters + << "Press" + << "Canon PS-IPU Color Laser Copier v52.3" + << "EPSON EPL-N4000 PS3" + << "Kroksleiven" + << "Lexmark Optra Color 1200 PS" + << "Yacc (Lexmark Optra T610 PCL)" + << "Yacc (Lexmark Optra T610 PS3)" + ; + } else if (QHostInfo::localHostName() == "bobo") { + sysPrinters + << "press" + << "finnmarka" + << "nordmarka" + ; + } +# else + QStringList sysPrinters = getPrintersFromSystem(); +# endif + QList<QPrinterInfo> printers = QPrinterInfo::availablePrinters(); + + QCOMPARE(printers.size(), sysPrinters.size()); + + QHash<QString, bool> qtPrinters; + + for (int j = 0; j < printers.size(); ++j) { + qtPrinters.insert(printers.at(j).printerName(), !printers.at(j).isNull()); + } + + for (int i = 0; i < sysPrinters.size(); ++i) { + if (!qtPrinters.value(sysPrinters.at(i))) { + qDebug() << "Available printers: " << qtPrinters; + QFAIL(qPrintable(QString("Printer '%1' reported by system, but not reported by Qt").arg(sysPrinters.at(i)))); + } + } +#else + QSKIP("Test doesn't work on non-Unix", SkipAll); +#endif // defined(Q_OS_UNIX) || defined(ACCEPTABLE_WINDOWS) +} + +void tst_QPrinterInfo::testForPaperSizes() +{ +QSKIP("PaperSize feature doesn't work on Windows, fails on Mac, and is unstable on Linux", SkipAll); + // This test is based on common printers found at the Oslo + // office. It is likely to be skipped or fail for other locations. + QStringList hardPrinters; + hardPrinters << "Finnmarka" << "Huldra"; + + QList<QList<QPrinter::PaperSize> > hardSizes; + hardSizes + << QList<QPrinter::PaperSize>() + << QList<QPrinter::PaperSize>() + ; + hardSizes[0] // Finnmarka + << QPrinter::Letter + << QPrinter::A4 + << QPrinter::A3 + << QPrinter::A5 + << QPrinter::B4 + << QPrinter::B5 + << QPrinter::Custom // COM10 + << QPrinter::Custom // C5 + << QPrinter::Custom // DL + << QPrinter::Custom // Monarch + << QPrinter::Executive + << QPrinter::Custom // Foolscap + << QPrinter::Custom // ISO B5 + << QPrinter::Ledger + << QPrinter::Legal + << QPrinter::Custom // Japanese Post Card + << QPrinter::Custom // Invoice + ; + hardSizes[1] // Huldra + << QPrinter::Custom // Not listed at http://localhost:631/, name "Custom" + << QPrinter::Letter + << QPrinter::A4 + << QPrinter::A5 + << QPrinter::A6 + << QPrinter::B5 + << QPrinter::Custom // #5 1/2 Envelope + << QPrinter::Custom // 6x9 Envelope + << QPrinter::Custom // #10 Envelope + << QPrinter::Custom // A7 Envelope + << QPrinter::Custom // C5 Envelope + << QPrinter::Custom // DL Envelope + << QPrinter::Custom // Monarch Envelope + << QPrinter::Custom // #6 3/4 Envelope + << QPrinter::Executive + << QPrinter::Custom // US Folio + << QPrinter::Custom // Index Card + << QPrinter::Custom // ISO B5 + << QPrinter::Legal + << QPrinter::Custom // Statement + ; + + QList<QPrinterInfo> printers = QPrinterInfo::availablePrinters(); + for (int i = 0; i < printers.size(); ++i) { + for (int j = 0; j < hardPrinters.size(); ++j) { + if (printers[i].printerName() == hardPrinters[j]) { + QList<QPrinter::PaperSize> sizes = printers[i].supportedPaperSizes(); + qSort(sizes); + qSort(hardSizes[j]); + QCOMPARE(sizes, hardSizes[j]); + } + } + } +} + +void tst_QPrinterInfo::testConstructors() +{ + QList<QPrinterInfo> prns(QPrinterInfo::availablePrinters()); + + for (int c = 0; c < prns.size(); ++c) { + QList<QPrinter::PaperSize> list1, list2; + list1 = prns[c].supportedPaperSizes(); + QPrinter pr(prns[c]); + list2 = QPrinterInfo(pr).supportedPaperSizes(); + QCOMPARE(list2, list1); + } +} + +void tst_QPrinterInfo::testAssignment() +{ + QList<QPrinterInfo> prns(QPrinterInfo::availablePrinters()); + + for (int c = 0; c < prns.size(); ++c) { + QPrinterInfo pi = QPrinterInfo::defaultPrinter(); + pi = prns[c]; + QCOMPARE(pi.printerName(), prns[c].printerName()); + QCOMPARE(pi.supportedPaperSizes(), prns[c].supportedPaperSizes()); + } +} + +QTEST_MAIN(tst_QPrinterInfo) +#include "tst_qprinterinfo.moc" +#else +QTEST_NOOP_MAIN +#endif diff --git a/tests/auto/gui/painting/qregion/.gitignore b/tests/auto/gui/painting/qregion/.gitignore new file mode 100644 index 0000000000..8be21c3736 --- /dev/null +++ b/tests/auto/gui/painting/qregion/.gitignore @@ -0,0 +1 @@ +tst_qregion diff --git a/tests/auto/gui/painting/qregion/qregion.pro b/tests/auto/gui/painting/qregion/qregion.pro new file mode 100644 index 0000000000..8dbb4844a0 --- /dev/null +++ b/tests/auto/gui/painting/qregion/qregion.pro @@ -0,0 +1,8 @@ +load(qttest_p4) + +QT += gui-private + +SOURCES += tst_qregion.cpp + + + diff --git a/tests/auto/gui/painting/qregion/tst_qregion.cpp b/tests/auto/gui/painting/qregion/tst_qregion.cpp new file mode 100644 index 0000000000..58d2034e41 --- /dev/null +++ b/tests/auto/gui/painting/qregion/tst_qregion.cpp @@ -0,0 +1,1012 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qregion.h> + +#include <qbitmap.h> +#include <qpainter.h> +#include <qpolygon.h> +#ifdef Q_WS_X11 +#include <private/qt_x11_p.h> +#endif + + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QRegion : public QObject +{ + Q_OBJECT + +public: + tst_QRegion(); + +private slots: + void boundingRect(); + void rects(); + void swap(); + void setRects(); + void ellipseRegion(); + void polygonRegion(); + void bitmapRegion(); + void intersected_data(); + void intersected(); + void emptyPolygonRegion_data(); + void emptyPolygonRegion(); + + void intersects_region_data(); + void intersects_region(); + void intersects_rect_data(); + void intersects_rect(); + void contains_point(); + + void operator_plus_data(); + void operator_plus(); + void operator_minus_data(); + void operator_minus(); + void operator_intersect_data(); + void operator_intersect(); + void operator_xor_data(); + void operator_xor(); + + void rectCount_data(); + void rectCount(); + + void isEmpty_data(); + void isEmpty(); +#if defined(Q_WS_X11) && defined(QT_BUILD_INTERNAL) + void clipRectangles(); +#endif + + void regionFromPath(); + + void regionToPath_data(); + void regionToPath(); +}; + +Q_DECLARE_METATYPE(QPolygon) +Q_DECLARE_METATYPE(QVector<QRect>) +Q_DECLARE_METATYPE(QRegion) + +tst_QRegion::tst_QRegion() +{ +} + +void tst_QRegion::boundingRect() +{ + { + QRect rect; + QRegion region( rect ); + QCOMPARE( region.boundingRect(), rect ); + } + { + QRect rect( 10, -20, 30, 40 ); + QRegion region( rect ); + QCOMPARE( region.boundingRect(), rect ); + } + { + QRect rect(15,25,10,10); + QRegion region( rect ); + QCOMPARE( region.boundingRect(), rect ); + } + +} + +void tst_QRegion::rects() +{ + { + QRect rect; + QRegion region( rect ); + QVERIFY( region.isEmpty() ); + QVERIFY( region.rects().isEmpty() ); + } + { + QRect rect( 10, -20, 30, 40 ); + QRegion region( rect ); + QCOMPARE( region.rects().count(), 1 ); + QCOMPARE( region.rects()[0], rect ); + } + { + QRect r( QPoint(10, 10), QPoint(40, 40) ); + QRegion region( r ); + QVERIFY( region.contains( QPoint(10,10) ) ); + QVERIFY( region.contains( QPoint(20,40) ) ); + QVERIFY( region.contains( QPoint(40,20) ) ); + QVERIFY( !region.contains( QPoint(20,41) ) ); + QVERIFY( !region.contains( QPoint(41,20) ) ); + } + { + QRect r( 10, 10, 30, 30 ); + QRegion region( r ); + QVERIFY( region.contains( QPoint(10,10) ) ); + QVERIFY( region.contains( QPoint(20,39) ) ); + QVERIFY( region.contains( QPoint(39,20) ) ); + QVERIFY( !region.contains( QPoint(20,40) ) ); + QVERIFY( !region.contains( QPoint(40,20) ) ); + } +} + +void tst_QRegion::swap() +{ + QRegion r1(QRect( 0, 0,10,10)); + QRegion r2(QRect(10,10,10,10)); + r1.swap(r2); + QCOMPARE(r1.rects().front(), QRect(10,10,10,10)); + QCOMPARE(r2.rects().front(), QRect( 0, 0,10,10)); +} + +void tst_QRegion::setRects() +{ + { + QRegion region; + region.setRects( 0, 0 ); + QVERIFY( region.rects().isEmpty() ); + } + { + QRegion region; + QRect rect; + region.setRects( &rect, 0 ); + QVERIFY(region.isEmpty()); + QVERIFY(region == QRegion()); + QVERIFY(!region.boundingRect().isValid()); + QVERIFY(region.rects().isEmpty()); + } + { + QRegion region; + QRect rect; + region.setRects( &rect, 1 ); + QVERIFY( !region.boundingRect().isValid() ); + QVERIFY( region.rects().isEmpty() ); + } + { + QRegion region; + QRect rect( 10, -20, 30, 40 ); + region.setRects( &rect, 1 ); + QCOMPARE( region.rects().count(), 1 ); + QCOMPARE( region.rects()[0], rect ); + } +} + +void tst_QRegion::ellipseRegion() +{ + QRegion region(0, 0, 100, 100, QRegion::Ellipse); + + // These should not be inside the circe + QVERIFY(!region.contains(QPoint(13, 13))); + QVERIFY(!region.contains(QPoint(13, 86))); + QVERIFY(!region.contains(QPoint(86, 13))); + QVERIFY(!region.contains(QPoint(86, 86))); + + // These should be inside + QVERIFY(region.contains(QPoint(16, 16))); + QVERIFY(region.contains(QPoint(16, 83))); + QVERIFY(region.contains(QPoint(83, 16))); + QVERIFY(region.contains(QPoint(83, 83))); + + // ..a.. + // .. .. + // . . + // . . + // b c + // . . + // . . + // .. .. + // ..d.. + QVERIFY(region.contains(QPoint(50, 0))); // Mid-top (a) + QVERIFY(region.contains(QPoint(0, 50))); // Mid-left (b) + QVERIFY(region.contains(QPoint(99, 50))); // Mid-right (c) + QVERIFY(region.contains(QPoint(50, 99))); // Mid-bottom (d) + + QRect bounds = region.boundingRect(); + QCOMPARE(bounds.x(), 0); + QCOMPARE(bounds.y(), 0); + QCOMPARE(bounds.width(), 100); + QCOMPARE(bounds.height(), 100); +} + +void tst_QRegion::polygonRegion() +{ + QPolygon pa; + { + QRegion region ( pa ); + QVERIFY( region.isEmpty() ); + } + { + pa.setPoints( 8, 10, 10, // a____________b + 40, 10, // | | + 40, 20, // |___ ___| + 30, 20, // | | + 30, 40, // | | + 20, 40, // | | + 20, 20, // |____c + 10, 20 ); + + QRegion region ( pa ); + QVERIFY( !region.isEmpty() ); + + // These should not be inside the circle + QVERIFY( !region.contains( QPoint( 9, 9 ) ) ); + QVERIFY( !region.contains( QPoint( 30, 41 ) ) ); + QVERIFY( !region.contains( QPoint( 41, 10 ) ) ); + QVERIFY( !region.contains( QPoint( 31, 21 ) ) ); + + // These should be inside + QVERIFY( region.contains( QPoint( 10, 10 ) ) ); // Upper-left (a) + + } +} + +void tst_QRegion::emptyPolygonRegion_data() +{ + QTest::addColumn<QPolygon>("pa"); + QTest::addColumn<bool>("isEmpty"); + QTest::addColumn<int>("numRects"); + QTest::addColumn<QVector<QRect> >("rects"); + + QPolygon pa; + + + QTest::newRow("no points") << pa << true << 0 << QVector<QRect>(); + pa = QPolygon() << QPoint(10,10); + QTest::newRow("one point") << pa << true << 0 << QVector<QRect>(); + pa = QPolygon() << QPoint(10,10) << QPoint(10,20); + QTest::newRow("two points, horizontal") << pa << true << 0 << QVector<QRect>(); + + pa = QPolygon() << QPoint(10,10) << QPoint(20,10); + QTest::newRow("two points, vertical") << pa << true << 0 << QVector<QRect>(); + + pa = QPolygon() << QPoint(10,10) << QPoint(20,20); + QTest::newRow("two points, diagonal") << pa << true << 0 << QVector<QRect>(); + + pa = QPolygon() << QPoint(10,10) << QPoint(15,15) << QPoint(10,15) << QPoint(10, 10) ; + QVector<QRect> v; + v << QRect(10,11,1, 1) << QRect(10,12,2,1) << QRect(10,13,3,1) << QRect(10,14,4,1); + QTest::newRow("triangle") << pa << false << 4 << v; + + v.clear(); + v << QRect(10,10,10,10); + + QTest::newRow("rectangle") << QPolygon(QRect(10,10,10,10)) << false << 1 << v; + +} + +void tst_QRegion::emptyPolygonRegion() +{ + QFETCH(QPolygon, pa); + + QRegion r(pa); + QTEST(r.isEmpty(), "isEmpty"); + QTEST(r.rects().count(), "numRects"); + QTEST(r.rects(), "rects"); +} + + +static const char *circle_xpm[] = { + "20 20 2 1", + " c #FFFFFF", + ". c #000000", + " ...... ", + " .......... ", + " .............. ", + " ................ ", + " ................ ", + " .................. ", + " .................. ", + "....................", + "....................", + "....................", + "....................", + "....................", + "....................", + " .................. ", + " .................. ", + " ................ ", + " ................ ", + " .............. ", + " .......... ", + " ...... " +}; + +void tst_QRegion::bitmapRegion() +{ + QBitmap circle; + { + QRegion region( circle ); + QVERIFY( region.isEmpty() ); + } + { + circle = QPixmap( circle_xpm ); + QRegion region( circle ); + + //// These should not be inside the circe + QVERIFY( !region.contains( QPoint( 2, 2 ) ) ); + QVERIFY( !region.contains( QPoint( 2, 17 ) ) ); + QVERIFY( !region.contains( QPoint( 17, 2 ) ) ); + QVERIFY( !region.contains( QPoint( 17, 17 ) ) ); + + //// These should be inside + QVERIFY( region.contains( QPoint( 3, 3 ) ) ); + QVERIFY( region.contains( QPoint( 3, 16 ) ) ); + QVERIFY( region.contains( QPoint( 16, 3 ) ) ); + QVERIFY( region.contains( QPoint( 16, 16 ) ) ); + + QVERIFY( region.contains( QPoint( 0, 10 ) ) ); // Mid-left + QVERIFY( region.contains( QPoint( 10, 0 ) ) ); // Mid-top + QVERIFY( region.contains( QPoint( 19, 10 ) ) ); // Mid-right + QVERIFY( region.contains( QPoint( 10, 19 ) ) ); // Mid-bottom + } +} + +void tst_QRegion::intersected_data() +{ + QTest::addColumn<QRegion>("r1"); + QTest::addColumn<QRegion>("r2"); + QTest::addColumn<bool>("intersects"); + // QTest::addColumn<QRegion>("intersected"); + + QPolygon ps1(8); + QPolygon ps2(8); + ps1.putPoints(0,8, 20,20, 50,20, 50,100, 70,100, 70,20, 120,20, 120,200, 20, 200); + ps2.putPoints(0,8, 100,150, 140,150, 140,160, 160,160, 160,150, 200,150, 200,180, 100,180); + QTest::newRow("task30716") << QRegion(ps1) << QRegion(ps2) << true; +} + +void tst_QRegion::intersected() +{ + QFETCH(QRegion, r1); + QFETCH(QRegion, r2); + QFETCH(bool, intersects); + + QRegion interReg = r1.intersected(r2); + QVERIFY(interReg.isEmpty() != intersects); + // Need a way to test the intersected QRegion is right +} + +void tst_QRegion::intersects_region_data() +{ + QTest::addColumn<QRegion>("r1"); + QTest::addColumn<QRegion>("r2"); + QTest::addColumn<bool>("intersects"); + + QTest::newRow("rect overlap rect") << QRegion(100, 100, 200, 200) + << QRegion(200, 200, 200, 200) + << true; + + QTest::newRow("rect not overlap rect") << QRegion(100, 100, 200, 200) + << QRegion(400, 400, 200, 200) + << false; + + QTest::newRow("ellipse overlap ellipse") << QRegion(100, 100, 200, 200, QRegion::Ellipse) + << QRegion(200, 200, 200, 200, QRegion::Ellipse) + << true; + + QTest::newRow("ellipse not overlap ellipse") << QRegion(100, 100, 200, 200, QRegion::Ellipse) + << QRegion(400, 400, 200, 200, QRegion::Ellipse) + << false; +} + +void tst_QRegion::intersects_region() +{ + QFETCH(QRegion, r1); + QFETCH(QRegion, r2); + QFETCH(bool, intersects); + QCOMPARE(r1.intersects(r2), intersects); +} + + +void tst_QRegion::intersects_rect_data() +{ + QTest::addColumn<QRegion>("region"); + QTest::addColumn<QRect>("rect"); + QTest::addColumn<bool>("intersects"); + + QTest::newRow("rect overlap rect") << QRegion(100, 100, 200, 200) + << QRect(200, 200, 200, 200) + << true; + + QTest::newRow("rect not overlap rect") << QRegion(100, 100, 200, 200) + << QRect(400, 400, 200, 200) + << false; + + QTest::newRow("ellipse overlap rect") << QRegion(100, 100, 200, 200, QRegion::Ellipse) + << QRect(200, 200, 200, 200) + << true; + + QTest::newRow("ellipse not overlap rect") << QRegion(100, 100, 200, 200, QRegion::Ellipse) + << QRect(400, 400, 200, 200) + << false; +} + +void tst_QRegion::intersects_rect() +{ + QFETCH(QRegion, region); + QFETCH(QRect, rect); + QFETCH(bool, intersects); + QCOMPARE(region.intersects(rect), intersects); +} + +void tst_QRegion::contains_point() +{ + QCOMPARE(QRegion().contains(QPoint(1,1)),false); + QCOMPARE(QRegion(0,0,2,2).contains(QPoint(1,1)),true); +} + +void tst_QRegion::operator_plus_data() +{ + QTest::addColumn<QRegion>("r1"); + QTest::addColumn<QRegion>("r2"); + QTest::addColumn<QRegion>("expected"); + + QTest::newRow("empty 0") << QRegion() << QRegion() << QRegion(); + QTest::newRow("empty 1") << QRegion() << QRegion(QRect(10, 10, 10, 10)) + << QRegion(QRect(10, 10, 10, 10)); + QTest::newRow("empty 2") << QRegion(QRect(10, 10, 10, 10)) << QRegion() + << QRegion(QRect(10, 10, 10, 10)); + + QRegion expected; + QVector<QRect> rects; + rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10); + expected.setRects(rects.constData(), rects.size()); + QTest::newRow("non overlapping") << QRegion(10, 10, 10, 10) + << QRegion(22, 10, 10, 10) + << expected; + + rects.clear(); + rects << QRect(50, 0, 50, 2); + expected.setRects(rects.constData(), rects.size()); + QTest::newRow("adjacent y-rects") << QRegion(50, 0, 50, 1) + << QRegion(50, 1, 50, 1) + << expected; + + rects.clear(); + rects << QRect(50, 0, 2, 1); + expected.setRects(rects.constData(), rects.size()); + QTest::newRow("adjacent x-rects") << QRegion(50, 0, 1, 1) + << QRegion(51, 0, 1, 1) + << expected; + + rects.clear(); + rects << QRect(10, 10, 10, 10) << QRect(10, 20, 5, 10); + QRegion r1; + r1.setRects(rects.constData(), rects.size()); + QTest::newRow("double merge") << r1 << QRegion(15, 20, 5, 10) + << QRegion(10, 10, 10, 20); + rects.clear(); + rects << QRect(15, 10, 5, 10) << QRect(10, 20, 10, 10); + r1.setRects(rects.constData(), rects.size()); + QTest::newRow("double merge 2") << r1 << QRegion(10, 10, 5, 10) + << QRegion(10, 10, 10, 20); + QTest::newRow("overlapping x") << QRegion(10, 10, 10, 10) + << QRegion(15, 10, 10, 10) + << QRegion(10, 10, 15, 10); + QTest::newRow("overlapping y") << QRegion(10, 10, 10, 10) + << QRegion(10, 15, 10, 10) + << QRegion(10, 10, 10, 15); + rects.clear(); + rects << QRect(10, 10, 10, 10) << QRect(10, 20, 5, 10); + r1.setRects(rects.constData(), rects.size()); + rects.clear(); + rects << QRect(15, 20, 5, 10) << QRect(10, 30, 10, 10); + QRegion r2; + r2.setRects(rects.constData(), rects.size()); + QTest::newRow("triple merge") << r1 << r2 + << QRegion(10, 10, 10, 30); + + rects.clear(); + rects << QRect(10, 10, 4, 10) << QRect(15, 10, 10, 10); + r1.setRects(rects.constData(), rects.size()); + rects.clear(); + rects << QRect(15, 20, 10, 10); + r2.setRects(rects.constData(), rects.size()); + rects.clear(); + rects << QRect(10, 10, 4, 10) << QRect(15, 10, 10, 10) + << QRect(15, 20, 10, 10); + expected.setRects(rects.constData(), rects.size()); + QTest::newRow("don't merge y") << r1 << r2 << expected; + + QTest::newRow("equal 1") << QRegion(10, 10, 10, 10) + << QRegion(10, 10, 10, 10) + << QRegion(10, 10, 10, 10); + QTest::newRow("equal 2") << expected << expected << expected; +} + +void tst_QRegion::operator_plus() +{ + QFETCH(QRegion, r1); + QFETCH(QRegion, r2); + QFETCH(QRegion, expected); + + if (r1 + r2 != expected) { + qDebug() << "r1 + r2" << (r1 + r2); + qDebug() << "expected" << expected; + } + QCOMPARE(r1 + r2, expected); + if (r2.rectCount() == 1) { + if (r1 + r2.boundingRect() != expected) { + qDebug() << "r1 + QRect(r2)" << (r1 + r2.boundingRect()); + qDebug() << "expected" << expected; + } + QCOMPARE(r1 + r2.boundingRect(), expected); + } + + if (r2 + r1 != expected) { + qDebug() << "r2 + r1" << (r2 + r1); + qDebug() << "expected" << expected; + } + QCOMPARE(r2 + r1, expected); + if (r1.rectCount() == 1) { + if (r1 + r2.boundingRect() != expected) { + qDebug() << "r2 + QRect(r1)" << (r2 + r1.boundingRect()); + qDebug() << "expected" << expected; + } + QCOMPARE(r2 + r1.boundingRect(), expected); + } + + QRegion result1 = r1; + result1 += r2; + if (result1 != expected) { + qDebug() << "r1 += r2" << result1; + qDebug() << "expected" << expected; + } + QCOMPARE(result1, expected); + if (r2.rectCount() == 1) { + result1 = r1; + result1 += r2.boundingRect(); + if (result1 != expected) { + qDebug() << "r1 += QRect(r2)" << result1; + qDebug() << "expected" << expected; + } + QCOMPARE(result1, expected); + } + + QRegion result2 = r2; + result2 += r1; + if (result2 != expected) { + qDebug() << "r2 += r1" << result2; + qDebug() << "expected" << expected; + } + QCOMPARE(result2, expected); + if (r1.rectCount() == 1) { + result2 = r2; + result2 += r1.boundingRect(); + if (result2 != expected) { + qDebug() << "r2 += QRect(r1)" << result2; + qDebug() << "expected" << expected; + } + QCOMPARE(result2, expected); + } +} + +void tst_QRegion::operator_minus_data() +{ + QTest::addColumn<QRegion>("dest"); + QTest::addColumn<QRegion>("subtract"); + QTest::addColumn<QRegion>("expected"); + + QTest::newRow("empty 0") << QRegion() << QRegion() << QRegion(); + QTest::newRow("empty 1") << QRegion() << QRegion(QRect(10, 10, 10, 10)) + << QRegion(); + QTest::newRow("empty 2") << QRegion(QRect(10, 10, 10, 10)) << QRegion() + << QRegion(QRect(10, 10, 10, 10)); + + QRegion dest; + QVector<QRect> rects; + rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10); + dest.setRects(rects.constData(), rects.size()); + QTest::newRow("simple 1") << dest + << QRegion(22, 10, 10, 10) + << QRegion(10, 10, 10, 10); + QTest::newRow("simple 2") << dest + << QRegion(10, 10, 10, 10) + << QRegion(22, 10, 10, 10); + + rects.clear(); + rects << QRect(0, 0, 10, 10) << QRect(15, 0, 10, 10); + dest.setRects(rects.constData(), rects.size()); + + QRegion minus; + rects.clear(); + rects << QRect(0, 0, 12, 12) << QRect(15, 0, 12, 12); + minus.setRects(rects.constData(), rects.size()); + QTest::newRow("empty 3") << dest << minus << QRegion(); +} + +void tst_QRegion::operator_minus() +{ + QFETCH(QRegion, dest); + QFETCH(QRegion, subtract); + QFETCH(QRegion, expected); + + if (dest - subtract != expected) { + qDebug() << "dest - subtract" << (dest - subtract); + qDebug() << "expected" << expected; + }; + QCOMPARE(dest - subtract, expected); + + dest -= subtract; + + if (dest != expected) { + qDebug() << "dest" << dest; + qDebug() << "expected" << expected; + }; + QCOMPARE(dest, expected); +} + +void tst_QRegion::operator_intersect_data() +{ + QTest::addColumn<QRegion>("r1"); + QTest::addColumn<QRegion>("r2"); + QTest::addColumn<QRegion>("expected"); + + QTest::newRow("empty 0") << QRegion() << QRegion() << QRegion(); + QTest::newRow("empty 1") << QRegion() << QRegion(QRect(10, 10, 10, 10)) + << QRegion(); + QTest::newRow("empty 2") << QRegion(QRect(10, 10, 10, 10)) << QRegion() + << QRegion(); + + QRegion dest; + QVector<QRect> rects; + rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10); + dest.setRects(rects.constData(), rects.size()); + QTest::newRow("simple 1") << dest + << QRegion(22, 10, 10, 10) + << QRegion(22, 10, 10, 10); + QTest::newRow("simple 2") << dest + << QRegion(10, 10, 10, 10) + << QRegion(10, 10, 10, 10); + + rects.clear(); + rects << QRect(10, 10, 10, 10) << QRect(10, 20, 15, 10); + dest.setRects(rects.constData(), rects.size()); + QTest::newRow("merge 1") << dest + << QRegion(10, 10, 10, 20) + << QRegion(10, 10, 10, 20); + + rects.clear(); + rects << QRect(11, 11, 218, 117) << QRect(11, 128, 218, 27) + << QRect(264, 128, 122, 27) << QRect(11, 155, 218, 43) + << QRect(11, 198, 218, 27) << QRect(264, 198, 122, 27) + << QRect(11, 225, 218, 221); + dest.setRects(rects.constData(), rects.size()); + QTest::newRow("merge 2") << dest << QRegion(11, 11, 218, 458) + << QRegion(11, 11, 218, 435); + + rects.clear(); + rects << QRect(0, 0, 10, 10) << QRect(20, 0, 10, 10); + dest.setRects(rects.constData(), rects.size()); + QTest::newRow("empty 3") << dest << QRegion(11, 0, 5, 5) << QRegion(); + + QTest::newRow("extents check") << dest << QRegion(0, 0, 15, 15) + << QRegion(0, 0, 10, 10); + + rects.clear(); + rects << QRect(10, 10, 10, 10) << QRect(10, 20, 10, 10) + << QRect(30, 20, 10, 10) << QRect(10, 30, 10, 10); + dest.setRects(rects.constData(), rects.size()); + rects.clear(); + rects << QRect(10, 10, 10, 10) << QRect(10, 20, 10, 10) + << QRect(30, 20, 10, 10); + QRegion expected; + expected.setRects(rects.constData(), rects.size()); + QTest::newRow("dont merge") << dest << QRegion(0, 0, 100, 30) + << expected; +} + +void tst_QRegion::operator_intersect() +{ + QFETCH(QRegion, r1); + QFETCH(QRegion, r2); + QFETCH(QRegion, expected); + + if ((r1 & r2) != expected) { + qDebug() << "r1 & r2" << (r1 & r2); + qDebug() << "expected" << expected; + } + QCOMPARE(r1 & r2, expected); + + if ((r2 & r1) != expected) { + qDebug() << "r2 & r1" << (r2 & r1); + qDebug() << "expected" << expected; + } + QCOMPARE(r2 & r1, expected); + + r1 &= r2; + QCOMPARE(r1, expected); +} + +void tst_QRegion::operator_xor_data() +{ + QTest::addColumn<QRegion>("dest"); + QTest::addColumn<QRegion>("arg"); + QTest::addColumn<QRegion>("expected"); + + QTest::newRow("empty 0") << QRegion() << QRegion() << QRegion(); + QTest::newRow("empty 1") << QRegion() << QRegion(QRect(10, 10, 10, 10)) + << QRegion(QRect(10, 10, 10, 10)); + QTest::newRow("empty 2") << QRegion(QRect(10, 10, 10, 10)) << QRegion() + << QRegion(QRect(10, 10, 10, 10)); + + QRegion dest; + QVector<QRect> rects; + rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10); + dest.setRects(rects.constData(), rects.size()); + QTest::newRow("simple 1") << dest + << QRegion(22, 10, 10, 10) + << QRegion(10, 10, 10, 10); + QTest::newRow("simple 2") << dest + << QRegion(10, 10, 10, 10) + << QRegion(22, 10, 10, 10); + QTest::newRow("simple 3") << dest << dest << QRegion(); + QTest::newRow("simple 4") << QRegion(10, 10, 10, 10) + << QRegion(10, 10, 5, 10) + << QRegion(15, 10, 5, 10); + QTest::newRow("simple 5") << QRegion(10, 10, 10, 10) + << QRegion(10, 10, 10, 5) + << QRegion(10, 15, 10, 5); + + const QRegion rgnA(0, 0, 100, 100); + const QRegion rgnB(0, 0, 10, 10); + + QTest::newRow("simple 6") << rgnA + << rgnA - rgnB + << rgnB; + + QTest::newRow("simple 7") << rgnB + << rgnA + << rgnA - rgnB; +} + +void tst_QRegion::operator_xor() +{ + QFETCH(QRegion, dest); + QFETCH(QRegion, arg); + QFETCH(QRegion, expected); + + QCOMPARE(dest ^ arg, expected); + QCOMPARE(dest.xored(arg), expected); + + dest ^= arg; + QCOMPARE(dest, expected); +} + +void tst_QRegion::rectCount_data() +{ + QTest::addColumn<QRegion>("region"); + QTest::addColumn<int>("expected"); + + QTest::newRow("empty") << QRegion() << 0; + QTest::newRow("rect") << QRegion(10, 10, 10, 10) << 1; + + QRegion dest; + QVector<QRect> rects; + rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10); + dest.setRects(rects.constData(), rects.size()); + + QTest::newRow("2 rects") << dest << rects.size(); +} + +void tst_QRegion::rectCount() +{ + QFETCH(QRegion, region); + QFETCH(int, expected); + + QCOMPARE(region.rectCount(), expected); +} + +void tst_QRegion::isEmpty_data() +{ + QTest::addColumn<QRegion>("region"); + + QTest::newRow("QRegion") << QRegion(); + + QVector<QRect> rects; + rects << QRect(0, 0, 10, 10) << QRect(15, 0, 10, 10); + QRegion r1; + r1.setRects(rects.constData(), rects.size()); + + QRegion r2; + rects.clear(); + rects << QRect(0, 0, 12, 12) << QRect(15, 0, 12, 12); + r2.setRects(rects.constData(), rects.size()); + QTest::newRow("minus") << (r1 - r2); +} + +void tst_QRegion::isEmpty() +{ + QFETCH(QRegion, region); + + QVERIFY(region.isEmpty()); + QCOMPARE(region, QRegion()); + QCOMPARE(region.rectCount(), 0); + QCOMPARE(region.boundingRect(), QRect()); + QVERIFY(region.rects().isEmpty()); +} + +#if defined(Q_WS_X11) && defined(QT_BUILD_INTERNAL) +void tst_QRegion::clipRectangles() +{ + QRegion region(30, 30, 30, 30); + int num = 0; + qt_getClipRects(region, num); + QCOMPARE(num, 1); + + region += QRegion(10, 10, 10, 10); + XRectangle *rects2 = static_cast<XRectangle *>(qt_getClipRects(region, num)); + QCOMPARE(num, 2); + + // Here's the important part (Y-sorted): + QCOMPARE(int(rects2[0].y), 10); + QCOMPARE(int(rects2[1].y), 30); +} +#endif + +void tst_QRegion::regionFromPath() +{ + { + QPainterPath path; + path.addRect(0, 0, 10, 10); + path.addRect(0, 100, 100, 1000); + + QRegion rgn(path.toFillPolygon().toPolygon()); + QCOMPARE(rgn.rects().size(), 2); + QCOMPARE(rgn.rects().at(0), QRect(0, 0, 10, 10)); + QCOMPARE(rgn.rects().at(1), QRect(0, 100, 100, 1000)); + + QCOMPARE(rgn.boundingRect(), QRect(0, 0, 100, 1100)); + } + + { + QPainterPath path; + path.addRect(0, 0, 100, 100); + path.addRect(10, 10, 80, 80); + + QRegion rgn(path.toFillPolygon().toPolygon()); + QCOMPARE(rgn.rects().size(), 4); + + QCOMPARE(rgn.rects().at(0), QRect(0, 0, 100, 10)); + QCOMPARE(rgn.rects().at(1), QRect(0, 10, 10, 80)); + QCOMPARE(rgn.rects().at(2), QRect(90, 10, 10, 80)); + QCOMPARE(rgn.rects().at(3), QRect(0, 90, 100, 10)); + + QCOMPARE(rgn.boundingRect(), QRect(0, 0, 100, 100)); + } +} + +Q_DECLARE_METATYPE(QPainterPath) + +void tst_QRegion::regionToPath_data() +{ + QTest::addColumn<QPainterPath>("path"); + { + QPainterPath path; + path.addRect(QRect(0, 0, 10, 10)); + + QTest::newRow("Rectangle") << path; + } + + { + QPainterPath path; + path.addRect(QRect(0, 0, 10, 10)); + path.addRect(QRect(20, 0, 10, 10)); + + QTest::newRow("Two rects") << path; + } + + { + QPainterPath path; + path.addEllipse(QRect(0, 0, 10, 10)); + + QTest::newRow("Ellipse") << path; + } + + { + QPainterPath path; + path.addRect(QRect(0, 0, 3, 8)); + path.addRect(QRect(6, 0, 3, 8)); + path.addRect(QRect(3, 3, 3, 2)); + path.addRect(QRect(12, 3, 3, 2)); + + QTest::newRow("H-dot") << path; + } + + { + QPainterPath path; + for (int y = 0; y <= 10; ++y) { + for (int x = 0; x <= 10; ++x) { + if (!(y & 1) || ((x ^ y) & 1)) + path.addRect(QRect(x, y, 1, 1)); + } + } + + QTest::newRow("Grid") << path; + } +} + +#ifdef QT_BUILD_INTERNAL +QT_BEGIN_NAMESPACE +extern QPainterPath qt_regionToPath(const QRegion ®ion); +QT_END_NAMESPACE +#endif + +void tst_QRegion::regionToPath() +{ +#ifdef QT_BUILD_INTERNAL + + QFETCH(QPainterPath, path); + + for (int i = 0; i < 360; i += 10) { + + QTransform transform; + transform.scale(5, 5); + transform.rotate(i); + + QPainterPath mapped = transform.map(path); + QRegion region(mapped.toFillPolygon().toPolygon()); + + QPainterPath a; + a.addRegion(region); + + QPainterPath b = qt_regionToPath(region); + + QRect r = a.boundingRect().toAlignedRect(); + QImage ia(r.size(), QImage::Format_RGB32); + ia.fill(0xffffffff); + QImage ib = ia; + + QPainter p(&ia); + p.translate(-r.x(), -r.y()); + p.fillPath(a, Qt::red); + p.end(); + p.begin(&ib); + p.translate(-r.x(), -r.y()); + p.fillPath(b, Qt::red); + p.end(); + + QCOMPARE(ia, ib); + QCOMPARE(a.boundingRect(), b.boundingRect()); + } +#endif +} + +QTEST_MAIN(tst_QRegion) +#include "tst_qregion.moc" diff --git a/tests/auto/gui/painting/qtransform/.gitignore b/tests/auto/gui/painting/qtransform/.gitignore new file mode 100644 index 0000000000..f1da0161e7 --- /dev/null +++ b/tests/auto/gui/painting/qtransform/.gitignore @@ -0,0 +1 @@ +tst_qtransform diff --git a/tests/auto/gui/painting/qtransform/qtransform.pro b/tests/auto/gui/painting/qtransform/qtransform.pro new file mode 100644 index 0000000000..92bef8ce38 --- /dev/null +++ b/tests/auto/gui/painting/qtransform/qtransform.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +HEADERS += +SOURCES += tst_qtransform.cpp + +unix:!mac:!symbian:LIBS+=-lm + + diff --git a/tests/auto/gui/painting/qtransform/tst_qtransform.cpp b/tests/auto/gui/painting/qtransform/tst_qtransform.cpp new file mode 100644 index 0000000000..f8319c9e13 --- /dev/null +++ b/tests/auto/gui/painting/qtransform/tst_qtransform.cpp @@ -0,0 +1,807 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include "qtransform.h" +#include <math.h> +#include <qpolygon.h> +#include <qdebug.h> + +Q_DECLARE_METATYPE(QRect) + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QTransform : public QObject +{ + Q_OBJECT + +public: + tst_QTransform(); + virtual ~tst_QTransform(); + + +public slots: + void init(); + void cleanup(); +private slots: + void mapRect_data(); + void operator_star_qrect_data(); + void mapToPolygon_data(); + void mapRect(); + void operator_star_qrect(); + void assignments(); + void mapToPolygon(); + void translate(); + void scale(); + void matrix(); + void testOffset(); + void types(); + void scalarOps(); + void transform(); + void mapEmptyPath(); + void boundingRect(); + void controlPointRect(); + void inverted_data(); + void inverted(); + void projectivePathMapping(); + void mapInt(); + void mapPathWithPoint(); + +private: + void mapping_data(); +}; + +Q_DECLARE_METATYPE(QTransform) +Q_DECLARE_METATYPE(QPolygon) + +tst_QTransform::tst_QTransform() +{ +} + +tst_QTransform::~tst_QTransform() +{ +} + +void tst_QTransform::init() +{ + // No initialisation is required +} + +void tst_QTransform::cleanup() +{ + // No cleanup is required. +} + +#if defined(Q_OS_WIN) && !defined(M_PI) +#define M_PI 3.14159265897932384626433832795f +#endif + +void tst_QTransform::mapRect_data() +{ + mapping_data(); + + // rotations that are not multiples of 90 degrees. mapRect returns the bounding rect here. + qreal deg = -45; + QTest::newRow( "rot 45 a" ) + << QTransform().rotate(deg) + << QRect( 0, 0, 10, 10 ) + << QPolygon( QRect( 0, -7, 14, 14 ) ); + QTest::newRow( "rot 45 b" ) + << QTransform().rotate(deg) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 21, -14, 50, 49 ) ); + QTest::newRow( "rot 45 c" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 0, 0, 10, 10 ) + << QPolygon( QRect( 0, -71, 141, 142 ) ); + QTest::newRow( "rot 45 d" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 212, -141, 495, 495 ) ); + + deg = 45; + QTest::newRow( "rot -45 a" ) + << QTransform().rotate(deg) + << QRect( 0, 0, 10, 10 ) + << QPolygon( QRect( -7, 0, 14, 14 ) ); + QTest::newRow( "rot -45 b" ) + << QTransform().rotate(deg) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -35, 21, 49, 50 ) ); + QTest::newRow( "rot -45 c" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 0, 0, 10, 10 ) + << QPolygon( QRect( -71, 0, 142, 141 ) ); + QTest::newRow( "rot -45 d" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -354, 212, 495, 495 ) ); +} + +void tst_QTransform::operator_star_qrect_data() +{ + mapping_data(); +} + +void tst_QTransform::mapToPolygon_data() +{ + mapping_data(); +} + +void tst_QTransform::mapping_data() +{ + //create the testtable instance and define the elements + QTest::addColumn<QTransform>("matrix"); + QTest::addColumn<QRect>("src"); + QTest::addColumn<QPolygon>("res"); + + //next we fill it with data + + // identity + QTest::newRow( "identity" ) + << QTransform() + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 10, 20, 30, 40 ) ); + // scaling + QTest::newRow( "scale 0" ) + << QTransform().scale(2, 2) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 20, 40, 60, 80 ) ); + QTest::newRow( "scale 1" ) + << QTransform().scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 100, 200, 300, 400 ) ); + // mirroring + QTest::newRow( "mirror 0" ) + << QTransform().scale(-1, 1) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -40, 20, 30, 40 ) ); + QTest::newRow( "mirror 1" ) + << QTransform().scale(1, -1) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 10, -60, 30, 40 ) ); + QTest::newRow( "mirror 2" ) + << QTransform().scale(-1, -1) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -40, -60, 30, 40 ) ); + QTest::newRow( "mirror 3" ) + << QTransform().scale(-2, -2) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -80, -120, 60, 80 ) ); + QTest::newRow( "mirror 4" ) + << QTransform().scale(-10, -10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -400, -600, 300, 400 ) ); + QTest::newRow( "mirror 5" ) + << QTransform().scale(-1, 1) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -30, 0, 30, 40 ) ); + QTest::newRow( "mirror 6" ) + << QTransform().scale(1, -1) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( 0, -40, 30, 40 ) ); + QTest::newRow( "mirror 7" ) + << QTransform().scale(-1, -1) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -30, -40, 30, 40 ) ); + QTest::newRow( "mirror 8" ) + << QTransform().scale(-2, -2) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -60, -80, 60, 80 ) ); + QTest::newRow( "mirror 9" ) + << QTransform().scale(-10, -10) << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -300, -400, 300, 400 ) ); + + // rotations + float deg = 0.; + QTest::newRow( "rot 0 a" ) + << QTransform().rotate(deg) + << QRect( 0, 0, 30, 40 ) + << QPolygon ( QRect( 0, 0, 30, 40 ) ); + deg = 0.00001f; + QTest::newRow( "rot 0 b" ) + << QTransform().rotate(deg) + << QRect( 0, 0, 30, 40 ) + << QPolygon ( QRect( 0, 0, 30, 40 ) ); + deg = 0.; + QTest::newRow( "rot 0 c" ) + << QTransform().rotate(deg) + << QRect( 10, 20, 30, 40 ) + << QPolygon ( QRect( 10, 20, 30, 40 ) ); + deg = 0.00001f; + QTest::newRow( "rot 0 d" ) + << QTransform().rotate(deg) + << QRect( 10, 20, 30, 40 ) + << QPolygon ( QRect( 10, 20, 30, 40 ) ); + + // rotations + deg = -90.f; + QTest::newRow( "rotscale 90 a" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( 0, -300, 400, 300 ) ); + deg = -90.00001f; + QTest::newRow( "rotscale 90 b" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( 0, -300, 400, 300 ) ); + deg = -90.f; + QTest::newRow( "rotscale 90 c" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 200, -400, 400, 300 ) ); + deg = -90.00001f; + QTest::newRow( "rotscale 90 d" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 200, -400, 400, 300 ) ); + + deg = 180.f; + QTest::newRow( "rotscale 180 a" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -300, -400, 300, 400 ) ); + deg = 180.000001f; + QTest::newRow( "rotscale 180 b" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -300, -400, 300, 400 ) ); + deg = 180.f; + QTest::newRow( "rotscale 180 c" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -400, -600, 300, 400 ) ); + deg = 180.000001f; + QTest::newRow( "rotscale 180 d" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -400, -600, 300, 400 ) ); + + deg = -270.f; + QTest::newRow( "rotscale 270 a" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -400, 0, 400, 300 ) ); + deg = -270.0000001f; + QTest::newRow( "rotscale 270 b" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -400, 0, 400, 300 ) ); + deg = -270.f; + QTest::newRow( "rotscale 270 c" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -600, 100, 400, 300 ) ); + deg = -270.000001f; + QTest::newRow( "rotscale 270 d" ) + << QTransform().rotate(deg).scale(10, 10) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -600, 100, 400, 300 ) ); +} + +void tst_QTransform::mapRect() +{ + QFETCH( QTransform, matrix ); + QFETCH( QRect, src ); + QFETCH( QPolygon, res ); + QRect mapped = matrix.mapRect(src); + QCOMPARE( mapped, res.boundingRect().adjusted(0, 0, -1, -1) ); + + QRectF r = matrix.mapRect(QRectF(src)); + QRect ir(r.topLeft().toPoint(), r.bottomRight().toPoint() - QPoint(1, 1)); + QCOMPARE( mapped, ir ); +} + +void tst_QTransform::operator_star_qrect() +{ +#if 0 + QFETCH( QTransform, matrix ); + QFETCH( QRect, src ); + QFETCH( QPolygon, res ); + + QCOMPARE( (matrix * src), QRegion(res) ); +#endif +} + +void tst_QTransform::assignments() +{ + QTransform m; + m.scale(2, 3); + m.rotate(45); + m.shear(4, 5); + + QTransform c1(m); + + QCOMPARE(m.m11(), c1.m11()); + QCOMPARE(m.m12(), c1.m12()); + QCOMPARE(m.m21(), c1.m21()); + QCOMPARE(m.m22(), c1.m22()); + QCOMPARE(m.dx(), c1.dx()); + QCOMPARE(m.dy(), c1.dy()); + + QTransform c2 = m; + QCOMPARE(m.m11(), c2.m11()); + QCOMPARE(m.m12(), c2.m12()); + QCOMPARE(m.m21(), c2.m21()); + QCOMPARE(m.m22(), c2.m22()); + QCOMPARE(m.dx(), c2.dx()); + QCOMPARE(m.dy(), c2.dy()); +} + + +void tst_QTransform::mapToPolygon() +{ + QFETCH( QTransform, matrix ); + QFETCH( QRect, src ); + QFETCH( QPolygon, res ); + + QPolygon poly = matrix.mapToPolygon(src); + + // don't care about starting point + bool equal = false; + for (int i = 0; i < poly.size(); ++i) { + QPolygon rot; + for (int j = i; j < poly.size(); ++j) + rot << poly[j]; + for (int j = 0; j < i; ++j) + rot << poly[j]; + if (rot == res) + equal = true; + } + + QVERIFY(equal); +} + + +void tst_QTransform::translate() +{ + QTransform m( 1, 2, 3, 4, 5, 6 ); + QTransform res2( m ); + QTransform res( 1, 2, 3, 4, 75, 106 ); + m.translate( 10, 20 ); + QVERIFY( m == res ); + m.translate( -10, -20 ); + QVERIFY( m == res2 ); + QVERIFY( QTransform::fromTranslate( 0, 0 ).type() == QTransform::TxNone ); + QVERIFY( QTransform::fromTranslate( 10, 0 ).type() == QTransform::TxTranslate ); + QVERIFY( QTransform::fromTranslate( -1, 5 ) == QTransform().translate( -1, 5 )); + QVERIFY( QTransform::fromTranslate( 0, 0 ) == QTransform()); +} + +void tst_QTransform::scale() +{ + QTransform m( 1, 2, 3, 4, 5, 6 ); + QTransform res2( m ); + QTransform res( 10, 20, 60, 80, 5, 6 ); + m.scale( 10, 20 ); + QVERIFY( m == res ); + m.scale( 1./10., 1./20. ); + QVERIFY( m == res2 ); + QVERIFY( QTransform::fromScale( 1, 1 ).type() == QTransform::TxNone ); + QVERIFY( QTransform::fromScale( 2, 4 ).type() == QTransform::TxScale ); + QVERIFY( QTransform::fromScale( 2, 4 ) == QTransform().scale( 2, 4 )); + QVERIFY( QTransform::fromScale( 1, 1 ) == QTransform()); +} + +void tst_QTransform::matrix() +{ + QMatrix mat1; + mat1.scale(0.3, 0.7); + mat1.translate(53.3, 94.4); + mat1.rotate(45); + + QMatrix mat2; + mat2.rotate(33); + mat2.scale(0.6, 0.6); + mat2.translate(13.333, 7.777); + + QTransform tran1(mat1); + QTransform tran2(mat2); + QTransform dummy; + dummy.setMatrix(mat1.m11(), mat1.m12(), 0, + mat1.m21(), mat1.m22(), 0, + mat1.dx(), mat1.dy(), 1); + + QVERIFY(tran1 == dummy); + QVERIFY(tran1.inverted() == dummy.inverted()); + QVERIFY(tran1.inverted() == QTransform(mat1.inverted())); + QVERIFY(tran2.inverted() == QTransform(mat2.inverted())); + + QMatrix mat3 = mat1 * mat2; + QTransform tran3 = tran1 * tran2; + QVERIFY(QTransform(mat3) == tran3); + + /* QMatrix::operator==() doesn't use qFuzzyCompare(), which + * on win32-g++ results in a failure. So we work around it by + * calling QTranform::operator==(), which performs a fuzzy compare. */ + QCOMPARE(QTransform(mat3), QTransform(tran3.toAffine())); + + QTransform tranInv = tran1.inverted(); + QMatrix matInv = mat1.inverted(); + + QRect rect(43, 70, 200, 200); + QPoint pt(43, 66); + QVERIFY(tranInv.map(pt) == matInv.map(pt)); + QVERIFY(tranInv.map(pt) == matInv.map(pt)); + + QPainterPath path; + path.moveTo(55, 60); + path.lineTo(110, 110); + path.quadTo(220, 50, 10, 20); + path.closeSubpath(); + QVERIFY(tranInv.map(path) == matInv.map(path)); +} + +void tst_QTransform::testOffset() +{ + QTransform trans; + const QMatrix &aff = trans.toAffine(); + QCOMPARE((void*)(&aff), (void*)(&trans)); +} + +void tst_QTransform::types() +{ + QTransform m1; + QCOMPARE(m1.type(), QTransform::TxNone); + + m1.translate(1.0f, 0.0f); + QCOMPARE(m1.type(), QTransform::TxTranslate); + QCOMPARE(m1.inverted().type(), QTransform::TxTranslate); + + m1.scale(1.0f, 2.0f); + QCOMPARE(m1.type(), QTransform::TxScale); + QCOMPARE(m1.inverted().type(), QTransform::TxScale); + + m1.rotate(45.0f); + QCOMPARE(m1.type(), QTransform::TxRotate); + QCOMPARE(m1.inverted().type(), QTransform::TxRotate); + + m1.shear(0.5f, 0.25f); + QCOMPARE(m1.type(), QTransform::TxShear); + QCOMPARE(m1.inverted().type(), QTransform::TxShear); + + m1.rotate(45.0f, Qt::XAxis); + QCOMPARE(m1.type(), QTransform::TxProject); + m1.shear(0.5f, 0.25f); + QCOMPARE(m1.type(), QTransform::TxProject); + m1.rotate(45.0f); + QCOMPARE(m1.type(), QTransform::TxProject); + m1.scale(1.0f, 2.0f); + QCOMPARE(m1.type(), QTransform::TxProject); + m1.translate(1.0f, 0.0f); + QCOMPARE(m1.type(), QTransform::TxProject); + + QTransform m2(1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 1.0f); + + QCOMPARE(m2.type(), QTransform::TxTranslate); + QCOMPARE((m1 * m2).type(), QTransform::TxProject); + + m1 *= QTransform(); + QCOMPARE(m1.type(), QTransform::TxProject); + + m1 *= QTransform(1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 1.0f); + QCOMPARE(m1.type(), QTransform::TxProject); + + m2.reset(); + QCOMPARE(m2.type(), QTransform::TxNone); + + m2.setMatrix(1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f); + QCOMPARE(m2.type(), QTransform::TxNone); + + m2 *= QTransform(); + QCOMPARE(m2.type(), QTransform::TxNone); + + m2.setMatrix(2.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f); + QCOMPARE(m2.type(), QTransform::TxScale); + m2 *= QTransform(); + QCOMPARE(m2.type(), QTransform::TxScale); + + m2.setMatrix(0.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 1.0f); + QCOMPARE(m2.type(), QTransform::TxRotate); + m2 *= QTransform(); + QCOMPARE(m2.type(), QTransform::TxRotate); + + m2.setMatrix(1.0f, 0.0f, 0.5f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f); + QCOMPARE(m2.type(), QTransform::TxProject); + m2 *= QTransform(); + QCOMPARE(m2.type(), QTransform::TxProject); + + m2.setMatrix(1.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 1.0f); + QCOMPARE(m2.type(), QTransform::TxShear); + + m2 *= m2.inverted(); + QCOMPARE(m2.type(), QTransform::TxNone); + + m2.translate(5.0f, 5.0f); + m2.rotate(45.0f); + m2.rotate(-45.0f); + QCOMPARE(m2.type(), QTransform::TxTranslate); + + m2.scale(2.0f, 3.0f); + m2.shear(1.0f, 0.0f); + m2.shear(-1.0f, 0.0f); + QCOMPARE(m2.type(), QTransform::TxScale); + + m2 *= QTransform(1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f); + QCOMPARE(m2.type(), QTransform::TxShear); + + m2 *= QTransform(1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 1.0f); + QCOMPARE(m2.type(), QTransform::TxShear); + + QTransform m3(1.8f, 0.0f, 0.0f, + 0.0f, 1.8f, 0.0f, + 0.0f, 0.0f, 1.0f); + + QCOMPARE(m3.type(), QTransform::TxScale); + m3.translate(5.0f, 5.0f); + QCOMPARE(m3.type(), QTransform::TxScale); + QCOMPARE(m3.inverted().type(), QTransform::TxScale); + + m3.setMatrix(1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 2.0f); + QCOMPARE(m3.type(), QTransform::TxProject); + + m3.setMatrix(0.0f, 2.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 2.0f); + QCOMPARE(m3.type(), QTransform::TxProject); + + QTransform m4; + m4.scale(5, 5); + m4.translate(4, 2); + m4.rotate(45); + + QCOMPARE(m4.type(), QTransform::TxRotate); + + QTransform m5; + m5.scale(5, 5); + m5 = m5.adjoint() / m5.determinant(); + QCOMPARE(m5.type(), QTransform::TxScale); +} + + +void tst_QTransform::scalarOps() +{ + QTransform t; + QCOMPARE(t.m11(), 1.); + QCOMPARE(t.m33(), 1.); + QCOMPARE(t.m21(), 0.); + + t = QTransform() + 3; + QCOMPARE(t.m11(), 4.); + QCOMPARE(t.m33(), 4.); + QCOMPARE(t.m21(), 3.); + + t = t - 3; + QCOMPARE(t.m11(), 1.); + QCOMPARE(t.m33(), 1.); + QCOMPARE(t.m21(), 0.); + QCOMPARE(t.isIdentity(), true); + + t += 3; + t = t * 2; + QCOMPARE(t.m11(), 8.); + QCOMPARE(t.m33(), 8.); + QCOMPARE(t.m21(), 6.); +} + +void tst_QTransform::transform() +{ + QTransform t; + t.rotate(30, Qt::YAxis); + t.translate(15, 10); + t.scale(2, 2); + t.rotate(30); + t.shear(0.5, 0.5); + + QTransform a, b, c, d, e; + a.rotate(30, Qt::YAxis); + b.translate(15, 10); + c.scale(2, 2); + d.rotate(30); + e.shear(0.5, 0.5); + + QVERIFY(qFuzzyCompare(t, e * d * c * b * a)); +} + +void tst_QTransform::mapEmptyPath() +{ + QPainterPath path; + path.moveTo(10, 10); + path.lineTo(10, 10); + QCOMPARE(QTransform().map(path), path); +} + +void tst_QTransform::boundingRect() +{ + QPainterPath path; + path.moveTo(10, 10); + path.lineTo(10, 10); + QCOMPARE(path.boundingRect(), QRectF(10, 10, 0, 0)); +} + +void tst_QTransform::controlPointRect() +{ + QPainterPath path; + path.moveTo(10, 10); + path.lineTo(10, 10); + QCOMPARE(path.controlPointRect(), QRectF(10, 10, 0, 0)); +} + +void tst_QTransform::inverted_data() +{ + QTest::addColumn<QTransform>("matrix"); + + QTest::newRow("identity") + << QTransform(); + + QTest::newRow("TxTranslate") + << QTransform().translate(200, 10); + + QTest::newRow("TxScale") + << QTransform().scale(5, 2); + + QTest::newRow("TxTranslate TxScale") + << QTransform().translate(100, -10).scale(40, 2); + + QTest::newRow("TxScale TxTranslate") + << QTransform().scale(40, 2).translate(100, -10); + + QTest::newRow("TxRotate") + << QTransform().rotate(40, Qt::ZAxis); + + QTest::newRow("TxRotate TxScale") + << QTransform().rotate(60, Qt::ZAxis).scale(2, 0.25); + + QTest::newRow("TxScale TxRotate") + << QTransform().scale(2, 0.25).rotate(30, Qt::ZAxis); + + QTest::newRow("TxRotate TxScale TxTranslate") + << QTransform().rotate(60, Qt::ZAxis).scale(2, 0.25).translate(200, -3000); + + QTest::newRow("TxRotate TxTranslate TxScale") + << QTransform().rotate(60, Qt::ZAxis).translate(200, -3000).scale(19, 77); + + QTest::newRow("TxShear") + << QTransform().shear(10, 10); + + QTest::newRow("TxShear TxRotate") + << QTransform().shear(10, 10).rotate(45, Qt::ZAxis); + + QTest::newRow("TxShear TxRotate TxScale") + << QTransform().shear(10, 10).rotate(45, Qt::ZAxis).scale(19, 81); + + QTest::newRow("TxTranslate TxShear TxRotate TxScale") + << QTransform().translate(150, -1).shear(10, 10).rotate(45, Qt::ZAxis).scale(19, 81); + + const qreal s = 500000; + + QTransform big; + big.scale(s, s); + + QTest::newRow("big") << big; + + QTransform smallTransform; + smallTransform.scale(1/s, 1/s); + + QTest::newRow("small") << smallTransform; +} + +void tst_QTransform::inverted() +{ + if (sizeof(qreal) != sizeof(double)) + QSKIP("precision error if qreal is not double", SkipAll); + + QFETCH(QTransform, matrix); + + const QTransform inverted = matrix.inverted(); + + QVERIFY(matrix.isIdentity() == inverted.isIdentity()); + QVERIFY(matrix.type() == inverted.type()); + + QVERIFY((matrix * inverted).isIdentity()); + QVERIFY((inverted * matrix).isIdentity()); +} + +void tst_QTransform::projectivePathMapping() +{ + QPainterPath path; + path.addRect(-50, -50, 100, 100); + + const QRectF view(0, 0, 1024, 1024); + + QVERIFY(view.intersects(path.boundingRect())); + + for (int i = 0; i < 85; i += 5) { + QTransform transform; + transform.translate(512, 512); + transform.rotate(i, Qt::YAxis); + + const QPainterPath mapped = transform.map(path); + + QVERIFY(view.intersects(mapped.boundingRect())); + QVERIFY(transform.inverted().mapRect(view).intersects(path.boundingRect())); + } +} + +void tst_QTransform::mapInt() +{ + int x = 0; + int y = 0; + + QTransform::fromTranslate(10, 10).map(x, y, &x, &y); + + QCOMPARE(x, 10); + QCOMPARE(y, 10); +} + +void tst_QTransform::mapPathWithPoint() +{ + QPainterPath p(QPointF(10, 10)); + p = QTransform::fromTranslate(10, 10).map(p); + QCOMPARE(p.currentPosition(), QPointF(20, 20)); +} + +QTEST_APPLESS_MAIN(tst_QTransform) + + +#include "tst_qtransform.moc" diff --git a/tests/auto/gui/painting/qwmatrix/.gitignore b/tests/auto/gui/painting/qwmatrix/.gitignore new file mode 100644 index 0000000000..c983191769 --- /dev/null +++ b/tests/auto/gui/painting/qwmatrix/.gitignore @@ -0,0 +1 @@ +tst_qwmatrix diff --git a/tests/auto/gui/painting/qwmatrix/qwmatrix.pro b/tests/auto/gui/painting/qwmatrix/qwmatrix.pro new file mode 100644 index 0000000000..bab298bc93 --- /dev/null +++ b/tests/auto/gui/painting/qwmatrix/qwmatrix.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_qwmatrix.cpp + +unix:!mac:!symbian:LIBS+=-lm + + diff --git a/tests/auto/gui/painting/qwmatrix/tst_qwmatrix.cpp b/tests/auto/gui/painting/qwmatrix/tst_qwmatrix.cpp new file mode 100644 index 0000000000..0e7372d9d8 --- /dev/null +++ b/tests/auto/gui/painting/qwmatrix/tst_qwmatrix.cpp @@ -0,0 +1,436 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qmatrix.h> +#include <math.h> +#include <qpolygon.h> + +Q_DECLARE_METATYPE(QRect) + +//TESTED_CLASS= +//TESTED_FILES=gui/painting/qmatrix.h gui/painting/qmatrix.cpp + +class tst_QWMatrix : public QObject +{ + Q_OBJECT + +public: + tst_QWMatrix(); + virtual ~tst_QWMatrix(); + + +public slots: + void init(); + void cleanup(); +private slots: + void mapRect_data(); + void operator_star_qrect_data(); + void mapToPolygon_data(); + void mapRect(); + void operator_star_qrect(); + void operator_star_qwmatrix(); + void assignments(); + void mapToPolygon(); + void translate(); + void scale(); + void mapPolygon(); + +private: + void mapping_data(); +}; + +Q_DECLARE_METATYPE(QMatrix) +Q_DECLARE_METATYPE(QPolygon) + +tst_QWMatrix::tst_QWMatrix() +{ +} + +tst_QWMatrix::~tst_QWMatrix() +{ +} + +void tst_QWMatrix::init() +{ + // No initialisation is required +} + +void tst_QWMatrix::cleanup() +{ + // No cleanup is required. +} + +void tst_QWMatrix::mapRect_data() +{ + mapping_data(); +} + +void tst_QWMatrix::operator_star_qrect_data() +{ + mapping_data(); +} + +void tst_QWMatrix::mapToPolygon_data() +{ + mapping_data(); +} + +void tst_QWMatrix::mapping_data() +{ + //create the testtable instance and define the elements + QTest::addColumn<QMatrix>("matrix"); + QTest::addColumn<QRect>("src"); + QTest::addColumn<QPolygon>("res"); + + //next we fill it with data + + // identity + QTest::newRow( "identity" ) << QMatrix( 1, 0, 0, 1, 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 10, 20, 30, 40 ) ); + // scaling + QTest::newRow( "scale 0" ) << QMatrix( 2, 0, 0, 2, 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 20, 40, 60, 80 ) ); + QTest::newRow( "scale 1" ) << QMatrix( 10, 0, 0, 10, 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 100, 200, 300, 400 ) ); + // mirroring + QTest::newRow( "mirror 0" ) << QMatrix( -1, 0, 0, 1, 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -40, 20, 30, 40 ) ); + QTest::newRow( "mirror 1" ) << QMatrix( 1, 0, 0, -1, 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 10, -60, 30, 40 ) ); + QTest::newRow( "mirror 2" ) << QMatrix( -1, 0, 0, -1, 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -40, -60, 30, 40 ) ); + QTest::newRow( "mirror 3" ) << QMatrix( -2, 0, 0, -2, 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -80, -120, 60, 80 ) ); + QTest::newRow( "mirror 4" ) << QMatrix( -10, 0, 0, -10, 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -400, -600, 300, 400 ) ); + QTest::newRow( "mirror 5" ) << QMatrix( -1, 0, 0, 1, 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -30, 0, 30, 40 ) ); + QTest::newRow( "mirror 6" ) << QMatrix( 1, 0, 0, -1, 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( 0, -40, 30, 40 ) ); + QTest::newRow( "mirror 7" ) << QMatrix( -1, 0, 0, -1, 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -30, -40, 30, 40 ) ); + QTest::newRow( "mirror 8" ) << QMatrix( -2, 0, 0, -2, 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -60, -80, 60, 80 ) ); + QTest::newRow( "mirror 9" ) << QMatrix( -10, 0, 0, -10, 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -300, -400, 300, 400 ) ); + +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +#define M_PI 3.14159265897932384626433832795f +#endif + + // rotations + float deg = 0.; + QTest::newRow( "rot 0 a" ) << QMatrix( cos( M_PI*deg/180. ), -sin( M_PI*deg/180. ), + sin( M_PI*deg/180. ), cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon ( QRect( 0, 0, 30, 40 ) ); + deg = 0.00001f; + QTest::newRow( "rot 0 b" ) << QMatrix( cos( M_PI*deg/180. ), -sin( M_PI*deg/180. ), + sin( M_PI*deg/180. ), cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon ( QRect( 0, 0, 30, 40 ) ); + deg = 0.; + QTest::newRow( "rot 0 c" ) << QMatrix( cos( M_PI*deg/180. ), -sin( M_PI*deg/180. ), + sin( M_PI*deg/180. ), cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon ( QRect( 10, 20, 30, 40 ) ); + deg = 0.00001f; + QTest::newRow( "rot 0 d" ) << QMatrix( cos( M_PI*deg/180. ), -sin( M_PI*deg/180. ), + sin( M_PI*deg/180. ), cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon ( QRect( 10, 20, 30, 40 ) ); + +#if 0 + // rotations + deg = 90.; + QTest::newRow( "rotscale 90 a" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( 0, -299, 400, 300 ) ); + deg = 90.00001; + QTest::newRow( "rotscale 90 b" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( 0, -299, 400, 300 ) ); + deg = 90.; + QTest::newRow( "rotscale 90 c" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 200, -399, 400, 300 ) ); + deg = 90.00001; + QTest::newRow( "rotscale 90 d" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 200, -399, 400, 300 ) ); + + deg = 180.; + QTest::newRow( "rotscale 180 a" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -299, -399, 300, 400 ) ); + deg = 180.000001; + QTest::newRow( "rotscale 180 b" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -299, -399, 300, 400 ) ); + deg = 180.; + QTest::newRow( "rotscale 180 c" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -399, -599, 300, 400 ) ); + deg = 180.000001; + QTest::newRow( "rotscale 180 d" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -399, -599, 300, 400 ) ); + + deg = 270.; + QTest::newRow( "rotscale 270 a" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -399, 00, 400, 300 ) ); + deg = 270.0000001; + QTest::newRow( "rotscale 270 b" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 30, 40 ) + << QPolygon( QRect( -399, 00, 400, 300 ) ); + deg = 270.; + QTest::newRow( "rotscale 270 c" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -599, 100, 400, 300 ) ); + deg = 270.000001; + QTest::newRow( "rotscale 270 d" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -599, 100, 400, 300 ) ); + + // rotations that are not multiples of 90 degrees. mapRect returns the bounding rect here. + deg = 45; + QTest::newRow( "rot 45 a" ) << QMatrix( cos( M_PI*deg/180. ), -sin( M_PI*deg/180. ), + sin( M_PI*deg/180. ), cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 10, 10 ) + << QPolygon( QRect( 0, -7, 14, 14 ) ); + QTest::newRow( "rot 45 b" ) << QMatrix( cos( M_PI*deg/180. ), -sin( M_PI*deg/180. ), + sin( M_PI*deg/180. ), cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 21, -14, 49, 49 ) ); + QTest::newRow( "rot 45 c" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 10, 10 ) + << QPolygon( QRect( 0, -70, 141, 141 ) ); + QTest::newRow( "rot 45 d" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( 212, -141, 495, 495 ) ); + + deg = -45; + QTest::newRow( "rot -45 a" ) << QMatrix( cos( M_PI*deg/180. ), -sin( M_PI*deg/180. ), + sin( M_PI*deg/180. ), cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 10, 10 ) + << QPolygon( QRect( -7, 0, 14, 14 ) ); + QTest::newRow( "rot -45 b" ) << QMatrix( cos( M_PI*deg/180. ), -sin( M_PI*deg/180. ), + sin( M_PI*deg/180. ), cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -35, 21, 49, 49 ) ); + QTest::newRow( "rot -45 c" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 0, 0, 10, 10 ) + << QPolygon( QRect( -70, 0, 141, 141 ) ); + QTest::newRow( "rot -45 d" ) << QMatrix( 10*cos( M_PI*deg/180. ), -10*sin( M_PI*deg/180. ), + 10*sin( M_PI*deg/180. ), 10*cos( M_PI*deg/180. ), 0, 0 ) + << QRect( 10, 20, 30, 40 ) + << QPolygon( QRect( -353, 212, 495, 495 ) ); +#endif +} + +void tst_QWMatrix::mapRect() +{ + QFETCH( QMatrix, matrix ); + QFETCH( QRect, src ); +// qDebug( "got src: %d/%d (%d/%d), matrix=[ %f %f %f %f %f %f ]", +// src.x(), src.y(), src.width(), src.height(), +// matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(), matrix.dx(), matrix.dy() ); + QTEST( QPolygon( matrix.mapRect(src) ), "res" ); +} + +void tst_QWMatrix::operator_star_qrect() +{ +#if 0 // QT_VERSION >= 0x030100 + QFETCH( QMatrix, matrix ); + QFETCH( QRect, src ); + QFETCH( QPolygon, res ); + + QCOMPARE( (matrix * src), QRegion(res) ); +#else + QSKIP( "Not tested with Qt versions < 3.1", SkipAll); +#endif +} + + +void tst_QWMatrix::operator_star_qwmatrix() +{ +#if 0 + // Left out until the matrix multiply operator behaves properly.. + QMatrix m1( 2, 3, 4, 5, 6, 7 ); + QMatrix m2( 3, 4, 5, 6, 7, 8 ); + + QMatrix result1x2( 21, 26, 37, 46, 44, 75 ); + QMatrix result2x1( 22, 29, 34, 45, 53, 80); + + QMatrix product12 = m1*m2; + QMatrix product21 = m2*m1; + + QVERIFY( product12==result1x2 ); + QVERIFY( product21==result2x1 ); +#else + QSKIP( "Not tested with Qt versions since the operator is broken..", + SkipAll ); +#endif +} + + +void tst_QWMatrix::assignments() +{ + QMatrix m; + m.scale(2, 3); + m.rotate(45); + m.shear(4, 5); + + QMatrix c1(m); + + QCOMPARE(m.m11(), c1.m11()); + QCOMPARE(m.m12(), c1.m12()); + QCOMPARE(m.m21(), c1.m21()); + QCOMPARE(m.m22(), c1.m22()); + QCOMPARE(m.dx(), c1.dx()); + QCOMPARE(m.dy(), c1.dy()); + + QMatrix c2 = m; + QCOMPARE(m.m11(), c2.m11()); + QCOMPARE(m.m12(), c2.m12()); + QCOMPARE(m.m21(), c2.m21()); + QCOMPARE(m.m22(), c2.m22()); + QCOMPARE(m.dx(), c2.dx()); + QCOMPARE(m.dy(), c2.dy()); +} + + +void tst_QWMatrix::mapToPolygon() +{ + QFETCH( QMatrix, matrix ); + QFETCH( QRect, src ); + QFETCH( QPolygon, res ); + + QCOMPARE( matrix.mapToPolygon( src ), res ); +} + + +void tst_QWMatrix::translate() +{ + QMatrix m( 1, 2, 3, 4, 5, 6 ); + QMatrix res2( m ); + QMatrix res( 1, 2, 3, 4, 75, 106 ); + m.translate( 10, 20 ); + QVERIFY( m == res ); + m.translate( -10, -20 ); + QVERIFY( m == res2 ); +} + +void tst_QWMatrix::scale() +{ + QMatrix m( 1, 2, 3, 4, 5, 6 ); + QMatrix res2( m ); + QMatrix res( 10, 20, 60, 80, 5, 6 ); + m.scale( 10, 20 ); + QVERIFY( m == res ); + m.scale( 1./10., 1./20. ); + QVERIFY( m == res2 ); +} + +void tst_QWMatrix::mapPolygon() +{ + QPolygon poly; + poly << QPoint(0, 0) << QPoint(1, 1) << QPoint(100, 1) << QPoint(1, 100) << QPoint(-1, -1) << QPoint(-1000, 1000); + + { + QMatrix m; + m.rotate(90); + + // rotating 90 degrees four times should result in original poly + QPolygon mapped = m.map(m.map(m.map(m.map(poly)))); + QCOMPARE(mapped, poly); + + QMatrix m2; + m2.scale(10, 10); + QMatrix m3; + m3.scale(0.1, 0.1); + + mapped = m3.map(m2.map(poly)); + QCOMPARE(mapped, poly); + } + + { + QMatrix m(1, 2, 3, 4, 5, 6); + + QPolygon mapped = m.map(poly); + for (int i = 0; i < mapped.size(); ++i) + QCOMPARE(mapped.at(i), m.map(poly.at(i))); + } +} + +QTEST_APPLESS_MAIN(tst_QWMatrix) +#include "tst_qwmatrix.moc" diff --git a/tests/auto/gui/text/qabstracttextdocumentlayout/.gitignore b/tests/auto/gui/text/qabstracttextdocumentlayout/.gitignore new file mode 100644 index 0000000000..d747466790 --- /dev/null +++ b/tests/auto/gui/text/qabstracttextdocumentlayout/.gitignore @@ -0,0 +1 @@ +tst_qabstracttextdocumentlayout diff --git a/tests/auto/gui/text/qabstracttextdocumentlayout/qabstracttextdocumentlayout.pro b/tests/auto/gui/text/qabstracttextdocumentlayout/qabstracttextdocumentlayout.pro new file mode 100644 index 0000000000..22b013e37e --- /dev/null +++ b/tests/auto/gui/text/qabstracttextdocumentlayout/qabstracttextdocumentlayout.pro @@ -0,0 +1,9 @@ +############################################################ +# Project file for autotest for file qabstracttextdocumentlayout.h +############################################################ + +load(qttest_p4) +QT += widgets +SOURCES += tst_qabstracttextdocumentlayout.cpp + + diff --git a/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp b/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp new file mode 100644 index 0000000000..90f212e832 --- /dev/null +++ b/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qdebug.h> +#include <qabstracttextdocumentlayout.h> +#include <qimage.h> +#include <qtextobject.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QAbstractTextDocumentLayout : public QObject +{ +Q_OBJECT + +public: + tst_QAbstractTextDocumentLayout(); + virtual ~tst_QAbstractTextDocumentLayout(); + +private slots: + void getSetCheck(); + void maximumBlockCount(); +}; + +tst_QAbstractTextDocumentLayout::tst_QAbstractTextDocumentLayout() +{ +} + +tst_QAbstractTextDocumentLayout::~tst_QAbstractTextDocumentLayout() +{ +} + +class MyAbstractTextDocumentLayout : public QAbstractTextDocumentLayout +{ + Q_OBJECT +public: + MyAbstractTextDocumentLayout(QTextDocument *doc) + : QAbstractTextDocumentLayout(doc) + , gotFullLayout(false) + , blockCount(0) + , changeEvents(0) + { + } + + void draw(QPainter *, const PaintContext &) {} + int hitTest(const QPointF &, Qt::HitTestAccuracy) const { return 0; } + int pageCount() const { return 0; } + QSizeF documentSize() const { return QSizeF(); } + QRectF frameBoundingRect(QTextFrame *) const { return QRectF(); } + QRectF blockBoundingRect(const QTextBlock &) const { return QRectF(); } + void documentChanged(int from, int /* oldLength */, int length) { + ++changeEvents; + + QTextBlock last = document()->lastBlock(); + int lastPos = last.position() + last.length() - 1; + if (from == 0 && length == lastPos) + gotFullLayout = true; + } + + bool gotFullLayout; + int blockCount; + int changeEvents; + +public slots: + void blockCountChanged(int bc) { blockCount = bc; } +}; + +// Testing get/set functions +void tst_QAbstractTextDocumentLayout::getSetCheck() +{ + QTextDocument doc; + MyAbstractTextDocumentLayout obj1(&doc); + // QPaintDevice * QAbstractTextDocumentLayout::paintDevice() + // void QAbstractTextDocumentLayout::setPaintDevice(QPaintDevice *) + QImage *var1 = new QImage(QSize(10,10), QImage::Format_ARGB32_Premultiplied); + obj1.setPaintDevice(var1); + QCOMPARE(static_cast<QPaintDevice *>(var1), obj1.paintDevice()); + obj1.setPaintDevice((QPaintDevice *)0); + QCOMPARE(static_cast<QPaintDevice *>(0), obj1.paintDevice()); + delete var1; +} + +void tst_QAbstractTextDocumentLayout::maximumBlockCount() +{ + QTextDocument doc; + doc.setMaximumBlockCount(10); + + MyAbstractTextDocumentLayout layout(&doc); + doc.setDocumentLayout(&layout); + QObject::connect(&doc, SIGNAL(blockCountChanged(int)), &layout, SLOT(blockCountChanged(int))); + + QTextCursor cursor(&doc); + for (int i = 0; i < 10; ++i) { + cursor.insertBlock(); + cursor.insertText("bla"); + } + + QCOMPARE(layout.blockCount, 10); + + layout.gotFullLayout = false; + layout.changeEvents = 0; + cursor.insertBlock(); + QCOMPARE(layout.changeEvents, 2); + cursor.insertText("foo"); + QCOMPARE(layout.changeEvents, 3); + cursor.insertBlock(); + QCOMPARE(layout.changeEvents, 5); + cursor.insertText("foo"); + QCOMPARE(layout.changeEvents, 6); + + QVERIFY(!layout.gotFullLayout); + + QCOMPARE(layout.blockCount, 10); +} + +QTEST_MAIN(tst_QAbstractTextDocumentLayout) +#include "tst_qabstracttextdocumentlayout.moc" diff --git a/tests/auto/gui/text/qcssparser/.gitignore b/tests/auto/gui/text/qcssparser/.gitignore new file mode 100644 index 0000000000..6cc99800e0 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/.gitignore @@ -0,0 +1 @@ +tst_qcssparser diff --git a/tests/auto/gui/text/qcssparser/qcssparser.pro b/tests/auto/gui/text/qcssparser/qcssparser.pro new file mode 100644 index 0000000000..16fa265231 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/qcssparser.pro @@ -0,0 +1,17 @@ +load(qttest_p4) +SOURCES += tst_qcssparser.cpp +QT += xml gui-private + +requires(contains(QT_CONFIG,private_tests)) +!symbian: { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} + +wince*|symbian: { + addFiles.files = testdata + addFiles.path = . + timesFont.files = C:/Windows/Fonts/times.ttf + timesFont.path = . + DEPLOYMENT += addFiles timesFont +} + diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/comments/input b/tests/auto/gui/text/qcssparser/testdata/scanner/comments/input new file mode 100644 index 0000000000..af2b659a5b --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/comments/input @@ -0,0 +1 @@ +/* let's see if comments actually work *//*foo*/ "it /*should be preserved \"in strings*/ though" diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/comments/output b/tests/auto/gui/text/qcssparser/testdata/scanner/comments/output new file mode 100644 index 0000000000..80ede0ba22 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/comments/output @@ -0,0 +1,4 @@ +S|/* let's see if comments actually work */ +S|/*foo*/ +S| +STRING|"it /*should be preserved "in strings*/ though" diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/comments2/input b/tests/auto/gui/text/qcssparser/testdata/scanner/comments2/input new file mode 100644 index 0000000000..3135acd78c --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/comments2/input @@ -0,0 +1 @@ +/*foo*/{/*foo*/+/*foo*/>/*foo*/,/*foo*/}/*foo*/- diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/comments2/output b/tests/auto/gui/text/qcssparser/testdata/scanner/comments2/output new file mode 100644 index 0000000000..d1f1259869 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/comments2/output @@ -0,0 +1,12 @@ +S|/*foo*/ +LBRACE|{ +S|/*foo*/ +PLUS|+ +S|/*foo*/ +GREATER|> +S|/*foo*/ +COMMA|, +S|/*foo*/ +RBRACE|} +S|/*foo*/ +MINUS|- diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/comments3/input b/tests/auto/gui/text/qcssparser/testdata/scanner/comments3/input new file mode 100644 index 0000000000..8634543a8f --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/comments3/input @@ -0,0 +1 @@ +url(/*comment*/"www.kde.org") diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/comments3/output b/tests/auto/gui/text/qcssparser/testdata/scanner/comments3/output new file mode 100644 index 0000000000..af7bad752a --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/comments3/output @@ -0,0 +1,4 @@ +FUNCTION|url( +S|/*comment*/ +STRING|"www.kde.org" +RPAREN|) diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/comments4/input b/tests/auto/gui/text/qcssparser/testdata/scanner/comments4/input new file mode 100644 index 0000000000..62d039b00c --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/comments4/input @@ -0,0 +1 @@ +!/*hmm*/important diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/comments4/output b/tests/auto/gui/text/qcssparser/testdata/scanner/comments4/output new file mode 100644 index 0000000000..eb86e7bd15 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/comments4/output @@ -0,0 +1,3 @@ +EXCLAMATION_SYM|! +S|/*hmm*/ +IDENT|important diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/quotedstring/input b/tests/auto/gui/text/qcssparser/testdata/scanner/quotedstring/input new file mode 100644 index 0000000000..deae3a8dab --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/quotedstring/input @@ -0,0 +1 @@ +background: 'test_bug.png'; diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/quotedstring/output b/tests/auto/gui/text/qcssparser/testdata/scanner/quotedstring/output new file mode 100644 index 0000000000..ed52419594 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/quotedstring/output @@ -0,0 +1,5 @@ +IDENT|background +COLON|: +S| +STRING|'test_bug.png' +SEMICOLON|; diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/simple/input b/tests/auto/gui/text/qcssparser/testdata/scanner/simple/input new file mode 100644 index 0000000000..b37e587661 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/simple/input @@ -0,0 +1 @@ +p { display:block; } diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/simple/output b/tests/auto/gui/text/qcssparser/testdata/scanner/simple/output new file mode 100644 index 0000000000..71c60ec9bf --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/simple/output @@ -0,0 +1,9 @@ +IDENT|p +LBRACE| { +S| +IDENT|display +COLON|: +IDENT|block +SEMICOLON|; +S| +RBRACE|} diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/unicode/input b/tests/auto/gui/text/qcssparser/testdata/scanner/unicode/input new file mode 100644 index 0000000000..2c33f7be97 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/unicode/input @@ -0,0 +1 @@ +\41"\7E"\00006Df diff --git a/tests/auto/gui/text/qcssparser/testdata/scanner/unicode/output b/tests/auto/gui/text/qcssparser/testdata/scanner/unicode/output new file mode 100644 index 0000000000..0829c37e28 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/testdata/scanner/unicode/output @@ -0,0 +1,3 @@ +IDENT|A +STRING|"~" +IDENT|mf diff --git a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp new file mode 100644 index 0000000000..1e82431a48 --- /dev/null +++ b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp @@ -0,0 +1,1718 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtTest/QtTest> +#include <QtXml/QtXml> +#if defined(Q_OS_WINCE) +#include <QtGui/QFontDatabase> +#endif + +//TESTED_CLASS=QCss +//TESTED_FILES=gui/text/qcssparser.cpp gui/text/qcssparser_p.h + +#include "private/qcssparser_p.h" + +class tst_QCssParser : public QObject +{ + Q_OBJECT + +public slots: + void initTestCase(); + void cleanupTestCase(); + +private slots: + void scanner_data(); + void scanner(); + void term_data(); + void term(); + void expr_data(); + void expr(); + void import(); + void media(); + void page(); + void ruleset(); + void selector_data(); + void selector(); + void prio(); + void escapes(); + void malformedDeclarations_data(); + void malformedDeclarations(); + void invalidAtKeywords(); + void marginValue(); + void marginValue_data(); + void colorValue_data(); + void colorValue(); + void styleSelector_data(); + void styleSelector(); + void specificity_data(); + void specificity(); + void specificitySort_data(); + void specificitySort(); + void rulesForNode_data(); + void rulesForNode(); + void shorthandBackgroundProperty_data(); + void shorthandBackgroundProperty(); + void pseudoElement_data(); + void pseudoElement(); + void gradient_data(); + void gradient(); + void extractFontFamily_data(); + void extractFontFamily(); + void extractBorder_data(); + void extractBorder(); + void noTextDecoration(); + void quotedAndUnquotedIdentifiers(); + +private: +#if defined(Q_OS_WINCE) + int m_timesFontId; +#endif +}; + +void tst_QCssParser::initTestCase() +{ +#if defined(Q_OS_WINCE) + QFontDatabase fontDB; + m_timesFontId = -1; + if (!fontDB.families().contains("Times New Roman")) { + m_timesFontId = QFontDatabase::addApplicationFont("times.ttf"); + QVERIFY(m_timesFontId != -1); + } +#endif +} + +void tst_QCssParser::cleanupTestCase() +{ +#if defined(Q_OS_WINCE) + if (m_timesFontId != -1) + QFontDatabase::removeApplicationFont(m_timesFontId); +#endif +} + +void tst_QCssParser::scanner_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("output"); + +#if !defined(Q_OS_IRIX) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) + QDir d(SRCDIR); +#else + QDir d(QDir::current()); +#endif + d.cd("testdata"); + d.cd("scanner"); + foreach (QFileInfo test, d.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { + QString dir = test.absoluteFilePath() + QDir::separator(); + QTest::newRow(qPrintable(test.baseName())) + << dir + "input" + << dir + "output" + ; + } +} + + +static const char *tokenName(QCss::TokenType t) +{ + switch (t) { + case QCss::NONE: return "NONE"; + case QCss::S: return "S"; + case QCss::CDO: return "CDO"; + case QCss::CDC: return "CDC"; + case QCss::INCLUDES: return "INCLUDES"; + case QCss::DASHMATCH: return "DASHMATCH"; + case QCss::LBRACE: return "LBRACE"; + case QCss::PLUS: return "PLUS"; + case QCss::GREATER: return "GREATER"; + case QCss::COMMA: return "COMMA"; + case QCss::STRING: return "STRING"; + case QCss::INVALID: return "INVALID"; + case QCss::IDENT: return "IDENT"; + case QCss::HASH: return "HASH"; + case QCss::ATKEYWORD_SYM: return "ATKEYWORD_SYM"; + case QCss::EXCLAMATION_SYM: return "EXCLAMATION_SYM"; + case QCss::LENGTH: return "LENGTH"; + case QCss::PERCENTAGE: return "PERCENTAGE"; + case QCss::NUMBER: return "NUMBER"; + case QCss::FUNCTION: return "FUNCTION"; + case QCss::COLON: return "COLON"; + case QCss::SEMICOLON: return "SEMICOLON"; + case QCss::RBRACE: return "RBRACE"; + case QCss::SLASH: return "SLASH"; + case QCss::MINUS: return "MINUS"; + case QCss::DOT: return "DOT"; + case QCss::STAR: return "STAR"; + case QCss::LBRACKET: return "LBRACKET"; + case QCss::RBRACKET: return "RBRACKET"; + case QCss::EQUAL: return "EQUAL"; + case QCss::LPAREN: return "LPAREN"; + case QCss::RPAREN: return "RPAREN"; + case QCss::OR: return "OR"; + } + return ""; +} + +static void debug(const QVector<QCss::Symbol> &symbols, int index = -1) +{ + qDebug() << "all symbols:"; + for (int i = 0; i < symbols.count(); ++i) + qDebug() << "(" << i << "); Token:" << tokenName(symbols.at(i).token) << "; Lexem:" << symbols.at(i).lexem(); + if (index != -1) + qDebug() << "failure at index" << index; +} + +//static void debug(const QCss::Parser &p) { debug(p.symbols); } + +void tst_QCssParser::scanner() +{ + QFETCH(QString, input); + QFETCH(QString, output); + + QFile inputFile(input); + QVERIFY(inputFile.open(QIODevice::ReadOnly|QIODevice::Text)); + QVector<QCss::Symbol> symbols; + QCss::Scanner::scan(QCss::Scanner::preprocess(QString::fromUtf8(inputFile.readAll())), &symbols); + + QVERIFY(symbols.count() > 1); + QVERIFY(symbols.last().token == QCss::S); + QVERIFY(symbols.last().lexem() == QLatin1String("\n")); + symbols.remove(symbols.count() - 1, 1); + + QFile outputFile(output); + QVERIFY(outputFile.open(QIODevice::ReadOnly|QIODevice::Text)); + QStringList lines; + while (!outputFile.atEnd()) { + QString line = QString::fromUtf8(outputFile.readLine()); + if (line.endsWith(QLatin1Char('\n'))) + line.chop(1); + lines.append(line); + } + + if (lines.count() != symbols.count()) { + debug(symbols); + QCOMPARE(lines.count(), symbols.count()); + } + + for (int i = 0; i < lines.count(); ++i) { + QStringList l = lines.at(i).split(QChar::fromLatin1('|')); + QCOMPARE(l.count(), 2); + const QString expectedToken = l.at(0); + const QString expectedLexem = l.at(1); + QString actualToken = QString::fromLatin1(tokenName(symbols.at(i).token)); + if (actualToken != expectedToken) { + debug(symbols, i); + QCOMPARE(actualToken, expectedToken); + } + if (symbols.at(i).lexem() != expectedLexem) { + debug(symbols, i); + QCOMPARE(symbols.at(i).lexem(), expectedLexem); + } + } +} + +Q_DECLARE_METATYPE(QCss::Value) + +void tst_QCssParser::term_data() +{ + QTest::addColumn<bool>("parseSuccess"); + QTest::addColumn<QString>("css"); + QTest::addColumn<QCss::Value>("expectedValue"); + + QCss::Value val; + + val.type = QCss::Value::Percentage; + val.variant = QVariant(double(200)); + QTest::newRow("percentage") << true << "200%" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10px"); + QTest::newRow("px") << true << "10px" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10cm"); + QTest::newRow("cm") << true << "10cm" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10mm"); + QTest::newRow("mm") << true << "10mm" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10pt"); + QTest::newRow("pt") << true << "10pt" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10pc"); + QTest::newRow("pc") << true << "10pc" << val; + + val.type = QCss::Value::Length; + val.variant = QString("42in"); + QTest::newRow("inch") << true << "42in" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10deg"); + QTest::newRow("deg") << true << "10deg" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10rad"); + QTest::newRow("rad") << true << "10rad" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10grad"); + QTest::newRow("grad") << true << "10grad" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10ms"); + QTest::newRow("time") << true << "10ms" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10s"); + QTest::newRow("times") << true << "10s" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10hz"); + QTest::newRow("hz") << true << "10hz" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10khz"); + QTest::newRow("khz") << true << "10khz" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10myunit"); + QTest::newRow("dimension") << true << "10myunit" << val; + + val.type = QCss::Value::Percentage; + + val.type = QCss::Value::Percentage; + val.variant = QVariant(double(-200)); + QTest::newRow("minuspercentage") << true << "-200%" << val; + + val.type = QCss::Value::Length; + val.variant = QString("10em"); + QTest::newRow("ems") << true << "10em" << val; + + val.type = QCss::Value::String; + val.variant = QVariant(QString("foo")); + QTest::newRow("string") << true << "\"foo\"" << val; + + val.type = QCss::Value::Function; + val.variant = QVariant(QStringList() << "myFunc" << "23, (nested text)"); + QTest::newRow("function") << true << "myFunc(23, (nested text))" << val; + + QTest::newRow("function_failure") << false << "myFunction((blah)" << val; + QTest::newRow("function_failure2") << false << "+myFunc(23, (nested text))" << val; + + val.type = QCss::Value::Color; + val.variant = QVariant(QColor("#12ff34")); + QTest::newRow("hexcolor") << true << "#12ff34" << val; + + val.type = QCss::Value::Color; + val.variant = QVariant(QColor("#ffbb00")); + QTest::newRow("hexcolor2") << true << "#fb0" << val; + + QTest::ignoreMessage(QtWarningMsg, "QCssParser::parseHexColor: Unknown color name '#cafebabe'"); + QTest::newRow("hexcolor_failure") << false << "#cafebabe" << val; + + val.type = QCss::Value::Uri; + val.variant = QString("www.kde.org"); + QTest::newRow("uri1") << true << "url(\"www.kde.org\")" << val; + + QTest::newRow("uri2") << true << "url(www.kde.org)" << val; + + val.type = QCss::Value::KnownIdentifier; + val.variant = int(QCss::Value_Italic); + QTest::newRow("italic") << true << "italic" << val; + + val.type = QCss::Value::KnownIdentifier; + val.variant = int(QCss::Value_Italic); + QTest::newRow("ItaLIc") << true << "ItaLIc" << val; +} + +void tst_QCssParser::term() +{ + QFETCH(bool, parseSuccess); + QFETCH(QString, css); + QFETCH(QCss::Value, expectedValue); + + QCss::Parser parser(css); + QCss::Value val; + QVERIFY(parser.testTerm()); + QCOMPARE(parser.parseTerm(&val), parseSuccess); + if (parseSuccess) { + QCOMPARE(int(val.type), int(expectedValue.type)); + if (val.variant != expectedValue.variant) { + qDebug() << "val.variant:" << val.variant << "expectedValue.variant:" << expectedValue.variant; + QCOMPARE(val.variant, expectedValue.variant); + } + } +} + +Q_DECLARE_METATYPE(QVector<QCss::Value>) + +void tst_QCssParser::expr_data() +{ + QTest::addColumn<bool>("parseSuccess"); + QTest::addColumn<QString>("css"); + QTest::addColumn<QVector<QCss::Value> >("expectedValues"); + + QVector<QCss::Value> values; + QCss::Value val; + + QCss::Value comma; + comma.type = QCss::Value::TermOperatorComma; + + val.type = QCss::Value::Identifier; + val.variant = QLatin1String("foo"); + values << val; + values << comma; + val.variant = QLatin1String("bar"); + values << val; + values << comma; + val.variant = QLatin1String("baz"); + values << val; + QTest::newRow("list") << true << "foo, bar, baz" << values; + values.clear(); +} + +void tst_QCssParser::expr() +{ + QFETCH(bool, parseSuccess); + QFETCH(QString, css); + QFETCH(QVector<QCss::Value>, expectedValues); + + QCss::Parser parser(css); + QVector<QCss::Value> values; + QVERIFY(parser.testExpr()); + QCOMPARE(parser.parseExpr(&values), parseSuccess); + if (parseSuccess) { + QCOMPARE(values.count(), expectedValues.count()); + + for (int i = 0; i < values.count(); ++i) { + QCOMPARE(int(values.at(i).type), int(expectedValues.at(i).type)); + QCOMPARE(values.at(i).variant, expectedValues.at(i).variant); + } + } +} + +void tst_QCssParser::import() +{ + QCss::Parser parser("@import \"plainstring\";"); + QVERIFY(parser.testImport()); + QCss::ImportRule rule; + QVERIFY(parser.parseImport(&rule)); + QCOMPARE(rule.href, QString("plainstring")); + + parser = QCss::Parser("@import url(\"www.kde.org\") print/*comment*/,screen;"); + QVERIFY(parser.testImport()); + QVERIFY(parser.parseImport(&rule)); + QCOMPARE(rule.href, QString("www.kde.org")); + QCOMPARE(rule.media.count(), 2); + QCOMPARE(rule.media.at(0), QString("print")); + QCOMPARE(rule.media.at(1), QString("screen")); +} + +void tst_QCssParser::media() +{ + QCss::Parser parser("@media print/*comment*/,screen /*comment to ignore*/{ }"); + QVERIFY(parser.testMedia()); + QCss::MediaRule rule; + QVERIFY(parser.parseMedia(&rule)); + QCOMPARE(rule.media.count(), 2); + QCOMPARE(rule.media.at(0), QString("print")); + QCOMPARE(rule.media.at(1), QString("screen")); + QVERIFY(rule.styleRules.isEmpty()); +} + +void tst_QCssParser::page() +{ + QCss::Parser parser("@page :first/*comment to ignore*/{ }"); + QVERIFY(parser.testPage()); + QCss::PageRule rule; + QVERIFY(parser.parsePage(&rule)); + QCOMPARE(rule.selector, QString("first")); + QVERIFY(rule.declarations.isEmpty()); +} + +void tst_QCssParser::ruleset() +{ + { + QCss::Parser parser("p/*foo*/{ }"); + QVERIFY(parser.testRuleset()); + QCss::StyleRule rule; + QVERIFY(parser.parseRuleset(&rule)); + QCOMPARE(rule.selectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); + QVERIFY(rule.declarations.isEmpty()); + } + + { + QCss::Parser parser("p/*comment*/,div{ }"); + QVERIFY(parser.testRuleset()); + QCss::StyleRule rule; + QVERIFY(parser.parseRuleset(&rule)); + QCOMPARE(rule.selectors.count(), 2); + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); + QCOMPARE(rule.selectors.at(1).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).elementName, QString("div")); + QVERIFY(rule.declarations.isEmpty()); + } + + { + QCss::Parser parser(":before, :after { }"); + QVERIFY(parser.testRuleset()); + QCss::StyleRule rule; + QVERIFY(parser.parseRuleset(&rule)); + QCOMPARE(rule.selectors.count(), 2); + + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).pseudos.at(0).name, QString("before")); + + QCOMPARE(rule.selectors.at(1).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.count(), 1); + QCOMPARE(rule.selectors.at(1).basicSelectors.at(0).pseudos.at(0).name, QString("after")); + + QVERIFY(rule.declarations.isEmpty()); + } + +} + +Q_DECLARE_METATYPE(QCss::Selector) + +void tst_QCssParser::selector_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<QCss::Selector>("expectedSelector"); + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "p"; + basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfPreceeds; + sel.basicSelectors << basic; + + basic = QCss::BasicSelector(); + basic.elementName = "div"; + sel.basicSelectors << basic; + + QTest::newRow("comment") << QString("p/* */+ div") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = QString(); + sel.basicSelectors << basic; + + QTest::newRow("any") << QString("*") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + sel.basicSelectors << basic; + + QTest::newRow("element") << QString("e") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfAncestor; + sel.basicSelectors << basic; + + basic.elementName = "f"; + basic.relationToNext = QCss::BasicSelector::NoRelation; + sel.basicSelectors << basic; + + QTest::newRow("descendant") << QString("e f") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfParent; + sel.basicSelectors << basic; + + basic.elementName = "f"; + basic.relationToNext = QCss::BasicSelector::NoRelation; + sel.basicSelectors << basic; + + QTest::newRow("parent") << QString("e > f") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::Pseudo pseudo; + pseudo.name = "first-child"; + basic.pseudos.append(pseudo); + sel.basicSelectors << basic; + + QTest::newRow("first-child") << QString("e:first-child") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::Pseudo pseudo; + pseudo.name = "c"; + pseudo.function = "lang"; + basic.pseudos.append(pseudo); + sel.basicSelectors << basic; + + QTest::newRow("lang") << QString("e:lang(c)") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + basic.relationToNext = QCss::BasicSelector::MatchNextSelectorIfPreceeds; + sel.basicSelectors << basic; + + basic.elementName = "f"; + basic.relationToNext = QCss::BasicSelector::NoRelation; + sel.basicSelectors << basic; + + QTest::newRow("precede") << QString("e + f") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::AttributeSelector attrSel; + attrSel.name = "foo"; + basic.attributeSelectors << attrSel; + sel.basicSelectors << basic; + + QTest::newRow("attr") << QString("e[foo]") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::AttributeSelector attrSel; + attrSel.name = "foo"; + attrSel.value = "warning"; + attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchEqual; + basic.attributeSelectors << attrSel; + sel.basicSelectors << basic; + + QTest::newRow("attr-equal") << QString("e[foo=\"warning\"]") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::AttributeSelector attrSel; + attrSel.name = "foo"; + attrSel.value = "warning"; + attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchContains; + basic.attributeSelectors << attrSel; + sel.basicSelectors << basic; + + QTest::newRow("attr-contains") << QString("e[foo~=\"warning\"]") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + QCss::AttributeSelector attrSel; + attrSel.name = "lang"; + attrSel.value = "en"; + attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchBeginsWith; + basic.attributeSelectors << attrSel; + sel.basicSelectors << basic; + + QTest::newRow("attr-contains") << QString("e[lang|=\"en\"]") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "div"; + + QCss::AttributeSelector attrSel; + attrSel.name = "class"; + attrSel.valueMatchCriterium = QCss::AttributeSelector::MatchContains; + attrSel.value = "warning"; + basic.attributeSelectors.append(attrSel); + + attrSel.value = "foo"; + basic.attributeSelectors.append(attrSel); + + sel.basicSelectors << basic; + + QTest::newRow("class") << QString("div.warning.foo") << sel; + } + + { + QCss::Selector sel; + QCss::BasicSelector basic; + + basic.elementName = "e"; + basic.ids << "myid"; + sel.basicSelectors << basic; + + QTest::newRow("id") << QString("e#myid") << sel; + } +} + +void tst_QCssParser::selector() +{ + QFETCH(QString, css); + QFETCH(QCss::Selector, expectedSelector); + + QCss::Parser parser(css); + QVERIFY(parser.testSelector()); + QCss::Selector selector; + QVERIFY(parser.parseSelector(&selector)); + + QCOMPARE(selector.basicSelectors.count(), expectedSelector.basicSelectors.count()); + for (int i = 0; i < selector.basicSelectors.count(); ++i) { + const QCss::BasicSelector sel = selector.basicSelectors.at(i); + const QCss::BasicSelector expectedSel = expectedSelector.basicSelectors.at(i); + QCOMPARE(sel.elementName, expectedSel.elementName); + QCOMPARE(int(sel.relationToNext), int(expectedSel.relationToNext)); + + QCOMPARE(sel.pseudos.count(), expectedSel.pseudos.count()); + for (int i = 0; i < sel.pseudos.count(); ++i) { + QCOMPARE(sel.pseudos.at(i).name, expectedSel.pseudos.at(i).name); + QCOMPARE(sel.pseudos.at(i).function, expectedSel.pseudos.at(i).function); + } + + QCOMPARE(sel.attributeSelectors.count(), expectedSel.attributeSelectors.count()); + for (int i = 0; i < sel.attributeSelectors.count(); ++i) { + QCOMPARE(sel.attributeSelectors.at(i).name, expectedSel.attributeSelectors.at(i).name); + QCOMPARE(sel.attributeSelectors.at(i).value, expectedSel.attributeSelectors.at(i).value); + QCOMPARE(int(sel.attributeSelectors.at(i).valueMatchCriterium), int(expectedSel.attributeSelectors.at(i).valueMatchCriterium)); + } + } +} + +void tst_QCssParser::prio() +{ + { + QCss::Parser parser("!important"); + QVERIFY(parser.testPrio()); + } + { + QCss::Parser parser("!impOrTAnt"); + QVERIFY(parser.testPrio()); + } + { + QCss::Parser parser("!\"important\""); + QVERIFY(!parser.testPrio()); + QCOMPARE(parser.index, 0); + } + { + QCss::Parser parser("!importbleh"); + QVERIFY(!parser.testPrio()); + QCOMPARE(parser.index, 0); + } +} + +void tst_QCssParser::escapes() +{ + QCss::Parser parser("\\hello"); + parser.test(QCss::IDENT); + QCOMPARE(parser.lexem(), QString("hello")); +} + +void tst_QCssParser::malformedDeclarations_data() +{ + QTest::addColumn<QString>("css"); + + QTest::newRow("1") << QString("p { color:green }"); + QTest::newRow("2") << QString("p { color:green; color } /* malformed declaration missing ':', value */"); + QTest::newRow("3") << QString("p { color:red; color; color:green } /* same with expected recovery */"); + QTest::newRow("4") << QString("p { color:green; color: } /* malformed declaration missing value */"); + QTest::newRow("5") << QString("p { color:red; color:; color:green } /* same with expected recovery */"); + QTest::newRow("6") << QString("p { color:green; color{;color:maroon} } /* unexpected tokens { } */"); + QTest::newRow("7") << QString("p { color:red; color{;color:maroon}; color:green } /* same with recovery */"); +} + +void tst_QCssParser::malformedDeclarations() +{ + QFETCH(QString, css); + QCss::Parser parser(css); + QVERIFY(parser.testRuleset()); + QCss::StyleRule rule; + QVERIFY(parser.parseRuleset(&rule)); + + QCOMPARE(rule.selectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("p")); + + QVERIFY(rule.declarations.count() >= 1); + QCOMPARE(int(rule.declarations.last().d->propertyId), int(QCss::Color)); + QCOMPARE(rule.declarations.last().d->values.count(), 1); + QCOMPARE(int(rule.declarations.last().d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(rule.declarations.last().d->values.at(0).variant.toString(), QString("green")); +} + +void tst_QCssParser::invalidAtKeywords() +{ + QCss::Parser parser("" + "@three-dee {" + " @background-lighting {" + " azimuth: 30deg;" + " elevation: 190deg;" + " }" + " h1 { color: red }" + "}" + "h1 { color: blue }"); + + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + + QCOMPARE(rule.selectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.count(), 1); + QCOMPARE(rule.selectors.at(0).basicSelectors.at(0).elementName, QString("h1")); + + QCOMPARE(rule.declarations.count(), 1); + QCOMPARE(int(rule.declarations.at(0).d->propertyId), int(QCss::Color)); + QCOMPARE(rule.declarations.at(0).d->values.count(), 1); + QCOMPARE(int(rule.declarations.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(rule.declarations.at(0).d->values.at(0).variant.toString(), QString("blue")); +} + +Q_DECLARE_METATYPE(QColor) + +void tst_QCssParser::colorValue_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<QColor>("expectedColor"); + + QTest::newRow("identifier") << "color: black" << QColor("black"); + QTest::newRow("string") << "color: \"green\"" << QColor("green"); + QTest::newRow("hexcolor") << "color: #12af0e" << QColor(0x12, 0xaf, 0x0e); + QTest::newRow("functional1") << "color: rgb(21, 45, 73)" << QColor(21, 45, 73); + QTest::newRow("functional2") << "color: rgb(100%, 0%, 100%)" << QColor(0xff, 0, 0xff); + QTest::newRow("rgba") << "color: rgba(10, 20, 30, 40)" << QColor(10, 20, 30, 40); + QTest::newRow("rgb") << "color: rgb(10, 20, 30, 40)" << QColor(10, 20, 30, 40); + QTest::newRow("hsl") << "color: hsv(10, 20, 30)" << QColor::fromHsv(10, 20, 30, 255); + QTest::newRow("hsla") << "color: hsva(10, 20, 30, 40)" << QColor::fromHsv(10, 20, 30, 40); + QTest::newRow("invalid1") << "color: rgb(why, does, it, always, rain, on, me)" << QColor(); + QTest::newRow("invalid2") << "color: rgba(i, meant, norway)" << QColor(); + QTest::newRow("role") << "color: palette(base)" << qApp->palette().color(QPalette::Base); + QTest::newRow("role2") << "color: palette( window-text ) " << qApp->palette().color(QPalette::WindowText); + QTest::newRow("transparent") << "color: transparent" << QColor(Qt::transparent); +} + +void tst_QCssParser::colorValue() +{ + QFETCH(QString, css); + QFETCH(QColor, expectedColor); + + QCss::Parser parser(css); + QCss::Declaration decl; + QVERIFY(parser.parseNextDeclaration(&decl)); + const QColor col = decl.colorValue(); + QVERIFY(expectedColor.isValid() == col.isValid()); + QCOMPARE(col, expectedColor); +} + +class DomStyleSelector : public QCss::StyleSelector +{ +public: + inline DomStyleSelector(const QDomDocument &doc, const QCss::StyleSheet &sheet) + : doc(doc) + { + styleSheets.append(sheet); + } + + virtual QStringList nodeNames(NodePtr node) const { return QStringList(reinterpret_cast<QDomElement *>(node.ptr)->tagName()); } + virtual QString attribute(NodePtr node, const QString &name) const { return reinterpret_cast<QDomElement *>(node.ptr)->attribute(name); } + virtual bool hasAttribute(NodePtr node, const QString &name) const { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttribute(name); } + virtual bool hasAttributes(NodePtr node) const { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttributes(); } + + virtual bool isNullNode(NodePtr node) const { + return reinterpret_cast<QDomElement *>(node.ptr)->isNull(); + } + virtual NodePtr parentNode(NodePtr node) const { + NodePtr parent; + parent.ptr = new QDomElement(reinterpret_cast<QDomElement *>(node.ptr)->parentNode().toElement()); + return parent; + } + virtual NodePtr duplicateNode(NodePtr node) const { + NodePtr n; + n.ptr = new QDomElement(*reinterpret_cast<QDomElement *>(node.ptr)); + return n; + } + virtual NodePtr previousSiblingNode(NodePtr node) const { + NodePtr sibling; + sibling.ptr = new QDomElement(reinterpret_cast<QDomElement *>(node.ptr)->previousSiblingElement()); + return sibling; + } + virtual void freeNode(NodePtr node) const { + delete reinterpret_cast<QDomElement *>(node.ptr); + } + +private: + QDomDocument doc; +}; + +Q_DECLARE_METATYPE(QDomDocument) + +void tst_QCssParser::marginValue_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<QString>("expectedMargin"); + + QFont f; + int ex = QFontMetrics(f).xHeight(); + int em = QFontMetrics(f).height(); + + QTest::newRow("one value") << "margin: 1px" << "1 1 1 1"; + QTest::newRow("two values") << "margin: 1px 2px" << "1 2 1 2"; + QTest::newRow("three value") << "margin: 1px 2px 3px" << "1 2 3 2"; + QTest::newRow("four values") << "margin: 1px 2px 3px 4px" << "1 2 3 4"; + QTest::newRow("default px") << "margin: 1 2 3 4" << "1 2 3 4"; + QTest::newRow("no unit") << "margin: 1 2 3 4" << "1 2 3 4"; + QTest::newRow("em") << "margin: 1ex 2ex 3ex 4ex" << QString("%1 %2 %3 %4").arg(ex).arg(2*ex).arg(3*ex).arg(4*ex); + QTest::newRow("ex") << "margin: 1 2em 3px 4ex" << QString("%1 %2 %3 %4").arg(1).arg(2*em).arg(3).arg(4*ex); + + f.setPointSize(20); + f.setBold(true); + ex = QFontMetrics(f).xHeight(); + em = QFontMetrics(f).height(); + QTest::newRow("em2") << "font: bold 20pt; margin: 1ex 2ex 3ex 4ex" << QString("%1 %2 %3 %4").arg(ex).arg(2*ex).arg(3*ex).arg(4*ex); + QTest::newRow("ex2") << "margin: 1 2em 3px 4ex; font-size: 20pt; font-weight: bold;" << QString("%1 %2 %3 %4").arg(1).arg(2*em).arg(3).arg(4*ex); + + QTest::newRow("crap") << "margin: crap" << "0 0 0 0"; +} + +void tst_QCssParser::marginValue() +{ + QFETCH(QString, css); + QFETCH(QString, expectedMargin); + + QDomDocument doc; + QVERIFY(doc.setContent(QLatin1String("<!DOCTYPE test><test> <dummy/> </test>"))); + + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector<QCss::StyleRule> rules = testSelector.styleRulesForNode(n); + QVector<QCss::Declaration> decls = rules.at(0).declarations; + QCss::ValueExtractor v(decls); + + { + int m[4]; + int p[4]; + int spacing; + v.extractBox(m, p, &spacing); + QString str = QString("%1 %2 %3 %4").arg(m[0]).arg(m[1]).arg(m[2]).arg(m[3]); + QCOMPARE(str, expectedMargin); + } +} + +void tst_QCssParser::styleSelector_data() +{ + QTest::addColumn<bool>("match"); + QTest::addColumn<QString>("selector"); + QTest::addColumn<QString>("xml"); + QTest::addColumn<QString>("elementToCheck"); + + QTest::newRow("plain") << true << QString("p") << QString("<p />") << QString(); + QTest::newRow("noplain") << false << QString("bar") << QString("<p />") << QString(); + + QTest::newRow("class") << true << QString(".foo") << QString("<p class=\"foo\" />") << QString(); + QTest::newRow("noclass") << false << QString(".bar") << QString("<p class=\"foo\" />") << QString(); + + QTest::newRow("attrset") << true << QString("[justset]") << QString("<p justset=\"bar\" />") << QString(); + QTest::newRow("notattrset") << false << QString("[justset]") << QString("<p otherattribute=\"blub\" />") << QString(); + + QTest::newRow("attrmatch") << true << QString("[foo=bar]") << QString("<p foo=\"bar\" />") << QString(); + QTest::newRow("noattrmatch") << false << QString("[foo=bar]") << QString("<p foo=\"xyz\" />") << QString(); + + QTest::newRow("contains") << true << QString("[foo~=bar]") << QString("<p foo=\"baz bleh bar\" />") << QString(); + QTest::newRow("notcontains") << false << QString("[foo~=bar]") << QString("<p foo=\"test\" />") << QString(); + + QTest::newRow("beingswith") << true << QString("[foo|=bar]") << QString("<p foo=\"bar-bleh\" />") << QString(); + QTest::newRow("notbeingswith") << false << QString("[foo|=bar]") << QString("<p foo=\"bleh-bar\" />") << QString(); + + QTest::newRow("attr2") << true << QString("[bar=foo]") << QString("<p bleh=\"bar\" bar=\"foo\" />") << QString(); + + QTest::newRow("universal1") << true << QString("*") << QString("<p />") << QString(); + + QTest::newRow("universal3") << false << QString("*[foo=bar]") << QString("<p foo=\"bleh\" />") << QString(); + QTest::newRow("universal4") << true << QString("*[foo=bar]") << QString("<p foo=\"bar\" />") << QString(); + + QTest::newRow("universal5") << false << QString("[foo=bar]") << QString("<p foo=\"bleh\" />") << QString(); + QTest::newRow("universal6") << true << QString("[foo=bar]") << QString("<p foo=\"bar\" />") << QString(); + + QTest::newRow("universal7") << true << QString(".charfmt1") << QString("<p class=\"charfmt1\" />") << QString(); + + QTest::newRow("id") << true << QString("#blub") << QString("<p id=\"blub\" />") << QString(); + QTest::newRow("noid") << false << QString("#blub") << QString("<p id=\"other\" />") << QString(); + + QTest::newRow("childselector") << true << QString("parent > child") + << QString("<parent><child /></parent>") + << QString("parent/child"); + + QTest::newRow("nochildselector2") << false << QString("parent > child") + << QString("<child><parent /></child>") + << QString("child/parent"); + + QTest::newRow("nochildselector3") << false << QString("parent > child") + << QString("<parent><intermediate><child /></intermediate></parent>") + << QString("parent/intermediate/child"); + + QTest::newRow("childselector2") << true << QString("parent[foo=bar] > child") + << QString("<parent foo=\"bar\"><child /></parent>") + << QString("parent/child"); + + QTest::newRow("nochildselector4") << false << QString("parent[foo=bar] > child") + << QString("<parent><child /></parent>") + << QString("parent/child"); + + QTest::newRow("nochildselector5") << false << QString("parent[foo=bar] > child") + << QString("<parent foo=\"bar\"><parent><child /></parent></parent>") + << QString("parent/parent/child"); + + QTest::newRow("childselectors") << true << QString("grandparent > parent > child") + << QString("<grandparent><parent><child /></parent></grandparent>") + << QString("grandparent/parent/child"); + + QTest::newRow("descendant") << true << QString("grandparent child") + << QString("<grandparent><parent><child /></parent></grandparent>") + << QString("grandparent/parent/child"); + + QTest::newRow("nodescendant") << false << QString("grandparent child") + << QString("<other><parent><child /></parent></other>") + << QString("other/parent/child"); + + QTest::newRow("descendant2") << true << QString("grandgrandparent grandparent child") + << QString("<grandgrandparent><inbetween><grandparent><parent><child /></parent></grandparent></inbetween></grandgrandparent>") + << QString("grandgrandparent/inbetween/grandparent/parent/child"); + + QTest::newRow("combined") << true << QString("grandparent parent > child") + << QString("<grandparent><inbetween><parent><child /></parent></inbetween></grandparent>") + << QString("grandparent/inbetween/parent/child"); + + QTest::newRow("combined2") << true << QString("grandparent > parent child") + << QString("<grandparent><parent><inbetween><child /></inbetween></parent></grandparent>") + << QString("grandparent/parent/inbetween/child"); + + QTest::newRow("combined3") << true << QString("grandparent > parent child") + << QString("<grandparent><parent><inbetween><child /></inbetween></parent></grandparent>") + << QString("grandparent/parent/inbetween/child"); + + QTest::newRow("nocombined") << false << QString("grandparent parent > child") + << QString("<inbetween><parent><child /></parent></inbetween>") + << QString("inbetween/parent/child"); + + QTest::newRow("nocombined2") << false << QString("grandparent parent > child") + << QString("<parent><child /></parent>") + << QString("parent/child"); + + QTest::newRow("previoussibling") << true << QString("p1 + p2") + << QString("<p1 /><p2 />") + << QString("p2"); + + QTest::newRow("noprevioussibling") << false << QString("p2 + p1") + << QString("<p1 /><p2 />") + << QString("p2"); + + QTest::newRow("ancestry_firstmismatch") << false << QString("parent child[foo=bar]") + << QString("<parent><child /></parent>") + << QString("parent/child"); + + QTest::newRow("unknown-pseudo") << false << QString("p:enabled:foobar") << QString("<p/>") << QString(); +} + +void tst_QCssParser::styleSelector() +{ + QFETCH(bool, match); + QFETCH(QString, selector); + QFETCH(QString, xml); + QFETCH(QString, elementToCheck); + + QString css = QString("%1 { background-color: green }").arg(selector); + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QDomDocument doc; + xml.prepend("<!DOCTYPE test><test>"); + xml.append("</test>"); + QVERIFY(doc.setContent(xml)); + + DomStyleSelector testSelector(doc, sheet); + + QDomElement e = doc.documentElement(); + if (elementToCheck.isEmpty()) { + e = e.firstChildElement(); + } else { + QStringList path = elementToCheck.split(QLatin1Char('/')); + do { + e = e.namedItem(path.takeFirst()).toElement(); + } while (!path.isEmpty()); + } + QVERIFY(!e.isNull()); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector<QCss::Declaration> decls = testSelector.declarationsForNode(n); + + if (match) { + QCOMPARE(decls.count(), 1); + QCOMPARE(int(decls.at(0).d->propertyId), int(QCss::BackgroundColor)); + QCOMPARE(decls.at(0).d->values.count(), 1); + QCOMPARE(int(decls.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), QString("green")); + } else { + QVERIFY(decls.isEmpty()); + } +} + +void tst_QCssParser::specificity_data() +{ + QTest::addColumn<QString>("selector"); + QTest::addColumn<int>("specificity"); + + QTest::newRow("universal") << QString("*") << 0; + + QTest::newRow("elements+pseudos1") << QString("foo") << 1; + QTest::newRow("elements+pseudos2") << QString("foo *[blah]") << 1 + (1 * 0x10); + + // should strictly speaking be '2', but we don't support pseudo-elements yet, + // only pseudo-classes + QTest::newRow("elements+pseudos3") << QString("li:first-line") << 1 + (1 * 0x10); + + QTest::newRow("elements+pseudos4") << QString("ul li") << 2; + QTest::newRow("elements+pseudos5") << QString("ul ol+li") << 3; + QTest::newRow("elements+pseudos6") << QString("h1 + *[rel=up]") << 1 + (1 * 0x10); + + QTest::newRow("elements+pseudos7") << QString("ul ol li.red") << 3 + (1 * 0x10); + QTest::newRow("elements+pseudos8") << QString("li.red.level") << 1 + (2 * 0x10); + QTest::newRow("id") << QString("#x34y") << 1 * 0x100; +} + +void tst_QCssParser::specificity() +{ + QFETCH(QString, selector); + + QString css = QString("%1 { }").arg(selector); + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count() + sheet.idIndex.count() , 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? sheet.styleRules.at(0) + : (!sheet.nameIndex.isEmpty()) ? *sheet.nameIndex.begin() + : *sheet.idIndex.begin(); + QCOMPARE(rule.selectors.count(), 1); + QTEST(rule.selectors.at(0).specificity(), "specificity"); +} + +void tst_QCssParser::specificitySort_data() +{ + QTest::addColumn<QString>("firstSelector"); + QTest::addColumn<QString>("secondSelector"); + QTest::addColumn<QString>("xml"); + + QTest::newRow("universal1") << QString("*") << QString("p") << QString("<p />"); + QTest::newRow("attr") << QString("p") << QString("p[foo=bar]") << QString("<p foo=\"bar\" />"); + QTest::newRow("id") << QString("p") << QString("#hey") << QString("<p id=\"hey\" />"); + QTest::newRow("id2") << QString("[id=hey]") << QString("#hey") << QString("<p id=\"hey\" />"); + QTest::newRow("class") << QString("p") << QString(".hey") << QString("<p class=\"hey\" />"); +} + +void tst_QCssParser::specificitySort() +{ + QFETCH(QString, firstSelector); + QFETCH(QString, secondSelector); + QFETCH(QString, xml); + + firstSelector.append(" { color: green; }"); + secondSelector.append(" { color: red; }"); + + QDomDocument doc; + xml.prepend("<!DOCTYPE test><test>"); + xml.append("</test>"); + QVERIFY(doc.setContent(xml)); + + for (int i = 0; i < 2; ++i) { + QString css; + if (i == 0) + css = firstSelector + secondSelector; + else + css = secondSelector + firstSelector; + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector<QCss::Declaration> decls = testSelector.declarationsForNode(n); + + QCOMPARE(decls.count(), 2); + + QCOMPARE(int(decls.at(0).d->propertyId), int(QCss::Color)); + QCOMPARE(decls.at(0).d->values.count(), 1); + QCOMPARE(int(decls.at(0).d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), QString("green")); + + QCOMPARE(int(decls.at(1).d->propertyId), int(QCss::Color)); + QCOMPARE(decls.at(1).d->values.count(), 1); + QCOMPARE(int(decls.at(1).d->values.at(0).type), int(QCss::Value::Identifier)); + QCOMPARE(decls.at(1).d->values.at(0).variant.toString(), QString("red")); + } +} + +void tst_QCssParser::rulesForNode_data() +{ + QTest::addColumn<QString>("xml"); + QTest::addColumn<QString>("css"); + QTest::addColumn<quint64>("pseudoClass"); + QTest::addColumn<int>("declCount"); + QTest::addColumn<QString>("value0"); + QTest::addColumn<QString>("value1"); + + QTest::newRow("universal1") << QString("<p/>") << QString("* { color: red }") + << (quint64)QCss::PseudoClass_Unspecified << 1 << "red" << ""; + + QTest::newRow("basic") << QString("<p/>") << QString("p:enabled { color: red; bg:blue; }") + << (quint64)QCss::PseudoClass_Enabled << 2 << "red" << "blue"; + + QTest::newRow("single") << QString("<p/>") + << QString("p:enabled { color: red; } *:hover { color: white }") + << (quint64)QCss::PseudoClass_Hover << 1 << "white" << ""; + + QTest::newRow("multisel") << QString("<p/>") + << QString("p:enabled { color: red; } p:hover { color: gray } *:hover { color: white } ") + << (quint64)QCss::PseudoClass_Hover << 2 << "white" << "gray"; + + QTest::newRow("multisel2") << QString("<p/>") + << QString("p:enabled { color: red; } p:hover:focus { color: gray } *:hover { color: white } ") + << quint64(QCss::PseudoClass_Hover|QCss::PseudoClass_Focus) << 2 << "white" << "gray"; + + QTest::newRow("multisel3-diffspec") << QString("<p/>") + << QString("p:enabled { color: red; } p:hover:focus { color: gray } *:hover { color: white } ") + << quint64(QCss::PseudoClass_Hover) << 1 << "white" << ""; + + QTest::newRow("!-1") << QString("<p/>") + << QString("p:checked:!hover { color: red; } p:checked:hover { color: gray } p:checked { color: white }") + << quint64(QCss::PseudoClass_Hover|QCss::PseudoClass_Checked) << 2 << "white" << "gray"; + + QTest::newRow("!-2") << QString("<p/>") + << QString("p:checked:!hover:!pressed { color: red; } p:!checked:hover { color: gray } p:!focus { color: blue }") + << quint64(QCss::PseudoClass_Focus) << 0 << "" << ""; + + QTest::newRow("!-3") << QString("<p/>") + << QString("p:checked:!hover:!pressed { color: red; } p:!checked:hover { color: gray } p:!focus { color: blue; }") + << quint64(QCss::PseudoClass_Pressed) << 1 << "blue" << ""; +} + +void tst_QCssParser::rulesForNode() +{ + QFETCH(QString, xml); + QFETCH(QString, css); + QFETCH(quint64, pseudoClass); + QFETCH(int, declCount); + QFETCH(QString, value0); + QFETCH(QString, value1); + + QDomDocument doc; + xml.prepend("<!DOCTYPE test><test>"); + xml.append("</test>"); + QVERIFY(doc.setContent(xml)); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector<QCss::StyleRule> rules = testSelector.styleRulesForNode(n); + + QVector<QCss::Declaration> decls; + for (int i = 0; i < rules.count(); i++) { + const QCss::Selector &selector = rules.at(i).selectors.at(0); + quint64 negated = 0; + quint64 cssClass = selector.pseudoClass(&negated); + if ((cssClass == QCss::PseudoClass_Unspecified) + || ((((cssClass & pseudoClass) == cssClass)) && ((negated & pseudoClass) == 0))) + decls += rules.at(i).declarations; + } + + QVERIFY(decls.count() == declCount); + + if (declCount > 0) + QCOMPARE(decls.at(0).d->values.at(0).variant.toString(), value0); + if (declCount > 1) + QCOMPARE(decls.at(1).d->values.at(0).variant.toString(), value1); +} + +void tst_QCssParser::shorthandBackgroundProperty_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<QBrush>("expectedBrush"); + QTest::addColumn<QString>("expectedImage"); + QTest::addColumn<int>("expectedRepeatValue"); + QTest::addColumn<int>("expectedAlignment"); + + QTest::newRow("simple color") << "background: red" << QBrush(QColor("red")) << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("plain color") << "background-color: red" << QBrush(QColor("red")) << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("palette color") << "background-color: palette(mid)" << qApp->palette().mid() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("multiple") << "background: url(chess.png) blue repeat-y" << QBrush(QColor("blue")) << QString("chess.png") << int(QCss::Repeat_Y) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("plain alignment") << "background-position: center" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignCenter); + QTest::newRow("plain alignment2") << "background-position: left top" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignTop); + QTest::newRow("plain alignment3") << "background-position: left" << QBrush() << QString() << int(QCss::Repeat_XY) << int(Qt::AlignLeft | Qt::AlignVCenter); + QTest::newRow("multi") << "background: left url(blah.png) repeat-x" << QBrush() << QString("blah.png") << int(QCss::Repeat_X) << int(Qt::AlignLeft | Qt::AlignVCenter); + QTest::newRow("multi2") << "background: url(blah.png) repeat-x top" << QBrush() << QString("blah.png") << int(QCss::Repeat_X) << int(Qt::AlignTop | Qt::AlignHCenter); + QTest::newRow("multi3") << "background: url(blah.png) top right" << QBrush() << QString("blah.png") << int(QCss::Repeat_XY) << int(Qt::AlignTop | Qt::AlignRight); +} + +void tst_QCssParser::shorthandBackgroundProperty() +{ + QFETCH(QString, css); + + QDomDocument doc; + QVERIFY(doc.setContent(QLatin1String("<!DOCTYPE test><test> <dummy/> </test>"))); + + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector<QCss::StyleRule> rules = testSelector.styleRulesForNode(n); + QVector<QCss::Declaration> decls = rules.at(0).declarations; + QCss::ValueExtractor v(decls); + + QBrush brush; + QString image; + QCss::Repeat repeat = QCss::Repeat_XY; + Qt::Alignment alignment = Qt::AlignTop | Qt::AlignLeft; + QCss::Origin origin = QCss::Origin_Padding; + QCss::Attachment attachment; + QCss::Origin ignoredOrigin; + v.extractBackground(&brush, &image, &repeat, &alignment, &origin, &attachment, &ignoredOrigin); + + QFETCH(QBrush, expectedBrush); + QVERIFY(expectedBrush.color() == brush.color()); + + QTEST(image, "expectedImage"); + QTEST(int(repeat), "expectedRepeatValue"); + QTEST(int(alignment), "expectedAlignment"); + + //QTBUG-9674 : a second evaluation should give the same results + QVERIFY(v.extractBackground(&brush, &image, &repeat, &alignment, &origin, &attachment, &ignoredOrigin)); + QVERIFY(expectedBrush.color() == brush.color()); + QTEST(image, "expectedImage"); + QTEST(int(repeat), "expectedRepeatValue"); + QTEST(int(alignment), "expectedAlignment"); +} + +void tst_QCssParser::pseudoElement_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<QString>("pseudoElement"); + QTest::addColumn<int>("declCount"); + + // QComboBox::dropDown { border-image: blah; } + QTest::newRow("no pseudo-elements") << QString("dummy:hover { color: red }") << "" << 1; + QTest::newRow("no pseudo-elements") << QString("dummy:hover { color: red }") << "pe" << 0; + + QTest::newRow("1 pseudo-element (1)") << QString("dummy::pe:hover { color: red }") << "pe" << 1; + QTest::newRow("1 pseudo-element (2)") << QString("dummy::pe:hover { color: red }") << "x" << 0; + QTest::newRow("1 pseudo-element (2)") << QString("whatever::pe:hover { color: red }") << "pe" << 0; + + QTest::newRow("1 pseudo-element (3)") + << QString("dummy { color: white; } dummy::pe:hover { color: red }") << "x" << 0; + QTest::newRow("1 pseudo-element (4)") + << QString("dummy { color: white; } dummy::pe:hover { color: red } dummy { x:y }") << "" << 2; + QTest::newRow("1 pseudo-element (5)") + << QString("dummy { color: white; } dummy::pe:hover { color: red }") << "pe" << 1; + QTest::newRow("1 pseudo-element (6)") + << QString("dummy { color: white; } dummy::pe:hover { color: red } dummy::pe:checked { x: y} ") << "pe" << 2; + + QTest::newRow("2 pseudo-elements (1)") + << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") + << "" << 1; + QTest::newRow("2 pseudo-elements (1)") + << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") + << "pe1" << 1; + QTest::newRow("2 pseudo-elements (2)") + << QString("dummy { color: white; } dummy::pe1:hover { color: red } dummy::pe2:checked { x: y} ") + << "pe2" << 1; +} + +void tst_QCssParser::pseudoElement() +{ + QFETCH(QString, css); + QFETCH(QString, pseudoElement); + QFETCH(int, declCount); + + QDomDocument doc; + QVERIFY(doc.setContent(QLatin1String("<!DOCTYPE test><test> <dummy/> </test>"))); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector<QCss::StyleRule> rules = testSelector.styleRulesForNode(n); + QVector<QCss::Declaration> decls; + for (int i = 0; i < rules.count(); i++) { + const QCss::Selector& selector = rules.at(i).selectors.at(0); + if (pseudoElement.compare(selector.pseudoElement(), Qt::CaseInsensitive) != 0) + continue; + decls += rules.at(i).declarations; + + } + QVERIFY(decls.count() == declCount); +} + +void tst_QCssParser::gradient_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<QString>("type"); + QTest::addColumn<QPointF>("start"); + QTest::addColumn<QPointF>("finalStop"); + QTest::addColumn<int>("spread"); + QTest::addColumn<qreal>("stop0"); + QTest::addColumn<QColor>("color0"); + QTest::addColumn<qreal>("stop1"); + QTest::addColumn<QColor>("color1"); + + QTest::newRow("color-string") << + "selection-background-color: qlineargradient(x1:1, y1:2, x2:3, y2:4, " + "stop:0.2 red, stop:0.5 green)" << "linear" << QPointF(1, 2) << QPointF(3, 4) + << 0 << qreal(0.2) << QColor("red") << qreal(0.5) << QColor("green"); + + QTest::newRow("color-#") << + "selection-background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + "spread: reflect, stop:0.2 #123, stop:0.5 #456)" << "linear" << QPointF(0, 0) << QPointF(0, 1) + << 1 << qreal(0.2) << QColor("#123") << qreal(0.5) << QColor("#456"); + + QTest::newRow("color-rgb") << + "selection-background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + "spread: reflect, stop:0.2 rgb(1, 2, 3), stop:0.5 rgba(1, 2, 3, 4))" << "linear" << QPointF(0, 0) << QPointF(0, 1) + << 1 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); + + QTest::newRow("color-spaces") << + "selection-background-color: qlineargradient(x1: 0, y1 :0,x2:0, y2 : 1 , " + "spread: reflect, stop:0.2 rgb(1, 2, 3), stop: 0.5 rgba(1, 2, 3, 4))" << "linear" << QPointF(0, 0) << QPointF(0, 1) + << 1 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); + + QTest::newRow("conical gradient") << + "selection-background-color: qconicalgradient(cx: 4, cy : 2, angle: 23, " + "spread: repeat, stop:0.2 rgb(1, 2, 3), stop:0.5 rgba(1, 2, 3, 4))" << "conical" << QPointF(4, 2) << QPointF() + << 2 << qreal(0.2) << QColor(1, 2, 3) << qreal(0.5) << QColor(1, 2, 3, 4); + + /* wont pass: stop values are expected to be sorted + QTest::newRow("unsorted-stop") << + "selection-background: lineargradient(x1:0, y1:0, x2:0, y2:1, " + "stop:0.5 green, stop:0.2 red)" << QPointF(0, 0) << QPointF(0, 1) + 0 << 0.2 << QColor("red") << 0.5 << QColor("green"); + */ +} + +void tst_QCssParser::gradient() +{ + QFETCH(QString, css); + QFETCH(QString, type); + QFETCH(QPointF, finalStop); + QFETCH(QPointF, start); + QFETCH(int, spread); + QFETCH(qreal, stop0); QFETCH(QColor, color0); + QFETCH(qreal, stop1); QFETCH(QColor, color1); + + QDomDocument doc; + QVERIFY(doc.setContent(QLatin1String("<!DOCTYPE test><test> <dummy/> </test>"))); + + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + DomStyleSelector testSelector(doc, sheet); + QDomElement e = doc.documentElement().firstChildElement(); + QCss::StyleSelector::NodePtr n; + n.ptr = &e; + QVector<QCss::StyleRule> rules = testSelector.styleRulesForNode(n); + QVector<QCss::Declaration> decls = rules.at(0).declarations; + QCss::ValueExtractor ve(decls); + QBrush fg, sfg; + QBrush sbg, abg; + QVERIFY(ve.extractPalette(&fg, &sfg, &sbg, &abg)); + if (type == "linear") { + QVERIFY(sbg.style() == Qt::LinearGradientPattern); + const QLinearGradient *lg = static_cast<const QLinearGradient *>(sbg.gradient()); + QCOMPARE(lg->start(), start); + QCOMPARE(lg->finalStop(), finalStop); + } else if (type == "conical") { + QVERIFY(sbg.style() == Qt::ConicalGradientPattern); + const QConicalGradient *cg = static_cast<const QConicalGradient *>(sbg.gradient()); + QCOMPARE(cg->center(), start); + } + const QGradient *g = sbg.gradient(); + QCOMPARE(g->spread(), QGradient::Spread(spread)); + QVERIFY(g->stops().at(0).first == stop0); + QVERIFY(g->stops().at(0).second == color0); + QVERIFY(g->stops().at(1).first == stop1); + QVERIFY(g->stops().at(1).second == color1); +} + +void tst_QCssParser::extractFontFamily_data() +{ + if (QFontInfo(QFont("Times New Roman")).family() != "Times New Roman") + QSKIP("'Times New Roman' font not found ", SkipAll); + + QTest::addColumn<QString>("css"); + QTest::addColumn<QString>("expectedFamily"); + + QTest::newRow("quoted-family-name") << "font-family: 'Times New Roman'" << QString("Times New Roman"); + QTest::newRow("unquoted-family-name") << "font-family: Times New Roman" << QString("Times New Roman"); + QTest::newRow("unquoted-family-name2") << "font-family: Times New Roman" << QString("Times New Roman"); + QTest::newRow("multiple") << "font-family: Times New Roman , foobar, 'baz'" << QString("Times New Roman"); + QTest::newRow("multiple2") << "font-family: invalid, Times New Roman " << QString("Times New Roman"); + QTest::newRow("invalid") << "font-family: invalid" << QFontInfo(QFont("invalid font")).family(); + QTest::newRow("shorthand") << "font: 12pt Times New Roman" << QString("Times New Roman"); + QTest::newRow("shorthand multiple quote") << "font: 12pt invalid, \"Times New Roman\" " << QString("Times New Roman"); + QTest::newRow("shorthand multiple") << "font: 12pt invalid, Times New Roman " << QString("Times New Roman"); + QTest::newRow("invalid spaces") << "font-family: invalid spaces, Times New Roman " << QString("Times New Roman"); + QTest::newRow("invalid spaces quotes") << "font-family: 'invalid spaces', 'Times New Roman' " << QString("Times New Roman"); +} + + +void tst_QCssParser::extractFontFamily() +{ + QFETCH(QString, css); + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + + const QVector<QCss::Declaration> decls = rule.declarations; + QVERIFY(!decls.isEmpty()); + QCss::ValueExtractor extractor(decls); + + int adjustment = 0; + QFont fnt; + extractor.extractFont(&fnt, &adjustment); + QFontInfo info(fnt); + +#ifdef Q_WS_QPA + // Note, we have to QSKIP rather than QEXPECT_FAIL because font lookup is broken + // such that it may work or not work depending on the order in which fonts were + // loaded from disk + QSKIP("QTBUG-20986 may fail on qpa", SkipSingle); +#endif + + QTEST(info.family(), "expectedFamily"); +} + +void tst_QCssParser::extractBorder_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<int>("expectedTopWidth"); + QTest::addColumn<int>("expectedTopStyle"); + QTest::addColumn<QColor>("expectedTopColor"); + + QTest::newRow("all values") << "border: 2px solid green" << 2 << (int)QCss::BorderStyle_Solid << QColor("green"); + QTest::newRow("palette") << "border: 2px solid palette(highlight)" << 2 << (int)QCss::BorderStyle_Solid << qApp->palette().color(QPalette::Highlight); + QTest::newRow("just width") << "border: 2px" << 2 << (int)QCss::BorderStyle_None << QColor(); + QTest::newRow("just style") << "border: solid" << 0 << (int)QCss::BorderStyle_Solid << QColor(); + QTest::newRow("just color") << "border: green" << 0 << (int)QCss::BorderStyle_None << QColor("green"); + QTest::newRow("width+style") << "border: 2px solid" << 2 << (int)QCss::BorderStyle_Solid << QColor(); + QTest::newRow("style+color") << "border: solid green" << 0 << (int)QCss::BorderStyle_Solid << QColor("green"); + QTest::newRow("width+color") << "border: 3px green" << 3 << (int)QCss::BorderStyle_None << QColor("green"); + QTest::newRow("groove style") << "border: groove" << 0 << (int)QCss::BorderStyle_Groove << QColor(); + QTest::newRow("ridge style") << "border: ridge" << 0 << (int)QCss::BorderStyle_Ridge << QColor(); + QTest::newRow("double style") << "border: double" << 0 << (int)QCss::BorderStyle_Double << QColor(); + QTest::newRow("inset style") << "border: inset" << 0 << (int)QCss::BorderStyle_Inset << QColor(); + QTest::newRow("outset style") << "border: outset" << 0 << (int)QCss::BorderStyle_Outset << QColor(); + QTest::newRow("dashed style") << "border: dashed" << 0 << (int)QCss::BorderStyle_Dashed << QColor(); + QTest::newRow("dotted style") << "border: dotted" << 0 << (int)QCss::BorderStyle_Dotted << QColor(); + QTest::newRow("dot-dash style") << "border: dot-dash" << 0 << (int)QCss::BorderStyle_DotDash << QColor(); + QTest::newRow("dot-dot-dash style") << "border: dot-dot-dash" << 0 << (int)QCss::BorderStyle_DotDotDash << QColor(); + + QTest::newRow("top-width+color") << "border-top: 3px green" << 3 << (int)QCss::BorderStyle_None << QColor("green"); +} + +void tst_QCssParser::extractBorder() +{ + QFETCH(QString, css); + QFETCH(int, expectedTopWidth); + QFETCH(int, expectedTopStyle); + QFETCH(QColor, expectedTopColor); + + css.prepend("dummy {"); + css.append("}"); + + QCss::Parser parser(css); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + const QVector<QCss::Declaration> decls = rule.declarations; + QVERIFY(!decls.isEmpty()); + QCss::ValueExtractor extractor(decls); + + int widths[4]; + QBrush colors[4]; + QCss::BorderStyle styles[4]; + QSize radii[4]; + + extractor.extractBorder(widths, colors, styles, radii); + QVERIFY(widths[QCss::TopEdge] == expectedTopWidth); + QVERIFY(styles[QCss::TopEdge] == expectedTopStyle); + QVERIFY(colors[QCss::TopEdge] == expectedTopColor); + + //QTBUG-9674 : a second evaluation should give the same results + QVERIFY(extractor.extractBorder(widths, colors, styles, radii)); + QVERIFY(widths[QCss::TopEdge] == expectedTopWidth); + QVERIFY(styles[QCss::TopEdge] == expectedTopStyle); + QVERIFY(colors[QCss::TopEdge] == expectedTopColor); +} + +void tst_QCssParser::noTextDecoration() +{ + QCss::Parser parser("dummy { text-decoration: none; }"); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + const QVector<QCss::Declaration> decls = rule.declarations; + QVERIFY(!decls.isEmpty()); + QCss::ValueExtractor extractor(decls); + + int adjustment = 0; + QFont f; + f.setUnderline(true); + f.setOverline(true); + f.setStrikeOut(true); + QVERIFY(extractor.extractFont(&f, &adjustment)); + + QVERIFY(!f.underline()); + QVERIFY(!f.overline()); + QVERIFY(!f.strikeOut()); +} + +void tst_QCssParser::quotedAndUnquotedIdentifiers() +{ + QCss::Parser parser("foo { font-style: \"italic\"; font-weight: bold }"); + QCss::StyleSheet sheet; + QVERIFY(parser.parse(&sheet)); + + QCOMPARE(sheet.styleRules.count() + sheet.nameIndex.count(), 1); + QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ? + sheet.styleRules.at(0) : *sheet.nameIndex.begin(); + const QVector<QCss::Declaration> decls = rule.declarations; + QCOMPARE(decls.size(), 2); + + QCOMPARE(decls.at(0).d->values.first().type, QCss::Value::String); + QCOMPARE(decls.at(0).d->property, QLatin1String("font-style")); + QCOMPARE(decls.at(0).d->values.first().toString(), QLatin1String("italic")); + + QCOMPARE(decls.at(1).d->values.first().type, QCss::Value::KnownIdentifier); + QCOMPARE(decls.at(1).d->property, QLatin1String("font-weight")); + QCOMPARE(decls.at(1).d->values.first().toString(), QLatin1String("bold")); +} + +QTEST_MAIN(tst_QCssParser) +#include "tst_qcssparser.moc" + diff --git a/tests/auto/gui/text/qfont/.gitignore b/tests/auto/gui/text/qfont/.gitignore new file mode 100644 index 0000000000..61aa3df16c --- /dev/null +++ b/tests/auto/gui/text/qfont/.gitignore @@ -0,0 +1 @@ +tst_qfont diff --git a/tests/auto/gui/text/qfont/qfont.pro b/tests/auto/gui/text/qfont/qfont.pro new file mode 100644 index 0000000000..891cb0a093 --- /dev/null +++ b/tests/auto/gui/text/qfont/qfont.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qfont.cpp + + diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp new file mode 100644 index 0000000000..a564e71e19 --- /dev/null +++ b/tests/auto/gui/text/qfont/tst_qfont.cpp @@ -0,0 +1,629 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <qfont.h> +#include <qfontdatabase.h> +#include <qfontinfo.h> +#include <qstringlist.h> +#include <qapplication.h> +#include <qwidget.h> +#include <qlist.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFont : public QObject +{ +Q_OBJECT + +public: + tst_QFont(); + virtual ~tst_QFont(); + +public slots: + void init(); + void cleanup(); +private slots: + void getSetCheck(); + void exactMatch(); + void compare(); + void resolve(); + void resetFont(); + void isCopyOf(); + void setFontRaw(); + void italicOblique(); + void insertAndRemoveSubstitutions(); + void serializeSpacing(); + void lastResortFont(); + void styleName(); +}; + +// Testing get/set functions +void tst_QFont::getSetCheck() +{ + QFont obj1; + // Style QFont::style() + // void QFont::setStyle(Style) + obj1.setStyle(QFont::Style(QFont::StyleNormal)); + QCOMPARE(QFont::Style(QFont::StyleNormal), obj1.style()); + obj1.setStyle(QFont::Style(QFont::StyleItalic)); + QCOMPARE(QFont::Style(QFont::StyleItalic), obj1.style()); + obj1.setStyle(QFont::Style(QFont::StyleOblique)); + QCOMPARE(QFont::Style(QFont::StyleOblique), obj1.style()); + + // StyleStrategy QFont::styleStrategy() + // void QFont::setStyleStrategy(StyleStrategy) + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferDefault)); + QCOMPARE(QFont::StyleStrategy(QFont::PreferDefault), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferBitmap)); + QCOMPARE(QFont::StyleStrategy(QFont::PreferBitmap), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferDevice)); + QCOMPARE(QFont::StyleStrategy(QFont::PreferDevice), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferOutline)); + QCOMPARE(QFont::StyleStrategy(QFont::PreferOutline), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::ForceOutline)); + QCOMPARE(QFont::StyleStrategy(QFont::ForceOutline), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferMatch)); + QCOMPARE(QFont::StyleStrategy(QFont::PreferMatch), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferQuality)); + QCOMPARE(QFont::StyleStrategy(QFont::PreferQuality), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferAntialias)); + QCOMPARE(QFont::StyleStrategy(QFont::PreferAntialias), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::NoAntialias)); + QCOMPARE(QFont::StyleStrategy(QFont::NoAntialias), obj1.styleStrategy()); + obj1.setStyleStrategy(QFont::StyleStrategy(QFont::OpenGLCompatible)); + QCOMPARE(QFont::StyleStrategy(QFont::OpenGLCompatible), obj1.styleStrategy()); +} + +tst_QFont::tst_QFont() +{ +} + +tst_QFont::~tst_QFont() +{ + +} + +void tst_QFont::init() +{ +// TODO: Add initialization code here. +// This will be executed immediately before each test is run. +} + +void tst_QFont::cleanup() +{ +// TODO: Add cleanup code here. +// This will be executed immediately after each test is run. +} + +void tst_QFont::exactMatch() +{ + QFont font; + + // Check if a non-existing font hasn't an exact match + font = QFont( "BogusFont", 33 ); + QVERIFY( !font.exactMatch() ); + +#ifdef Q_WS_WIN + QSKIP("Exact matching on windows misses a lot because of the sample chars", SkipAll); + return; +#endif + +#ifdef Q_WS_X11 + QVERIFY(QFont("sans").exactMatch()); + QVERIFY(QFont("sans-serif").exactMatch()); + QVERIFY(QFont("serif").exactMatch()); + QVERIFY(QFont("monospace").exactMatch()); +#endif + + QSKIP("This test is bogus on Unix with support for font aliases in fontconfig", SkipAll); + return; + + QFontDatabase fdb; + + QList<QFontDatabase::WritingSystem> systems = fdb.writingSystems(); + for (int system = 0; system < systems.count(); ++system) { + QStringList families = fdb.families(systems[system]); + if (families.isEmpty()) + return; + + QStringList::ConstIterator f_it, f_end = families.end(); + for (f_it = families.begin(); f_it != f_end; ++f_it) { + const QString &family = *f_it; + if (family.contains('[')) + continue; + + QStringList styles = fdb.styles(family); + QVERIFY(!styles.isEmpty()); + QStringList::ConstIterator s_it, s_end = styles.end(); + for (s_it = styles.begin(); s_it != s_end; ++s_it) { + const QString &style = *s_it; + + if (fdb.isSmoothlyScalable(family, style)) { + // smoothly scalable font... don't need to load every pointsize + font = fdb.font(family, style, 12); + QFontInfo fontinfo(font); + + if (! fontinfo.exactMatch()) { + // Unfortunately, this can fail, since + // QFontDatabase does not fill in all font + // properties. Check to make sure that the + // test didn't fail for obvious reasons + + if (fontinfo.family().isEmpty() + && fontinfo.pointSize() == 0) { + // this is a box rendering engine... this can happen from + // time to time, especially on X11 with iso10646-1 or + // unknown font encodings + continue; + } + +#ifdef Q_WS_WIN32 + if (font.family().startsWith("MS ") || fontinfo.family().startsWith("MS ")) { + /* qDebug("Family matching skipped for MS-Alias font: %s, fontinfo: %s", + font.family().latin1(), fontinfo.family().latin1()); + */ + } else +#endif + { + if (!(font.family() == fontinfo.family() + || fontinfo.family().contains(font.family()) + || fontinfo.family().isEmpty())) { + qDebug("Test about to fail for font: %s, fontinfo: %s", + font.family().toLatin1().constData(), + fontinfo.family().toLatin1().constData()); + } + QVERIFY(font.family() == fontinfo.family() + || fontinfo.family().contains(font.family()) + || fontinfo.family().isEmpty()); + } + if (font.pointSize() != -1) { + QVERIFY(font.pointSize() == fontinfo.pointSize()); + } else { + QVERIFY(font.pixelSize() == fontinfo.pixelSize()); + } + QVERIFY(font.italic() == fontinfo.italic()); + if (font.weight() != fontinfo.weight()) { + qDebug("font is %s", font.toString().toLatin1().constData()); + } + QVERIFY(font.weight() == fontinfo.weight()); + } else { + font.setFixedPitch(!fontinfo.fixedPitch()); + QFontInfo fontinfo1(font); + QVERIFY( !fontinfo1.exactMatch() ); + + font.setFixedPitch(fontinfo.fixedPitch()); + QFontInfo fontinfo2(font); + QVERIFY( fontinfo2.exactMatch() ); + } + } +#if 0 + // ############## can only work if we have float point sizes in QFD + else { + QList<int> sizes = fdb.pointSizes(family, style); + QVERIFY(!sizes.isEmpty()); + QList<int>::ConstIterator z_it, z_end = sizes.end(); + for (z_it = sizes.begin(); z_it != z_end; ++z_it) { + const int size = *z_it; + + // Initialize the font, and check if it is an exact match + font = fdb.font(family, style, size); + QFontInfo fontinfo(font, (QFont::Script) script); + + if (! fontinfo.exactMatch()) { + // Unfortunately, this can fail, since + // QFontDatabase does not fill in all font + // properties. Check to make sure that the + // test didn't fail for obvious reasons + + if (fontinfo.family().isEmpty() + && fontinfo.pointSize() == 0) { + // this is a box rendering engine... this can happen from + // time to time, especially on X11 with iso10646-1 or + // unknown font encodings + continue; + } + + // no need to skip MS-fonts here it seems + if (!(font.family() == fontinfo.family() + || fontinfo.family().contains(font.family()) + || fontinfo.family().isEmpty())) { + qDebug("Test about to fail for font: %s, fontinfo: %s", + font.family().latin1(), fontinfo.family().latin1()); + } + QVERIFY(font.family() == fontinfo.family() + || fontinfo.family().contains(font.family()) + || fontinfo.family().isEmpty()); + if (font.pointSize() != -1) { + QVERIFY(font.pointSize() == fontinfo.pointSize()); + } else { + QVERIFY(font.pixelSize() == fontinfo.pixelSize()); + } + QVERIFY(font.italic() == fontinfo.italic()); + QVERIFY(font.weight() == fontinfo.weight()); + } else { + font.setFixedPitch(!fontinfo.fixedPitch()); + QFontInfo fontinfo1(font, (QFont::Script) script); + QVERIFY( !fontinfo1.exactMatch() ); + + font.setFixedPitch(fontinfo.fixedPitch()); + QFontInfo fontinfo2(font, (QFont::Script) script); + QVERIFY( fontinfo2.exactMatch() ); + } + } + } +#endif + } + } + } +} + +void tst_QFont::italicOblique() +{ + QFontDatabase fdb; + + QStringList families = fdb.families(); + if (families.isEmpty()) + return; + + QStringList::ConstIterator f_it, f_end = families.end(); + for (f_it = families.begin(); f_it != f_end; ++f_it) { + + QString family = *f_it; + QStringList styles = fdb.styles(family); + QVERIFY(!styles.isEmpty()); + QStringList::ConstIterator s_it, s_end = styles.end(); + for (s_it = styles.begin(); s_it != s_end; ++s_it) { + QString style = *s_it; + + if (fdb.isSmoothlyScalable(family, style)) { + if (style.contains("Oblique")) { + style.replace("Oblique", "Italic"); + } else if (style.contains("Italic")) { + style.replace("Italic", "Oblique"); + } else { + continue; + } + QFont f = fdb.font(family, style, 12); + QVERIFY(f.italic()); + } + } + } +} + +void tst_QFont::compare() +{ + QFont font; + { + QFont font2 = font; + font2.setPointSize( 24 ); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + } + { + QFont font2 = font; + font2.setPixelSize( 24 ); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + } + + font.setPointSize(12); + font.setItalic(false); + font.setWeight(QFont::Normal); + font.setUnderline(false); + font.setStrikeOut(false); + font.setOverline(false); + { + QFont font2 = font; + font2.setPointSize( 24 ); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + } + { + QFont font2 = font; + font2.setPixelSize( 24 ); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + } + { + QFont font2 = font; + + font2.setItalic(true); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + font2.setItalic(false); + QVERIFY( font == font2 ); + QVERIFY(!(font < font2)); + + font2.setWeight(QFont::Bold); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + font2.setWeight(QFont::Normal); + QVERIFY( font == font2 ); + QVERIFY(!(font < font2)); + + font.setUnderline(true); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + font.setUnderline(false); + QVERIFY( font == font2 ); + QVERIFY(!(font < font2)); + + font.setStrikeOut(true); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + font.setStrikeOut(false); + QVERIFY( font == font2 ); + QVERIFY(!(font < font2)); + + font.setOverline(true); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + font.setOverline(false); + QVERIFY( font == font2 ); + QVERIFY(!(font < font2)); + + font.setCapitalization(QFont::SmallCaps); + QVERIFY( font != font2 ); + QCOMPARE(font < font2,!(font2 < font)); + font.setCapitalization(QFont::MixedCase); + QVERIFY( font == font2 ); + QVERIFY(!(font < font2)); + } + +#if defined(Q_WS_X11) + { + QFont font1, font2; + font1.setRawName("-Adobe-Helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1"); + font2.setRawName("-Adobe-Helvetica-medium-r-normal--24-240-75-75-p-130-iso8859-1"); + QVERIFY(font1 != font2); + } +#endif +} + +void tst_QFont::resolve() +{ + QFont font; + font.setPointSize(font.pointSize() * 2); + font.setItalic(false); + font.setWeight(QFont::Normal); + font.setUnderline(false); + font.setStrikeOut(false); + font.setOverline(false); + font.setStretch(QFont::Unstretched); + + QFont font1; + font1.setWeight(QFont::Bold); + QFont font2 = font1.resolve(font); + + QVERIFY(font2.weight() == font1.weight()); + + QVERIFY(font2.pointSize() == font.pointSize()); + QVERIFY(font2.italic() == font.italic()); + QVERIFY(font2.underline() == font.underline()); + QVERIFY(font2.overline() == font.overline()); + QVERIFY(font2.strikeOut() == font.strikeOut()); + QVERIFY(font2.stretch() == font.stretch()); + + QFont font3; + font3.setStretch(QFont::UltraCondensed); + QFont font4 = font3.resolve(font1).resolve(font); + + QVERIFY(font4.stretch() == font3.stretch()); + + QVERIFY(font4.weight() == font.weight()); + QVERIFY(font4.pointSize() == font.pointSize()); + QVERIFY(font4.italic() == font.italic()); + QVERIFY(font4.underline() == font.underline()); + QVERIFY(font4.overline() == font.overline()); + QVERIFY(font4.strikeOut() == font.strikeOut()); + + + QFont f1,f2,f3; + f2.setPointSize(45); + f3.setPointSize(55); + + QFont f4 = f1.resolve(f2); + QCOMPARE(f4.pointSize(), 45); + f4 = f4.resolve(f3); + QCOMPARE(f4.pointSize(), 55); +} + +void tst_QFont::resetFont() +{ + QWidget parent; + QFont parentFont = parent.font(); + parentFont.setPointSize(parentFont.pointSize() + 2); + parent.setFont(parentFont); + + QWidget *child = new QWidget(&parent); + + QFont childFont = child->font(); + childFont.setBold(!childFont.bold()); + child->setFont(childFont); + + QVERIFY(parentFont.resolve() != 0); + QVERIFY(childFont.resolve() != 0); + QVERIFY(childFont != parentFont); + + child->setFont(QFont()); // reset font + + QVERIFY(child->font().resolve() == 0); + QVERIFY(child->font().pointSize() == parent.font().pointSize()); + QVERIFY(parent.font().resolve() != 0); +} + +void tst_QFont::isCopyOf() +{ + QFont font; + QVERIFY(font.isCopyOf(QApplication::font())); + + QFont font2("bogusfont", 23); + QVERIFY(! font2.isCopyOf(QApplication::font())); + + QFont font3 = font; + QVERIFY(font3.isCopyOf(font)); + + font3.setPointSize(256); + QVERIFY(!font3.isCopyOf(font)); + font3.setPointSize(font.pointSize()); + QVERIFY(!font3.isCopyOf(font)); +} + +void tst_QFont::setFontRaw() +{ +#ifndef Q_WS_X11 + QSKIP("Only tested on X11", SkipAll); +#else + QFont f; + f.setRawName("-*-fixed-bold-r-normal--0-0-*-*-*-0-iso8859-1"); +// qDebug("font family: %s", f.family().utf8()); + QFontDatabase fdb; + QStringList families = fdb.families(); + bool found = false; + for (int i = 0; i < families.size(); ++i) { + QString str = families.at(i); + if (str.contains('[')) + str = str.left(str.indexOf('[')-1); + if (str.toLower() == "fixed") + found = true; + } + if (!found) { + QSKIP("Fixed font not available.", SkipSingle); + } + QCOMPARE(QFontInfo(f).family().left(5).toLower(), QString("fixed")); +#endif +} + +void tst_QFont::insertAndRemoveSubstitutions() +{ + QFont::removeSubstitution("BogusFontFamily"); + // make sure it is empty before we start + QVERIFY(QFont::substitutes("BogusFontFamily").isEmpty()); + QVERIFY(QFont::substitutes("bogusfontfamily").isEmpty()); + + // inserting Foo + QFont::insertSubstitution("BogusFontFamily", "Foo"); + QCOMPARE(QFont::substitutes("BogusFontFamily").count(), 1); + QCOMPARE(QFont::substitutes("bogusfontfamily").count(), 1); + + // inserting Bar and Baz + QStringList moreFonts; + moreFonts << "Bar" << "Baz"; + QFont::insertSubstitutions("BogusFontFamily", moreFonts); + QCOMPARE(QFont::substitutes("BogusFontFamily").count(), 3); + QCOMPARE(QFont::substitutes("bogusfontfamily").count(), 3); + + QFont::removeSubstitution("BogusFontFamily"); + // make sure it is empty again + QVERIFY(QFont::substitutes("BogusFontFamily").isEmpty()); + QVERIFY(QFont::substitutes("bogusfontfamily").isEmpty()); +} + + +static QFont copyFont(const QFont &font1) // copy using a QDataStream +{ + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + QDataStream ds(&buffer); + ds << font1; + buffer.close(); + + buffer.open(QIODevice::ReadOnly); + QFont font2; + ds >> font2; + return font2; +} + +void tst_QFont::serializeSpacing() +{ + QFont font; + QCOMPARE(font.letterSpacing(), 0.); + QCOMPARE(font.wordSpacing(), 0.); + + font.setLetterSpacing(QFont::AbsoluteSpacing, 105); + QCOMPARE(font.letterSpacing(), 105.); + QCOMPARE(font.letterSpacingType(), QFont::AbsoluteSpacing); + QCOMPARE(font.wordSpacing(), 0.); + QFont font2 = copyFont(font); + QCOMPARE(font2.letterSpacing(), 105.); + QCOMPARE(font2.letterSpacingType(), QFont::AbsoluteSpacing); + QCOMPARE(font2.wordSpacing(), 0.); + + font.setWordSpacing(50.0); + QCOMPARE(font.letterSpacing(), 105.); + QCOMPARE(font.wordSpacing(), 50.); + + QFont font3 = copyFont(font); + QCOMPARE(font3.letterSpacing(), 105.); + QCOMPARE(font3.letterSpacingType(), QFont::AbsoluteSpacing); + QCOMPARE(font3.wordSpacing(), 50.); +} + +void tst_QFont::lastResortFont() +{ +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) + QSKIP("QFont::lastResortFont() may abort with qFatal() on QWS/QPA", SkipAll); + // ...if absolutely no font is found. Just as ducumented for QFont::lastResortFont(). + // This happens on our CI machines which run QWS autotests. +#endif + QFont font; + QVERIFY(!font.lastResortFont().isEmpty()); +} + +void tst_QFont::styleName() +{ +#if !defined(Q_WS_MAC) + QSKIP("Only tested on Mac", SkipAll); +#else + QFont font("Helvetica Neue"); + font.setStyleName("UltraLight"); + + QCOMPARE(QFontInfo(font).styleName(), QString("UltraLight")); +#endif +} + +QTEST_MAIN(tst_QFont) +#include "tst_qfont.moc" diff --git a/tests/auto/gui/text/qfontdatabase/.gitignore b/tests/auto/gui/text/qfontdatabase/.gitignore new file mode 100644 index 0000000000..65edf9b279 --- /dev/null +++ b/tests/auto/gui/text/qfontdatabase/.gitignore @@ -0,0 +1 @@ +tst_qfontdatabase diff --git a/tests/auto/gui/text/qfontdatabase/FreeMono.ttf b/tests/auto/gui/text/qfontdatabase/FreeMono.ttf Binary files differnew file mode 100644 index 0000000000..d7ce52ddc7 --- /dev/null +++ b/tests/auto/gui/text/qfontdatabase/FreeMono.ttf diff --git a/tests/auto/gui/text/qfontdatabase/qfontdatabase.pro b/tests/auto/gui/text/qfontdatabase/qfontdatabase.pro new file mode 100644 index 0000000000..e7dfc3c73d --- /dev/null +++ b/tests/auto/gui/text/qfontdatabase/qfontdatabase.pro @@ -0,0 +1,10 @@ +load(qttest_p4) +SOURCES += tst_qfontdatabase.cpp +!symbian:DEFINES += SRCDIR=\\\"$$PWD\\\" + +wince*|symbian { + additionalFiles.files = FreeMono.ttf + additionalFiles.path = . + DEPLOYMENT += additionalFiles +} + diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp new file mode 100644 index 0000000000..1df61d0a06 --- /dev/null +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <qfontdatabase.h> + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "." +#endif + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFontDatabase : public QObject +{ +Q_OBJECT + +public: + tst_QFontDatabase(); + virtual ~tst_QFontDatabase(); + +public slots: + void init(); + void cleanup(); +private slots: + void styles_data(); + void styles(); + + void fixedPitch_data(); + void fixedPitch(); + +#ifdef Q_WS_MAC + void trickyFonts_data(); + void trickyFonts(); +#endif + + void widthTwoTimes_data(); + void widthTwoTimes(); + + void addAppFont_data(); + void addAppFont(); +}; + +tst_QFontDatabase::tst_QFontDatabase() +{ +#ifndef Q_OS_IRIX + QDir::setCurrent(SRCDIR); +#endif +} + +tst_QFontDatabase::~tst_QFontDatabase() +{ + +} + +void tst_QFontDatabase::init() +{ +// TODO: Add initialization code here. +// This will be executed immediately before each test is run. +} + +void tst_QFontDatabase::cleanup() +{ +// TODO: Add cleanup code here. +// This will be executed immediately after each test is run. +} + +void tst_QFontDatabase::styles_data() +{ + QTest::addColumn<QString>("font"); + + QTest::newRow( "data0" ) << QString( "Times New Roman" ); +} + +void tst_QFontDatabase::styles() +{ + QFETCH( QString, font ); + + QFontDatabase fdb; + QStringList styles = fdb.styles( font ); + QStringList::Iterator it = styles.begin(); + while ( it != styles.end() ) { + QString style = *it; + QString trimmed = style.trimmed(); + ++it; + + QCOMPARE( style, trimmed ); + } +} + +void tst_QFontDatabase::fixedPitch_data() +{ + QTest::addColumn<QString>("font"); + QTest::addColumn<bool>("fixedPitch"); + + QTest::newRow( "Times New Roman" ) << QString( "Times New Roman" ) << false; + QTest::newRow( "Arial" ) << QString( "Arial" ) << false; + QTest::newRow( "Andale Mono" ) << QString( "Andale Mono" ) << true; + QTest::newRow( "Courier" ) << QString( "Courier" ) << true; + QTest::newRow( "Courier New" ) << QString( "Courier New" ) << true; +#ifndef Q_WS_MAC + QTest::newRow( "Script" ) << QString( "Script" ) << false; + QTest::newRow( "Lucida Console" ) << QString( "Lucida Console" ) << true; +#else + QTest::newRow( "Menlo" ) << QString( "Menlo" ) << true; + QTest::newRow( "Monaco" ) << QString( "Monaco" ) << true; +#endif +} + +void tst_QFontDatabase::fixedPitch() +{ +#ifdef Q_WS_QWS + QSKIP("fixedPitch not implemented for Qtopia Core", SkipAll); +#endif + QFETCH(QString, font); + QFETCH(bool, fixedPitch); + + QFontDatabase fdb; + if (!fdb.families().contains(font)) + QSKIP( "Font not installed", SkipSingle); + +#ifdef Q_WS_QPA + if (fixedPitch) { + // fixedPitch() never returns true on qpa + QEXPECT_FAIL("", "QTBUG-20754 fails on qpa", Abort); + } +#endif + + QCOMPARE(fdb.isFixedPitch(font), fixedPitch); + + QFont qfont(font); + QFontInfo fi(qfont); + QCOMPARE(fi.fixedPitch(), fixedPitch); +} + +#ifdef Q_WS_MAC +void tst_QFontDatabase::trickyFonts_data() +{ + QTest::addColumn<QString>("font"); + + QTest::newRow( "Geeza Pro" ) << QString( "Geeza Pro" ); +} + +void tst_QFontDatabase::trickyFonts() +{ + QFETCH(QString, font); + + QFontDatabase fdb; + if (!fdb.families().contains(font)) + QSKIP( "Font not installed", SkipSingle); + + QFont qfont(font); + QFontInfo fi(qfont); + QCOMPARE(fi.family(), font); +} +#endif + +void tst_QFontDatabase::widthTwoTimes_data() +{ + QTest::addColumn<QString>("font"); + QTest::addColumn<int>("pixelSize"); + QTest::addColumn<QString>("text"); + + QTest::newRow("Arial") << QString("Arial") << 1000 << QString("Some text"); +} + +void tst_QFontDatabase::widthTwoTimes() +{ + QFETCH(QString, font); + QFETCH(int, pixelSize); + QFETCH(QString, text); + + QFont f; + f.setFamily(font); + f.setPixelSize(pixelSize); + + QFontMetrics fm(f); + int w1 = fm.charWidth(text, 0); + int w2 = fm.charWidth(text, 0); + + QCOMPARE(w1, w2); +} + +void tst_QFontDatabase::addAppFont_data() +{ + QTest::addColumn<bool>("useMemoryFont"); + QTest::newRow("font file") << false; + QTest::newRow("memory font") << true; +} + +void tst_QFontDatabase::addAppFont() +{ + QFETCH(bool, useMemoryFont); + QSignalSpy fontDbChangedSpy(QApplication::instance(), SIGNAL(fontDatabaseChanged())); + + QFontDatabase db; + +#ifdef Q_WS_QPA + QEXPECT_FAIL("memory font", "QTBUG-20754 fails on qpa", Abort); +#endif + + const QStringList oldFamilies = db.families(); + QVERIFY(!oldFamilies.isEmpty()); + + fontDbChangedSpy.clear(); + + int id; + if (useMemoryFont) { + QFile fontfile("FreeMono.ttf"); + fontfile.open(QIODevice::ReadOnly); + QByteArray fontdata = fontfile.readAll(); + QVERIFY(!fontdata.isEmpty()); + id = QFontDatabase::addApplicationFontFromData(fontdata); + } else { + id = QFontDatabase::addApplicationFont("FreeMono.ttf"); + } +#if defined(Q_OS_HPUX) && defined(QT_NO_FONTCONFIG) + // Documentation says that X11 systems that don't have fontconfig + // don't support application fonts. + QCOMPARE(id, -1); + return; +#endif + QCOMPARE(fontDbChangedSpy.count(), 1); +// addApplicationFont is supported on Mac, don't skip the test if it breaks. +#ifndef Q_WS_MAC + if (id == -1) { + QSKIP("Skip the test since app fonts are not supported on this system", SkipSingle); + return; + } +#endif + + const QStringList addedFamilies = QFontDatabase::applicationFontFamilies(id); + QVERIFY(!addedFamilies.isEmpty()); + +#ifdef Q_WS_QPA + QEXPECT_FAIL("font file", "QTBUG-20754 fails on qpa", Abort); +#endif + + const QStringList newFamilies = db.families(); + QVERIFY(!newFamilies.isEmpty()); + QVERIFY(newFamilies.count() >= oldFamilies.count()); + + for (int i = 0; i < addedFamilies.count(); ++i) + QVERIFY(newFamilies.contains(addedFamilies.at(i))); + + QVERIFY(QFontDatabase::removeApplicationFont(id)); + QCOMPARE(fontDbChangedSpy.count(), 2); + + QVERIFY(db.families() == oldFamilies); +} + +QTEST_MAIN(tst_QFontDatabase) +#include "tst_qfontdatabase.moc" diff --git a/tests/auto/gui/text/qfontmetrics/.gitignore b/tests/auto/gui/text/qfontmetrics/.gitignore new file mode 100644 index 0000000000..0b428672a3 --- /dev/null +++ b/tests/auto/gui/text/qfontmetrics/.gitignore @@ -0,0 +1 @@ +tst_qfontmetrics diff --git a/tests/auto/gui/text/qfontmetrics/qfontmetrics.pro b/tests/auto/gui/text/qfontmetrics/qfontmetrics.pro new file mode 100644 index 0000000000..c0dc1abbe6 --- /dev/null +++ b/tests/auto/gui/text/qfontmetrics/qfontmetrics.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qfontmetrics.cpp +RESOURCES += testfont.qrc + diff --git a/tests/auto/gui/text/qfontmetrics/testfont.qrc b/tests/auto/gui/text/qfontmetrics/testfont.qrc new file mode 100644 index 0000000000..bc0c0b0959 --- /dev/null +++ b/tests/auto/gui/text/qfontmetrics/testfont.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/fonts"> + <file>ucs4font.ttf</file> + </qresource> +</RCC> diff --git a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp new file mode 100644 index 0000000000..982cfc11d9 --- /dev/null +++ b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qfontdatabase.h> +#include <qstringlist.h> +#include <qlist.h> + + + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QFontMetrics : public QObject +{ +Q_OBJECT + +public: + tst_QFontMetrics(); + virtual ~tst_QFontMetrics(); + +public slots: + void init(); + void cleanup(); +private slots: + void same(); + void metrics(); + void boundingRect(); + void elidedText_data(); + void elidedText(); + void veryNarrowElidedText(); + void averageCharWidth(); + void bypassShaping(); + void elidedMultiLength(); + void elidedMultiLengthF(); + void inFontUcs4(); + void lineWidth(); +}; + +tst_QFontMetrics::tst_QFontMetrics() + +{ +} + +tst_QFontMetrics::~tst_QFontMetrics() +{ + +} + +void tst_QFontMetrics::init() +{ +} + +void tst_QFontMetrics::cleanup() +{ +} + +void tst_QFontMetrics::same() +{ + QFont font; + font.setBold(true); + QFontMetrics fm(font); + const QString text = QLatin1String("Some stupid STRING"); + QCOMPARE(fm.size(0, text), fm.size(0, text)) ; + + { + QImage image; + QFontMetrics fm2(font, &image); + QString text2 = QLatin1String("Foo Foo"); + QCOMPARE(fm2.size(0, text2), fm2.size(0, text2)); //used to crash + } + + { + QImage image; + QFontMetricsF fm3(font, &image); + QString text2 = QLatin1String("Foo Foo"); + QCOMPARE(fm3.size(0, text2), fm3.size(0, text2)); //used to crash + } +} + + +void tst_QFontMetrics::metrics() +{ + QFont font; + QFontDatabase fdb; + + // Query the QFontDatabase for a specific font, store the + // result in family, style and size. + QStringList families = fdb.families(); + if (families.isEmpty()) + return; + + QStringList::ConstIterator f_it, f_end = families.end(); + for (f_it = families.begin(); f_it != f_end; ++f_it) { + const QString &family = *f_it; + + QStringList styles = fdb.styles(family); + QStringList::ConstIterator s_it, s_end = styles.end(); + for (s_it = styles.begin(); s_it != s_end; ++s_it) { + const QString &style = *s_it; + + if (fdb.isSmoothlyScalable(family, style)) { + // smoothly scalable font... don't need to load every pointsize + font = fdb.font(family, style, 12); + + QFontMetrics fontmetrics(font); + QCOMPARE(fontmetrics.ascent() + fontmetrics.descent() + 1, + fontmetrics.height()); + + QCOMPARE(fontmetrics.height() + fontmetrics.leading(), + fontmetrics.lineSpacing()); + } else { + QList<int> sizes = fdb.pointSizes(family, style); + QVERIFY(!sizes.isEmpty()); + QList<int>::ConstIterator z_it, z_end = sizes.end(); + for (z_it = sizes.begin(); z_it != z_end; ++z_it) { + const int size = *z_it; + + // Initialize the font, and check if it is an exact match + font = fdb.font(family, style, size); + + QFontMetrics fontmetrics(font); + QCOMPARE(fontmetrics.ascent() + fontmetrics.descent() + 1, + fontmetrics.height()); + QCOMPARE(fontmetrics.height() + fontmetrics.leading(), + fontmetrics.lineSpacing()); + } + } + } + } +} + +void tst_QFontMetrics::boundingRect() +{ + QFont f; + f.setPointSize(24); + QFontMetrics fm(f); + QRect r = fm.boundingRect(QChar('Y')); + QVERIFY(r.top() < 0); + r = fm.boundingRect(QString("Y")); + QVERIFY(r.top() < 0); +} + +void tst_QFontMetrics::elidedText_data() +{ + QTest::addColumn<QFont>("font"); + QTest::addColumn<QString>("text"); + + QTest::newRow("helvetica hello") << QFont("helvetica",10) << QString("hello") ; + QTest::newRow("helvetica hello &Bye") << QFont("helvetica",10) << QString("hello&Bye") ; +} + + +void tst_QFontMetrics::elidedText() +{ + QFETCH(QFont, font); + QFETCH(QString, text); + QFontMetrics fm(font); + int w = fm.width(text); + QString newtext = fm.elidedText(text,Qt::ElideRight,w+1, 0); + QCOMPARE(text,newtext); // should not elide + newtext = fm.elidedText(text,Qt::ElideRight,w-1, 0); + QVERIFY(text != newtext); // should elide +} + +void tst_QFontMetrics::veryNarrowElidedText() +{ + QFont f; + QFontMetrics fm(f); + QString text("hello"); + QCOMPARE(fm.elidedText(text, Qt::ElideRight, 0), QString()); +} + +void tst_QFontMetrics::averageCharWidth() +{ + QFont f; + QFontMetrics fm(f); + QVERIFY(fm.averageCharWidth() != 0); + QFontMetricsF fmf(f); + QVERIFY(fmf.averageCharWidth() != 0); +} + +void tst_QFontMetrics::bypassShaping() +{ + QFont f; + f.setStyleStrategy(QFont::ForceIntegerMetrics); + QFontMetrics fm(f); + QString text = " A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z"; + int textWidth = fm.width(text, -1, Qt::TextBypassShaping); + QVERIFY(textWidth != 0); + int charsWidth = 0; + for (int i = 0; i < text.size(); ++i) + charsWidth += fm.width(text[i]); + // This assertion is needed in QtWebKit's WebCore::Font::offsetForPositionForSimpleText + QCOMPARE(textWidth, charsWidth); +} + +template<class FontMetrics> void elidedMultiLength_helper() +{ + QString text1 = "Long Text 1\x9cShorter\x9csmall"; + QString text1_long = "Long Text 1"; + QString text1_short = "Shorter"; + QString text1_small = "small"; + FontMetrics fm = FontMetrics(QFont()); + int width_long = fm.size(0, text1_long).width(); + QCOMPARE(fm.elidedText(text1,Qt::ElideRight, 8000), text1_long); + QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_long + 1), text1_long); + QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_long - 1), text1_short); + int width_short = fm.size(0, text1_short).width(); + QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_short + 1), text1_short); + QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_short - 1), text1_small); + + // Not even wide enough for "small" - should use ellipsis + QChar ellipsisChar(0x2026); + QString text1_el = QString::fromLatin1("s") + ellipsisChar; + int width_small = fm.width(text1_el); + QCOMPARE(fm.elidedText(text1,Qt::ElideRight, width_small + 1), text1_el); +} + +void tst_QFontMetrics::elidedMultiLength() +{ + elidedMultiLength_helper<QFontMetrics>(); +} + +void tst_QFontMetrics::elidedMultiLengthF() +{ + elidedMultiLength_helper<QFontMetricsF>(); +} + +void tst_QFontMetrics::inFontUcs4() +{ + int id = QFontDatabase::addApplicationFont(":/fonts/ucs4font.ttf"); + QVERIFY(id >= 0); + + QFont font("QtTestUcs4"); + { + QFontMetrics fm(font); + +#ifdef Q_WS_QPA + QEXPECT_FAIL("", "QTBUG-20759 fails for qpa", Continue); +#endif + + QVERIFY(fm.inFontUcs4(0x1D7FF)); + } + + { + QFontMetricsF fm(font); + +#ifdef Q_WS_QPA + QEXPECT_FAIL("", "QTBUG-20759 fails for qpa", Continue); +#endif + + QVERIFY(fm.inFontUcs4(0x1D7FF)); + } + + QFontDatabase::removeApplicationFont(id); +} + +void tst_QFontMetrics::lineWidth() +{ + // QTBUG-13009, QTBUG-13011 + QFont smallFont; + smallFont.setPointSize(8); + smallFont.setWeight(QFont::Light); + const QFontMetrics smallFontMetrics(smallFont); + + QFont bigFont; + bigFont.setPointSize(40); + bigFont.setWeight(QFont::Black); + const QFontMetrics bigFontMetrics(bigFont); + + QVERIFY(smallFontMetrics.lineWidth() >= 1); + +#ifdef Q_WS_QPA + QEXPECT_FAIL("", "QTBUG-20759 fails for qpa", Continue); +#endif + + QVERIFY(smallFontMetrics.lineWidth() < bigFontMetrics.lineWidth()); +} + +QTEST_MAIN(tst_QFontMetrics) +#include "tst_qfontmetrics.moc" diff --git a/tests/auto/gui/text/qfontmetrics/ucs4font.ttf b/tests/auto/gui/text/qfontmetrics/ucs4font.ttf Binary files differnew file mode 100644 index 0000000000..31b6997779 --- /dev/null +++ b/tests/auto/gui/text/qfontmetrics/ucs4font.ttf diff --git a/tests/auto/gui/text/qglyphrun/qglyphrun.pro b/tests/auto/gui/text/qglyphrun/qglyphrun.pro new file mode 100644 index 0000000000..480ad5b9a4 --- /dev/null +++ b/tests/auto/gui/text/qglyphrun/qglyphrun.pro @@ -0,0 +1,11 @@ +load(qttest_p4) +QT = core gui + +SOURCES += \ + tst_qglyphrun.cpp + +wince*|symbian*: { + DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} diff --git a/tests/auto/gui/text/qglyphrun/test.ttf b/tests/auto/gui/text/qglyphrun/test.ttf Binary files differnew file mode 100644 index 0000000000..9043a576ef --- /dev/null +++ b/tests/auto/gui/text/qglyphrun/test.ttf diff --git a/tests/auto/gui/text/qglyphrun/tst_qglyphrun.cpp b/tests/auto/gui/text/qglyphrun/tst_qglyphrun.cpp new file mode 100644 index 0000000000..e84915428f --- /dev/null +++ b/tests/auto/gui/text/qglyphrun/tst_qglyphrun.cpp @@ -0,0 +1,679 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <qglyphrun.h> +#include <qpainter.h> +#include <qtextlayout.h> +#include <qfontdatabase.h> + +// #define DEBUG_SAVE_IMAGE + +class tst_QGlyphRun: public QObject +{ + Q_OBJECT + +#if !defined(QT_NO_RAWFONT) +private slots: + void initTestCase(); + void init(); + void cleanupTestCase(); + + void constructionAndDestruction(); + void copyConstructor(); + void assignment(); + void equalsOperator_data(); + void equalsOperator(); + void textLayoutGlyphIndexes(); + void drawExistingGlyphs(); + void drawNonExistentGlyphs(); + void drawMultiScriptText1(); + void drawMultiScriptText2(); + void drawStruckOutText(); + void drawOverlinedText(); + void drawUnderlinedText(); + void drawRightToLeft(); + void detach(); + void setRawData(); + void setRawDataAndGetAsVector(); + +private: + int m_testFontId; + QFont m_testFont; + bool m_testFont_ok; +#endif // QT_NO_RAWFONT + +}; + +#if !defined(QT_NO_RAWFONT) + +Q_DECLARE_METATYPE(QGlyphRun); + +void tst_QGlyphRun::initTestCase() +{ + m_testFont_ok = false; + + m_testFontId = QFontDatabase::addApplicationFont(SRCDIR "test.ttf"); + QVERIFY(m_testFontId >= 0); + + m_testFont = QFont("QtsSpecialTestFont"); + +#ifdef Q_WS_QPA + QEXPECT_FAIL("", "QTBUG-20760 fails on qpa", Abort); +#endif + + QCOMPARE(QFontInfo(m_testFont).family(), QString::fromLatin1("QtsSpecialTestFont")); + + m_testFont_ok = true; +} + +void tst_QGlyphRun::init() +{ + if (!m_testFont_ok) { + QSKIP("Test font is not working correctly", SkipAll); + } +} + +void tst_QGlyphRun::cleanupTestCase() +{ + QFontDatabase::removeApplicationFont(m_testFontId); +} + +void tst_QGlyphRun::constructionAndDestruction() +{ + QGlyphRun glyphIndexes; +} + +static QGlyphRun make_dummy_indexes() +{ + QGlyphRun glyphs; + + QVector<quint32> glyphIndexes; + QVector<QPointF> positions; + QFont font; + font.setPointSize(18); + + glyphIndexes.append(1); + glyphIndexes.append(2); + glyphIndexes.append(3); + + positions.append(QPointF(1, 2)); + positions.append(QPointF(3, 4)); + positions.append(QPointF(5, 6)); + + glyphs.setRawFont(QRawFont::fromFont(font)); + glyphs.setGlyphIndexes(glyphIndexes); + glyphs.setPositions(positions); + + return glyphs; +} + +void tst_QGlyphRun::copyConstructor() +{ + QGlyphRun glyphs; + + { + QVector<quint32> glyphIndexes; + QVector<QPointF> positions; + QFont font; + font.setPointSize(18); + + glyphIndexes.append(1); + glyphIndexes.append(2); + glyphIndexes.append(3); + + positions.append(QPointF(1, 2)); + positions.append(QPointF(3, 4)); + positions.append(QPointF(5, 6)); + + glyphs.setRawFont(QRawFont::fromFont(font)); + glyphs.setGlyphIndexes(glyphIndexes); + glyphs.setPositions(positions); + } + + QGlyphRun otherGlyphs(glyphs); + QCOMPARE(otherGlyphs.rawFont(), glyphs.rawFont()); + QCOMPARE(glyphs.glyphIndexes(), otherGlyphs.glyphIndexes()); + QCOMPARE(glyphs.positions(), otherGlyphs.positions()); +} + +void tst_QGlyphRun::assignment() +{ + QGlyphRun glyphs(make_dummy_indexes()); + + QGlyphRun otherGlyphs = glyphs; + QCOMPARE(otherGlyphs.rawFont(), glyphs.rawFont()); + QCOMPARE(glyphs.glyphIndexes(), otherGlyphs.glyphIndexes()); + QCOMPARE(glyphs.positions(), otherGlyphs.positions()); +} + +void tst_QGlyphRun::equalsOperator_data() +{ + QTest::addColumn<QGlyphRun>("one"); + QTest::addColumn<QGlyphRun>("two"); + QTest::addColumn<bool>("equals"); + + QGlyphRun one(make_dummy_indexes()); + QGlyphRun two(make_dummy_indexes()); + + QTest::newRow("Identical") << one << two << true; + + { + QGlyphRun busted(two); + + QVector<QPointF> positions = busted.positions(); + positions[2] += QPointF(1, 1); + busted.setPositions(positions); + + + QTest::newRow("Different positions") << one << busted << false; + } + + { + QGlyphRun busted(two); + + QFont font; + font.setPixelSize(busted.rawFont().pixelSize() * 2); + busted.setRawFont(QRawFont::fromFont(font)); + + QTest::newRow("Different fonts") << one << busted << false; + } + + { + QGlyphRun busted(two); + + QVector<quint32> glyphIndexes = busted.glyphIndexes(); + glyphIndexes[2] += 1; + busted.setGlyphIndexes(glyphIndexes); + + QTest::newRow("Different glyph indexes") << one << busted << false; + } + +} + +void tst_QGlyphRun::equalsOperator() +{ + QFETCH(QGlyphRun, one); + QFETCH(QGlyphRun, two); + QFETCH(bool, equals); + + QCOMPARE(one == two, equals); + QCOMPARE(one != two, !equals); +} + + +void tst_QGlyphRun::textLayoutGlyphIndexes() +{ + QString s; + s.append(QLatin1Char('A')); + s.append(QChar(0xe000)); + + QTextLayout layout(s); + layout.setFont(m_testFont); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> listOfGlyphs = layout.glyphRuns(); + + QCOMPARE(listOfGlyphs.size(), 1); + + QGlyphRun glyphs = listOfGlyphs.at(0); + + QCOMPARE(glyphs.glyphIndexes().size(), 2); + QCOMPARE(glyphs.glyphIndexes().at(0), quint32(2)); + QCOMPARE(glyphs.glyphIndexes().at(1), quint32(1)); +} + +void tst_QGlyphRun::drawExistingGlyphs() +{ + QPixmap textLayoutDraw(1000, 1000); + QPixmap drawGlyphs(1000, 1000); + + textLayoutDraw.fill(Qt::white); + drawGlyphs.fill(Qt::white); + + QString s; + s.append(QLatin1Char('A')); + s.append(QChar(0xe000)); + + QTextLayout layout(s); + layout.setFont(m_testFont); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QPainter p(&textLayoutDraw); + layout.draw(&p, QPointF(50, 50)); + } + + QGlyphRun glyphs = layout.glyphRuns().size() > 0 + ? layout.glyphRuns().at(0) + : QGlyphRun(); + + { + QPainter p(&drawGlyphs); + p.drawGlyphRun(QPointF(50, 50), glyphs); + } + +#if defined(DEBUG_SAVE_IMAGE) + textLayoutDraw.save("drawExistingGlyphs_textLayoutDraw.png"); + drawGlyphs.save("drawExistingGlyphs_drawGlyphIndexes.png"); +#endif + + QCOMPARE(textLayoutDraw, drawGlyphs); +} + +void tst_QGlyphRun::setRawData() +{ + QGlyphRun glyphRun; + glyphRun.setRawFont(QRawFont::fromFont(m_testFont)); + glyphRun.setGlyphIndexes(QVector<quint32>() << 2 << 2 << 2); + glyphRun.setPositions(QVector<QPointF>() << QPointF(2, 3) << QPointF(20, 3) << QPointF(10, 20)); + + QPixmap baseline(100, 50); + baseline.fill(Qt::white); + { + QPainter p(&baseline); + p.drawGlyphRun(QPointF(3, 2), glyphRun); + } + + QGlyphRun baselineCopied = glyphRun; + + quint32 glyphIndexArray[3] = { 2, 2, 2 }; + QPointF glyphPositionArray[3] = { QPointF(2, 3), QPointF(20, 3), QPointF(10, 20) }; + + glyphRun.setRawData(glyphIndexArray, glyphPositionArray, 3); + + QPixmap rawDataGlyphs(100, 50); + rawDataGlyphs.fill(Qt::white); + { + QPainter p(&rawDataGlyphs); + p.drawGlyphRun(QPointF(3, 2), glyphRun); + } + + quint32 otherGlyphIndexArray[1] = { 2 }; + QPointF otherGlyphPositionArray[1] = { QPointF(2, 3) }; + + glyphRun.setRawData(otherGlyphIndexArray, otherGlyphPositionArray, 1); + + QPixmap baselineCopiedPixmap(100, 50); + baselineCopiedPixmap.fill(Qt::white); + { + QPainter p(&baselineCopiedPixmap); + p.drawGlyphRun(QPointF(3, 2), baselineCopied); + } + +#if defined(DEBUG_SAVE_IMAGE) + baseline.save("setRawData_baseline.png"); + rawDataGlyphs.save("setRawData_rawDataGlyphs.png"); + baselineCopiedPixmap.save("setRawData_baselineCopiedPixmap.png"); +#endif + + QCOMPARE(rawDataGlyphs, baseline); + QCOMPARE(baselineCopiedPixmap, baseline); +} + +void tst_QGlyphRun::setRawDataAndGetAsVector() +{ + QVector<quint32> glyphIndexArray; + glyphIndexArray << 3 << 2 << 1 << 4; + + QVector<QPointF> glyphPositionArray; + glyphPositionArray << QPointF(1, 2) << QPointF(3, 4) << QPointF(5, 6) << QPointF(7, 8); + + QGlyphRun glyphRun; + glyphRun.setRawData(glyphIndexArray.constData(), glyphPositionArray.constData(), 4); + + QVector<quint32> glyphIndexes = glyphRun.glyphIndexes(); + QVector<QPointF> glyphPositions = glyphRun.positions(); + + QCOMPARE(glyphIndexes.size(), 4); + QCOMPARE(glyphPositions.size(), 4); + + QCOMPARE(glyphIndexes, glyphIndexArray); + QCOMPARE(glyphPositions, glyphPositionArray); + + QGlyphRun otherGlyphRun; + otherGlyphRun.setGlyphIndexes(glyphIndexArray); + otherGlyphRun.setPositions(glyphPositionArray); + + QCOMPARE(glyphRun, otherGlyphRun); +} + +void tst_QGlyphRun::drawNonExistentGlyphs() +{ + QVector<quint32> glyphIndexes; + glyphIndexes.append(3); + + QVector<QPointF> glyphPositions; + glyphPositions.append(QPointF(0, 0)); + + QGlyphRun glyphs; + glyphs.setGlyphIndexes(glyphIndexes); + glyphs.setPositions(glyphPositions); + glyphs.setRawFont(QRawFont::fromFont(m_testFont)); + + QPixmap image(1000, 1000); + image.fill(Qt::white); + + QPixmap imageBefore = image; + { + QPainter p(&image); + p.drawGlyphRun(QPointF(50, 50), glyphs); + } + +#if defined(DEBUG_SAVE_IMAGE) + image.save("drawNonExistentGlyphs.png"); +#endif + + QCOMPARE(image, imageBefore); // Should be unchanged +} + +void tst_QGlyphRun::drawMultiScriptText1() +{ + QString text; + text += QChar(0x03D0); // Greek, beta + + QTextLayout textLayout(text); + textLayout.beginLayout(); + textLayout.createLine(); + textLayout.endLayout(); + + QPixmap textLayoutDraw(1000, 1000); + textLayoutDraw.fill(Qt::white); + + QPixmap drawGlyphs(1000, 1000); + drawGlyphs.fill(Qt::white); + + QList<QGlyphRun> glyphsList = textLayout.glyphRuns(); + QCOMPARE(glyphsList.size(), 1); + + { + QPainter p(&textLayoutDraw); + textLayout.draw(&p, QPointF(50, 50)); + } + + { + QPainter p(&drawGlyphs); + foreach (QGlyphRun glyphs, glyphsList) + p.drawGlyphRun(QPointF(50, 50), glyphs); + } + +#if defined(DEBUG_SAVE_IMAGE) + textLayoutDraw.save("drawMultiScriptText1_textLayoutDraw.png"); + drawGlyphs.save("drawMultiScriptText1_drawGlyphIndexes.png"); +#endif + + QCOMPARE(drawGlyphs, textLayoutDraw); +} + + +void tst_QGlyphRun::drawMultiScriptText2() +{ + QString text; + text += QChar(0x0621); // Arabic, Hamza + text += QChar(0x03D0); // Greek, beta + + QTextLayout textLayout(text); + textLayout.beginLayout(); + textLayout.createLine(); + textLayout.endLayout(); + + QPixmap textLayoutDraw(1000, 1000); + textLayoutDraw.fill(Qt::white); + + QPixmap drawGlyphs(1000, 1000); + drawGlyphs.fill(Qt::white); + + QList<QGlyphRun> glyphsList = textLayout.glyphRuns(); + QCOMPARE(glyphsList.size(), 2); + + { + QPainter p(&textLayoutDraw); + textLayout.draw(&p, QPointF(50, 50)); + } + + { + QPainter p(&drawGlyphs); + foreach (QGlyphRun glyphs, glyphsList) + p.drawGlyphRun(QPointF(50, 50), glyphs); + } + +#if defined(DEBUG_SAVE_IMAGE) + textLayoutDraw.save("drawMultiScriptText2_textLayoutDraw.png"); + drawGlyphs.save("drawMultiScriptText2_drawGlyphIndexes.png"); +#endif + + QCOMPARE(drawGlyphs, textLayoutDraw); +} + +void tst_QGlyphRun::detach() +{ + QGlyphRun glyphs; + + glyphs.setGlyphIndexes(QVector<quint32>() << 1 << 2 << 3); + + QGlyphRun otherGlyphs; + otherGlyphs = glyphs; + + QCOMPARE(otherGlyphs.glyphIndexes(), glyphs.glyphIndexes()); + + otherGlyphs.setGlyphIndexes(QVector<quint32>() << 4 << 5 << 6); + + QCOMPARE(otherGlyphs.glyphIndexes(), QVector<quint32>() << 4 << 5 << 6); + QCOMPARE(glyphs.glyphIndexes(), QVector<quint32>() << 1 << 2 << 3); +} + +void tst_QGlyphRun::drawStruckOutText() +{ + QPixmap textLayoutDraw(1000, 1000); + QPixmap drawGlyphs(1000, 1000); + + textLayoutDraw.fill(Qt::white); + drawGlyphs.fill(Qt::white); + + QString s = QString::fromLatin1("Foobar"); + + QFont font; + font.setStrikeOut(true); + + QTextLayout layout(s); + layout.setFont(font); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QPainter p(&textLayoutDraw); + layout.draw(&p, QPointF(50, 50)); + } + + QGlyphRun glyphs = layout.glyphRuns().size() > 0 + ? layout.glyphRuns().at(0) + : QGlyphRun(); + + { + QPainter p(&drawGlyphs); + p.drawGlyphRun(QPointF(50, 50), glyphs); + } + +#if defined(DEBUG_SAVE_IMAGE) + textLayoutDraw.save("drawStruckOutText_textLayoutDraw.png"); + drawGlyphs.save("drawStruckOutText_drawGlyphIndexes.png"); +#endif + + QCOMPARE(textLayoutDraw, drawGlyphs); +} + +void tst_QGlyphRun::drawOverlinedText() +{ + QPixmap textLayoutDraw(1000, 1000); + QPixmap drawGlyphs(1000, 1000); + + textLayoutDraw.fill(Qt::white); + drawGlyphs.fill(Qt::white); + + QString s = QString::fromLatin1("Foobar"); + + QFont font; + font.setOverline(true); + + QTextLayout layout(s); + layout.setFont(font); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QPainter p(&textLayoutDraw); + layout.draw(&p, QPointF(50, 50)); + } + + QGlyphRun glyphs = layout.glyphRuns().size() > 0 + ? layout.glyphRuns().at(0) + : QGlyphRun(); + + { + QPainter p(&drawGlyphs); + p.drawGlyphRun(QPointF(50, 50), glyphs); + } + +#if defined(DEBUG_SAVE_IMAGE) + textLayoutDraw.save("drawOverlineText_textLayoutDraw.png"); + drawGlyphs.save("drawOverlineText_drawGlyphIndexes.png"); +#endif + + QCOMPARE(textLayoutDraw, drawGlyphs); +} + +void tst_QGlyphRun::drawUnderlinedText() +{ + QPixmap textLayoutDraw(1000, 1000); + QPixmap drawGlyphs(1000, 1000); + + textLayoutDraw.fill(Qt::white); + drawGlyphs.fill(Qt::white); + + QString s = QString::fromLatin1("Foobar"); + + QFont font; + font.setUnderline(true); + + QTextLayout layout(s); + layout.setFont(font); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QPainter p(&textLayoutDraw); + layout.draw(&p, QPointF(50, 50)); + } + + QGlyphRun glyphs = layout.glyphRuns().size() > 0 + ? layout.glyphRuns().at(0) + : QGlyphRun(); + + { + QPainter p(&drawGlyphs); + p.drawGlyphRun(QPointF(50, 50), glyphs); + } + +#if defined(DEBUG_SAVE_IMAGE) + textLayoutDraw.save("drawUnderlineText_textLayoutDraw.png"); + drawGlyphs.save("drawUnderlineText_drawGlyphIndexes.png"); +#endif + + QCOMPARE(textLayoutDraw, drawGlyphs); +} + +void tst_QGlyphRun::drawRightToLeft() +{ + QString s; + s.append(QChar(1575)); + s.append(QChar(1578)); + + QPixmap textLayoutDraw(1000, 1000); + QPixmap drawGlyphs(1000, 1000); + + textLayoutDraw.fill(Qt::white); + drawGlyphs.fill(Qt::white); + + QFont font; + font.setUnderline(true); + + QTextLayout layout(s); + layout.setFont(font); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + { + QPainter p(&textLayoutDraw); + layout.draw(&p, QPointF(50, 50)); + } + + QGlyphRun glyphs = layout.glyphRuns().size() > 0 + ? layout.glyphRuns().at(0) + : QGlyphRun(); + + { + QPainter p(&drawGlyphs); + p.drawGlyphRun(QPointF(50, 50), glyphs); + } + +#if defined(DEBUG_SAVE_IMAGE) + textLayoutDraw.save("drawRightToLeft_textLayoutDraw.png"); + drawGlyphs.save("drawRightToLeft_drawGlyphIndexes.png"); +#endif + + QCOMPARE(textLayoutDraw, drawGlyphs); + +} + +#endif // QT_NO_RAWFONT + +QTEST_MAIN(tst_QGlyphRun) +#include "tst_qglyphrun.moc" + diff --git a/tests/auto/gui/text/qrawfont/qrawfont.pro b/tests/auto/gui/text/qrawfont/qrawfont.pro new file mode 100644 index 0000000000..1c08299699 --- /dev/null +++ b/tests/auto/gui/text/qrawfont/qrawfont.pro @@ -0,0 +1,16 @@ +load(qttest_p4) + +QT = core core-private gui gui-private + +SOURCES += \ + tst_qrawfont.cpp + +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src + +wince*|symbian*: { + DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} + +CONFIG += insignificant_test # QTBUG-21402 diff --git a/tests/auto/gui/text/qrawfont/testfont.ttf b/tests/auto/gui/text/qrawfont/testfont.ttf Binary files differnew file mode 100644 index 0000000000..d6042d2e58 --- /dev/null +++ b/tests/auto/gui/text/qrawfont/testfont.ttf diff --git a/tests/auto/gui/text/qrawfont/testfont_bold_italic.ttf b/tests/auto/gui/text/qrawfont/testfont_bold_italic.ttf Binary files differnew file mode 100644 index 0000000000..9f65ac8df7 --- /dev/null +++ b/tests/auto/gui/text/qrawfont/testfont_bold_italic.ttf diff --git a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp new file mode 100644 index 0000000000..1c18f2f1e8 --- /dev/null +++ b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp @@ -0,0 +1,897 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include <qrawfont.h> +#include <private/qrawfont_p.h> + +class tst_QRawFont: public QObject +{ + Q_OBJECT +#if !defined(QT_NO_RAWFONT) +private slots: + void init(); + + void invalidRawFont(); + + void explicitRawFontNotLoadedInDatabase_data(); + void explicitRawFontNotLoadedInDatabase(); + + void explicitRawFontNotAvailableInSystem_data(); + void explicitRawFontNotAvailableInSystem(); + + void correctFontData_data(); + void correctFontData(); + + void glyphIndices(); + + void advances_data(); + void advances(); + + void textLayout(); + + void fontTable_data(); + void fontTable(); + + void supportedWritingSystems_data(); + void supportedWritingSystems(); + + void supportsCharacter_data(); + void supportsCharacter(); + + void supportsUcs4Character_data(); + void supportsUcs4Character(); + + void fromFont_data(); + void fromFont(); + + void copyConstructor_data(); + void copyConstructor(); + + void detach_data(); + void detach(); + + void unsupportedWritingSystem_data(); + void unsupportedWritingSystem(); + + void rawFontSetPixelSize_data(); + void rawFontSetPixelSize(); + +#if defined(Q_WS_X11) || defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + void multipleRawFontsFromData(); +#endif + +#endif // QT_NO_RAWFONT +}; + +#if !defined(QT_NO_RAWFONT) +Q_DECLARE_METATYPE(QFont::HintingPreference) +Q_DECLARE_METATYPE(QFont::Style) +Q_DECLARE_METATYPE(QFont::Weight) +Q_DECLARE_METATYPE(QFontDatabase::WritingSystem) + +void tst_QRawFont::init() +{ +#ifdef Q_WS_QPA + // Loading fonts from a QByteArray seems unimplemented for all qpa plugins at time of writing; + // almost all testfunctions fail on qpa due to this, except these few: + const QByteArray func = QTest::currentTestFunction(); + if (func != "invalidRawFont" + && func != "explicitRawFontNotAvailableInSystem" + && func != "fromFont" + && func != "textLayout") + QEXPECT_FAIL("", "QTBUG-20976 fails on qpa", Abort); +#endif +} + +void tst_QRawFont::invalidRawFont() +{ + QRawFont font; + QVERIFY(!font.isValid()); + QCOMPARE(font.pixelSize(), 0.0); + QVERIFY(font.familyName().isEmpty()); + QCOMPARE(font.style(), QFont::StyleNormal); + QCOMPARE(font.weight(), -1); + QCOMPARE(font.ascent(), 0.0); + QCOMPARE(font.descent(), 0.0); + QVERIFY(font.glyphIndexesForString(QLatin1String("Test")).isEmpty()); +} + +void tst_QRawFont::explicitRawFontNotLoadedInDatabase_data() +{ + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::explicitRawFontNotLoadedInDatabase() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QVERIFY(!QFontDatabase().families().contains(font.familyName())); +} + +void tst_QRawFont::explicitRawFontNotAvailableInSystem_data() +{ + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::explicitRawFontNotAvailableInSystem() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont rawfont(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + + { + QFont font(rawfont.familyName(), 10); + + QVERIFY(!font.exactMatch()); + QVERIFY(font.family() != QFontInfo(font).family()); + } +} + +void tst_QRawFont::correctFontData_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("expectedFamilyName"); + QTest::addColumn<QFont::Style>("style"); + QTest::addColumn<QFont::Weight>("weight"); + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + QTest::addColumn<qreal>("unitsPerEm"); + QTest::addColumn<qreal>("pixelSize"); + + int hintingPreferences[] = { + int(QFont::PreferDefaultHinting), + int(QFont::PreferNoHinting), + int(QFont::PreferVerticalHinting), + int(QFont::PreferFullHinting), + -1 + }; + int *hintingPreference = hintingPreferences; + + while (*hintingPreference >= 0) { + QString fileName = QLatin1String(SRCDIR "testfont.ttf"); + QString title = fileName + + QLatin1String(": hintingPreference=") + + QString::number(*hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QString::fromLatin1("QtBidiTestFont") + << QFont::StyleNormal + << QFont::Normal + << QFont::HintingPreference(*hintingPreference) + << 1000.0 + << 10.0; + + fileName = QLatin1String(SRCDIR "testfont_bold_italic.ttf"); + title = fileName + + QLatin1String(": hintingPreference=") + + QString::number(*hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QString::fromLatin1("QtBidiTestFont") + << QFont::StyleItalic + << QFont::Bold + << QFont::HintingPreference(*hintingPreference) + << 1000.0 + << 10.0; + + ++hintingPreference; + } +} + +void tst_QRawFont::correctFontData() +{ + QFETCH(QString, fileName); + QFETCH(QString, expectedFamilyName); + QFETCH(QFont::Style, style); + QFETCH(QFont::Weight, weight); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(qreal, unitsPerEm); + QFETCH(qreal, pixelSize); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.familyName(), expectedFamilyName); + QCOMPARE(font.style(), style); + QCOMPARE(font.weight(), int(weight)); + QCOMPARE(font.hintingPreference(), hintingPreference); + QCOMPARE(font.unitsPerEm(), unitsPerEm); + QCOMPARE(font.pixelSize(), pixelSize); +} + +void tst_QRawFont::glyphIndices() +{ + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10); + QVERIFY(font.isValid()); + + QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("Foobar")); + QVector<quint32> expectedGlyphIndices; + expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86; + + QCOMPARE(glyphIndices, expectedGlyphIndices); +} + +void tst_QRawFont::advances_data() +{ + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::advances() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QRawFontPrivate *font_d = QRawFontPrivate::get(font); + QVERIFY(font_d->fontEngine != 0); + + QVector<quint32> glyphIndices; + glyphIndices << 44 << 83 << 83 << 70 << 69 << 86; // "Foobar" + + bool supportsSubPixelPositions = font_d->fontEngine->supportsSubPixelPositions(); + QVector<QPointF> advances = font.advancesForGlyphIndexes(glyphIndices); + for (int i=0; i<glyphIndices.size(); ++i) { + QVERIFY(qFuzzyCompare(qRound(advances.at(i).x()), 8.0)); + if (supportsSubPixelPositions) + QVERIFY(advances.at(i).x() > 8.0); + + QVERIFY(qFuzzyIsNull(advances.at(i).y())); + } +} + +void tst_QRawFont::textLayout() +{ + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(SRCDIR "testfont.ttf"); + QVERIFY(id >= 0); + + QString familyName = QString::fromLatin1("QtBidiTestFont"); + QFont font(familyName); + font.setPixelSize(18.0); +#ifdef Q_WS_QPA + QEXPECT_FAIL("", "QTBUG-20976 fails on qpa", Abort); +#endif + QCOMPARE(QFontInfo(font).family(), familyName); + + QTextLayout layout(QLatin1String("Foobar")); + layout.setFont(font); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> glyphRuns = layout.glyphRuns(); + QCOMPARE(glyphRuns.size(), 1); + + QGlyphRun glyphs = glyphRuns.at(0); + + QRawFont rawFont = glyphs.rawFont(); + QVERIFY(rawFont.isValid()); + QCOMPARE(rawFont.familyName(), familyName); + QCOMPARE(rawFont.pixelSize(), 18.0); + + QVector<quint32> expectedGlyphIndices; + expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86; + + QCOMPARE(glyphs.glyphIndexes(), expectedGlyphIndices); + + QVERIFY(fontDatabase.removeApplicationFont(id)); +} + +void tst_QRawFont::fontTable_data() +{ + QTest::addColumn<QByteArray>("tagName"); + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + QTest::addColumn<int>("offset"); + QTest::addColumn<quint32>("expectedValue"); + + QTest::newRow("Head table, magic number, default hinting") + << QByteArray("head") + << QFont::PreferDefaultHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, no hinting") + << QByteArray("head") + << QFont::PreferNoHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, vertical hinting") + << QByteArray("head") + << QFont::PreferVerticalHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, full hinting") + << QByteArray("head") + << QFont::PreferFullHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); +} + +void tst_QRawFont::fontTable() +{ + QFETCH(QByteArray, tagName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(int, offset); + QFETCH(quint32, expectedValue); + + QRawFont font(QString::fromLatin1(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QByteArray table = font.fontTable(tagName); + QVERIFY(!table.isEmpty()); + + const quint32 *value = reinterpret_cast<const quint32 *>(table.constData() + offset); + QCOMPARE(*value, expectedValue); +} + +typedef QList<QFontDatabase::WritingSystem> WritingSystemList; +Q_DECLARE_METATYPE(WritingSystemList) + +void tst_QRawFont::supportedWritingSystems_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<WritingSystemList>("writingSystems"); + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + + QTest::newRow(qPrintable(QString::fromLatin1("testfont.ttf, hintingPreference=%1") + .arg(hintingPreference))) + << QString::fromLatin1(SRCDIR "testfont.ttf") + << (QList<QFontDatabase::WritingSystem>() + << QFontDatabase::Latin + << QFontDatabase::Hebrew + << QFontDatabase::Vietnamese) // Vietnamese uses same unicode bits as Latin + << QFont::HintingPreference(hintingPreference); + + QTest::newRow(qPrintable(QString::fromLatin1("testfont_bold_italic.ttf, hintingPreference=%1") + .arg(hintingPreference))) + << QString::fromLatin1(SRCDIR "testfont_bold_italic.ttf") + << (QList<QFontDatabase::WritingSystem>() + << QFontDatabase::Latin + << QFontDatabase::Hebrew + << QFontDatabase::Devanagari + << QFontDatabase::Vietnamese) // Vietnamese uses same unicode bits as Latin + << QFont::HintingPreference(hintingPreference); + } +} + +void tst_QRawFont::supportedWritingSystems() +{ + QFETCH(QString, fileName); + QFETCH(WritingSystemList, writingSystems); + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + WritingSystemList actualWritingSystems = font.supportedWritingSystems(); + QCOMPARE(actualWritingSystems.size(), writingSystems.size()); + + foreach (QFontDatabase::WritingSystem writingSystem, writingSystems) + QVERIFY(actualWritingSystems.contains(writingSystem)); +} + +void tst_QRawFont::supportsCharacter_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + QTest::addColumn<QChar>("character"); + QTest::addColumn<bool>("shouldBeSupported"); + + const char *fileNames[2] = { + SRCDIR "testfont.ttf", + SRCDIR "testfont_bold_italic.ttf" + }; + + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + + for (int i=0; i<2; ++i) { + QString fileName = QLatin1String(fileNames[i]); + + // Latin text + for (char ch='!'; ch<='~'; ++ch) { + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar::fromLatin1(ch) + << true; + } + + // Hebrew text + for (quint16 ch=0x05D0; ch<=0x05EA; ++ch) { + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar(ch) + << true; + } + + QTest::newRow(qPrintable(QString::fromLatin1("Missing character, %1, hintingPreference=%2") + .arg(fileName).arg(hintingPreference))) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar(0xD8) + << false; + } + } +} + +void tst_QRawFont::supportsCharacter() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(QChar, character); + QFETCH(bool, shouldBeSupported); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.supportsCharacter(character), shouldBeSupported); +} + +void tst_QRawFont::supportsUcs4Character_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + QTest::addColumn<quint32>("ucs4"); + QTest::addColumn<bool>("shouldBeSupported"); + + // Gothic text + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + for (quint32 ch=0x10330; ch<=0x1034A; ++ch) { + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << ch + << true; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont_bold_italic.ttf"); + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << ch + << false; + } + } + } +} + +void tst_QRawFont::supportsUcs4Character() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(quint32, ucs4); + QFETCH(bool, shouldBeSupported); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.supportsCharacter(ucs4), shouldBeSupported); +} + +void tst_QRawFont::fromFont_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + QTest::addColumn<QString>("familyName"); + QTest::addColumn<QFontDatabase::WritingSystem>("writingSystem"); + + for (int i=QFont::PreferDefaultHinting; i<=QFont::PreferFullHinting; ++i) { + QString titleBase = QString::fromLatin1("%2, hintingPreference=%1, writingSystem=%3") + .arg(i); + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Hebrew; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Latin; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + } +} + +void tst_QRawFont::fromFont() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(QString, familyName); + QFETCH(QFontDatabase::WritingSystem, writingSystem); + + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(fileName); + QVERIFY(id >= 0); + + QFont font(familyName); + font.setHintingPreference(hintingPreference); + font.setPixelSize(26.0); + + QRawFont rawFont = QRawFont::fromFont(font, writingSystem); + QVERIFY(rawFont.isValid()); + +#ifdef Q_WS_QPA + QEXPECT_FAIL("", "QTBUG-20976 fails on qpa", Abort); +#endif + + QCOMPARE(rawFont.familyName(), familyName); + QCOMPARE(rawFont.pixelSize(), 26.0); + + QVERIFY(fontDatabase.removeApplicationFont(id)); +} + +void tst_QRawFont::copyConstructor_data() +{ + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::copyConstructor() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + { + QString rawFontFamilyName; + qreal rawFontPixelSize; + qreal rawFontAscent; + qreal rawFontDescent; + int rawFontTableSize; + + QRawFont outerRawFont; + { + QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference); + QVERIFY(rawFont.isValid()); + + rawFontFamilyName = rawFont.familyName(); + rawFontPixelSize = rawFont.pixelSize(); + rawFontAscent = rawFont.ascent(); + rawFontDescent = rawFont.descent(); + rawFontTableSize = rawFont.fontTable("glyf").size(); + QVERIFY(rawFontTableSize > 0); + + { + QRawFont otherRawFont(rawFont); + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + { + QRawFont otherRawFont = rawFont; + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + outerRawFont = rawFont; + } + + QVERIFY(outerRawFont.isValid()); + QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(outerRawFont.familyName(), rawFontFamilyName); + QCOMPARE(outerRawFont.hintingPreference(), hintingPreference); + QCOMPARE(outerRawFont.ascent(), rawFontAscent); + QCOMPARE(outerRawFont.descent(), rawFontDescent); + QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize); + } +} + +void tst_QRawFont::detach_data() +{ + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::detach() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + { + QString rawFontFamilyName; + qreal rawFontPixelSize; + qreal rawFontAscent; + qreal rawFontDescent; + int rawFontTableSize; + + QRawFont outerRawFont; + { + QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference); + QVERIFY(rawFont.isValid()); + + rawFontFamilyName = rawFont.familyName(); + rawFontPixelSize = rawFont.pixelSize(); + rawFontAscent = rawFont.ascent(); + rawFontDescent = rawFont.descent(); + rawFontTableSize = rawFont.fontTable("glyf").size(); + QVERIFY(rawFontTableSize > 0); + + { + QRawFont otherRawFont(rawFont); + + otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), + rawFontPixelSize, hintingPreference); + + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + { + QRawFont otherRawFont = rawFont; + + otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), + rawFontPixelSize, hintingPreference); + + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + outerRawFont = rawFont; + + rawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), rawFontPixelSize, + hintingPreference); + } + + QVERIFY(outerRawFont.isValid()); + QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(outerRawFont.familyName(), rawFontFamilyName); + QCOMPARE(outerRawFont.hintingPreference(), hintingPreference); + QCOMPARE(outerRawFont.ascent(), rawFontAscent); + QCOMPARE(outerRawFont.descent(), rawFontDescent); + QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize); + } +} + +void tst_QRawFont::unsupportedWritingSystem_data() +{ + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::unsupportedWritingSystem() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(QLatin1String(SRCDIR "testfont.ttf")); + + QFont font("QtBidiTestFont"); + font.setHintingPreference(hintingPreference); + font.setPixelSize(12.0); + + QRawFont rawFont = QRawFont::fromFont(font, QFontDatabase::Any); + QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(rawFont.pixelSize(), 12.0); + + rawFont = QRawFont::fromFont(font, QFontDatabase::Hebrew); + QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(rawFont.pixelSize(), 12.0); + + QString arabicText = QFontDatabase::writingSystemSample(QFontDatabase::Arabic); + + QTextLayout layout; + layout.setFont(font); + layout.setText(arabicText); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList<QGlyphRun> glyphRuns = layout.glyphRuns(); + QCOMPARE(glyphRuns.size(), 1); + + QGlyphRun glyphs = glyphRuns.at(0); + QRawFont layoutFont = glyphs.rawFont(); + QVERIFY(layoutFont.familyName() != QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(layoutFont.pixelSize(), 12.0); + + rawFont = QRawFont::fromFont(font, QFontDatabase::Arabic); + QCOMPARE(rawFont.familyName(), layoutFont.familyName()); + QCOMPARE(rawFont.pixelSize(), 12.0); + + fontDatabase.removeApplicationFont(id); +} + +void tst_QRawFont::rawFontSetPixelSize_data() +{ + QTest::addColumn<QFont::HintingPreference>("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::rawFontSetPixelSize() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QTextLayout layout("Foobar"); + + QFont font = layout.font(); + font.setHintingPreference(hintingPreference); + font.setPixelSize(12); + layout.setFont(font); + + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QGlyphRun glyphs = layout.glyphRuns().at(0); + QRawFont rawFont = glyphs.rawFont(); + QCOMPARE(rawFont.pixelSize(), 12.0); + + rawFont.setPixelSize(24); + QCOMPARE(rawFont.pixelSize(), 24.0); +} + +#if defined(Q_WS_X11) || defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) +void tst_QRawFont::multipleRawFontsFromData() +{ + QFile file(QString::fromLatin1(SRCDIR "testfont.ttf")); + QRawFont testFont; + if (file.open(QIODevice::ReadOnly)) { + testFont.loadFromData(file.readAll(), 11, QFont::PreferDefaultHinting); + file.close(); + } + file.setFileName(QLatin1String(SRCDIR "testfont_bold_italic.ttf")); + QRawFont testFontBoldItalic; + if (file.open(QIODevice::ReadOnly)) + testFontBoldItalic.loadFromData(file.readAll(), 11, QFont::PreferDefaultHinting); + + QVERIFY(testFont.familyName() != (testFontBoldItalic.familyName()) + || testFont.styleName() != (testFontBoldItalic.styleName())); +} +#endif + +#endif // QT_NO_RAWFONT + +QTEST_MAIN(tst_QRawFont) +#include "tst_qrawfont.moc" + diff --git a/tests/auto/gui/text/qstatictext/qstatictext.pro b/tests/auto/gui/text/qstatictext/qstatictext.pro new file mode 100644 index 0000000000..a8398dccf9 --- /dev/null +++ b/tests/auto/gui/text/qstatictext/qstatictext.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += widgets widgets-private +QT += core core-private gui gui-private +SOURCES += tst_qstatictext.cpp + +CONFIG += insignificant_test # QTBUG-21290 - crashes on qpa, xcb diff --git a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp new file mode 100644 index 0000000000..79cbd692ea --- /dev/null +++ b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp @@ -0,0 +1,870 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtWidgets/QApplication> +#include <QtGui/QPainter> +#include <QtGui/QImage> + +#include <qstatictext.h> +#include <qpaintengine.h> + +#include <private/qstatictext_p.h> +#include <private/qapplication_p.h> + +// #define DEBUG_SAVE_IMAGE + +class tst_QStaticText: public QObject +{ + Q_OBJECT +public: + tst_QStaticText() {} + +private slots: + void initTestCase(); + + void init(); + void cleanup(); + + void constructionAndDestruction(); + void drawToPoint_data(); + void drawToPoint(); + void drawToRect_data(); + void drawToRect(); + void setFont(); + void setTextWidth(); + void prepareToCorrectData(); + void prepareToWrongData(); + + void copyConstructor(); + + void translatedPainter(); + void rotatedPainter(); + void scaledPainter(); + void projectedPainter(); +#if 0 + void rotatedScaledAndTranslatedPainter_data(); + void rotatedScaledAndTranslatedPainter(); +#endif + void transformationChanged(); + + void plainTextVsRichText(); + + void setPenPlainText(); + void setPenRichText(); + void richTextOverridesPen(); + + void drawStruckOutText(); + void drawOverlinedText(); + void drawUnderlinedText(); + + void unprintableCharacter_qtbug12614(); + + void underlinedColor_qtbug20159(); + void textDocumentColor(); + +private: + bool supportsTransformations() const; + + QImage const m_whiteSquare; +}; + +void tst_QStaticText::initTestCase() +{ + // a "blank" square; we compare against in our testfunctions to verify + // that we have actually painted something + QPixmap pm(1000, 1000); + pm.fill(Qt::white); + const_cast<QImage&>(m_whiteSquare) = pm.toImage(); +} + +void tst_QStaticText::init() +{ +} + +void tst_QStaticText::cleanup() +{ +} + +void tst_QStaticText::constructionAndDestruction() +{ + QStaticText text("My text"); +} + +void tst_QStaticText::copyConstructor() +{ + QStaticText text(QLatin1String("My text")); + + QTextOption textOption(Qt::AlignRight); + text.setTextOption(textOption); + + text.setPerformanceHint(QStaticText::AggressiveCaching); + text.setTextWidth(123.456); + text.setTextFormat(Qt::PlainText); + + QStaticText copiedText(text); + copiedText.setText(QLatin1String("Other text")); + + QCOMPARE(copiedText.textOption().alignment(), Qt::AlignRight); + QCOMPARE(copiedText.performanceHint(), QStaticText::AggressiveCaching); + QCOMPARE(copiedText.textWidth(), 123.456); + QCOMPARE(copiedText.textFormat(), Qt::PlainText); + + QStaticText otherCopiedText(copiedText); + otherCopiedText.setTextWidth(789); + + QCOMPARE(otherCopiedText.text(), QString::fromLatin1("Other text")); +} + +Q_DECLARE_METATYPE(QStaticText::PerformanceHint) +void tst_QStaticText::drawToPoint_data() +{ + QTest::addColumn<QStaticText::PerformanceHint>("performanceHint"); + + QTest::newRow("Moderate caching") << QStaticText::ModerateCaching; + QTest::newRow("Aggressive caching") << QStaticText::AggressiveCaching; +} + +void tst_QStaticText::drawToPoint() +{ + QFETCH(QStaticText::PerformanceHint, performanceHint); + + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextFormat(Qt::PlainText); + text.setPerformanceHint(performanceHint); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); + } + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::drawToRect_data() +{ + QTest::addColumn<QStaticText::PerformanceHint>("performanceHint"); + + QTest::newRow("Moderate caching") << QStaticText::ModerateCaching; + QTest::newRow("Aggressive caching") << QStaticText::AggressiveCaching; +} + +void tst_QStaticText::drawToRect() +{ + QFETCH(QStaticText::PerformanceHint, performanceHint); + + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextWidth(10), + p.setClipRect(QRectF(11, 12, 10, 500)); + text.setPerformanceHint(performanceHint); + text.setTextFormat(Qt::PlainText); + p.drawStaticText(QPointF(11, 12), text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawToRect_imageDrawText.png"); + imageDrawStaticText.save("drawToRect_imageDrawStaticText.png"); +#endif + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::prepareToCorrectData() +{ + QTransform transform; + transform.scale(2.0, 2.0); + transform.rotate(90, Qt::ZAxis); + + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.setTransform(transform); + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + p.setTransform(transform); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.prepare(transform, p.font()); + text.setTextFormat(Qt::PlainText); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("prepareToCorrectData_imageDrawText.png"); + imageDrawStaticText.save("prepareToCorrectData_imageDrawStaticText.png"); +#endif + +#ifdef Q_WS_QPA + QEXPECT_FAIL("", "QTBUG-20977 fails on qpa", Abort); +#endif + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + + if (!supportsTransformations()) + QEXPECT_FAIL("", "Graphics system does not support transformed text on this platform", Abort); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::prepareToWrongData() +{ + QTransform transform; + transform.scale(2.0, 2.0); + transform.rotate(90, Qt::ZAxis); + + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.prepare(transform, p.font()); + text.setTextFormat(Qt::PlainText); + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); + } + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + + +void tst_QStaticText::setFont() +{ + QFont font = QApplication::font(); + font.setBold(true); + font.setPointSize(28); + + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.drawText(QRectF(0, 0, 1000, 1000), 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + + p.setFont(font); + p.drawText(QRectF(11, 120, 1000, 1000), 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + + QStaticText text; + text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextFormat(Qt::PlainText); + + p.drawStaticText(0, 0, text); + + p.setFont(font); + p.drawStaticText(11, 120, text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("setFont_imageDrawText.png"); + imageDrawStaticText.save("setFont_imageDrawStaticText.png"); +#endif + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::setTextWidth() +{ + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.drawText(QRectF(11, 12, 10, 500), "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextWidth(10); + p.setClipRect(QRectF(11, 12, 10, 500)); + p.drawStaticText(QPointF(11, 12), text); + } + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::translatedPainter() +{ + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.translate(100, 200); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + p.translate(100, 200); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextFormat(Qt::PlainText); + + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); + } + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +bool tst_QStaticText::supportsTransformations() const +{ + QPixmap pm(10, 10); + QPainter p(&pm); + QPaintEngine *engine = p.paintEngine(); + + QPaintEngine::Type type = engine->type(); + + if (type == QPaintEngine::OpenGL +#if !defined(Q_WS_WIN) && !defined(Q_WS_X11) && !defined(Q_WS_MAC) + || type == QPaintEngine::Raster +#endif + ) + return false; + + return true; +} + +void tst_QStaticText::rotatedPainter() +{ + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.rotate(30.0); + p.drawText(QRectF(0, 0, 1000, 100), 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextFormat(Qt::PlainText); + + QPainter p(&imageDrawStaticText); + p.rotate(30.0); + p.drawStaticText(QPoint(0, 0), text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("rotatedPainter_imageDrawText.png"); + imageDrawStaticText.save("rotatedPainter_imageDrawStaticText.png"); +#endif + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + + if (!supportsTransformations()) + QEXPECT_FAIL("", "Graphics system does not support transformed text on this platform", Abort); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::scaledPainter() +{ + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.scale(2.0, 0.2); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + p.scale(2.0, 0.2); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextFormat(Qt::PlainText); + + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); + } + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + + if (!supportsTransformations()) + QEXPECT_FAIL("", "Graphics system does not support transformed text on this platform", Abort); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::projectedPainter() +{ + QTransform transform; + transform.rotate(90, Qt::XAxis); + + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.setTransform(transform); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + p.setTransform(transform); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextFormat(Qt::PlainText); + + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); + } + + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +#if 0 +void tst_QStaticText::rotatedScaledAndTranslatedPainter_data() +{ + QTest::addColumn<qreal>("offset"); + + for (int i=0; i<100; ++i) { + qreal offset = 300 + i / 100.; + QTest::newRow(QByteArray::number(offset).constData()) << offset; + } +} + +void tst_QStaticText::rotatedScaledAndTranslatedPainter() +{ + QFETCH(qreal, offset); + + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.translate(offset, 0); + p.rotate(45.0); + p.scale(2.0, 2.0); + p.translate(100, 200); + + p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + p.translate(offset, 0); + p.rotate(45.0); + p.scale(2.0, 2.0); + p.translate(100, 200); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextFormat(Qt::PlainText); + + p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("rotatedScaledAndPainter_imageDrawText.png"); + imageDrawStaticText.save("rotatedScaledAndPainter_imageDrawStaticText.png"); +#endif + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + + if (!supportsTransformations()) + QEXPECT_FAIL("", "Graphics system does not support transformed text on this platform", Abort); + QCOMPARE(imageDrawStaticText, imageDrawText); +} +#endif + +void tst_QStaticText::transformationChanged() +{ + QPixmap imageDrawText(1000, 1000); + imageDrawText.fill(Qt::white); + { + QPainter p(&imageDrawText); + p.rotate(33.0); + p.scale(0.5, 0.7); + + p.drawText(QRectF(0, 0, 1000, 1000), 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + + p.scale(2.0, 2.5); + p.drawText(QRectF(0, 0, 1000, 1000), 0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + } + + QPixmap imageDrawStaticText(1000, 1000); + imageDrawStaticText.fill(Qt::white); + { + QPainter p(&imageDrawStaticText); + p.rotate(33.0); + p.scale(0.5, 0.7); + + QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); + text.setTextFormat(Qt::PlainText); + + p.drawStaticText(QPointF(0, 0), text); + + p.scale(2.0, 2.5); + p.drawStaticText(QPointF(0, 0), text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("transformationChanged_imageDrawText.png"); + imageDrawStaticText.save("transformationChanged_imageDrawStaticText.png"); +#endif + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + + if (!supportsTransformations()) + QEXPECT_FAIL("", "Graphics system does not support transformed text on this platform", Abort); + QCOMPARE(imageDrawStaticText, imageDrawText); +} + +void tst_QStaticText::plainTextVsRichText() +{ + QPixmap imagePlainText(1000, 1000); + imagePlainText.fill(Qt::white); + { + QPainter p(&imagePlainText); + + QStaticText staticText; + staticText.setText("FOObar"); + staticText.setTextFormat(Qt::PlainText); + + p.drawStaticText(10, 10, staticText); + } + + QPixmap imageRichText(1000, 1000); + imageRichText.fill(Qt::white); + { + QPainter p(&imageRichText); + + QStaticText staticText; + staticText.setText("<html><body>FOObar</body></html>"); + staticText.setTextFormat(Qt::RichText); + + p.drawStaticText(10, 10, staticText); + } + +#if defined(DEBUG_SAVE_IMAGE) + imagePlainText.save("plainTextVsRichText_imagePlainText.png"); + imageRichText.save("plainTextVsRichText_imageRichText.png"); +#endif + + QVERIFY(imagePlainText.toImage() != m_whiteSquare); + QCOMPARE(imagePlainText, imageRichText); +} + +void tst_QStaticText::setPenPlainText() +{ + QFont font = QApplication::font(); + font.setStyleStrategy(QFont::NoAntialias); + + QFontMetricsF fm(font); + QPixmap image(qCeil(fm.width("XXXXX")), qCeil(fm.height())); + image.fill(Qt::white); + { + QPainter p(&image); + p.setFont(font); + p.setPen(Qt::green); + + QStaticText staticText("XXXXX"); + staticText.setTextFormat(Qt::PlainText); + p.drawStaticText(0, 0, staticText); + } + + QImage img = image.toImage(); + for (int x=0; x<img.width(); ++x) { + for (int y=0; y<img.height(); ++y) { + QRgb pixel = img.pixel(x, y); + QVERIFY(pixel == QColor(Qt::white).rgba() + || pixel == QColor(Qt::green).rgba()); + } + } +} + +void tst_QStaticText::setPenRichText() +{ + QFont font = QApplication::font(); + font.setStyleStrategy(QFont::NoAntialias); + + QFontMetricsF fm(font); + QPixmap image(qCeil(fm.width("XXXXX")), qCeil(fm.height())); + image.fill(Qt::white); + { + QPainter p(&image); + p.setFont(font); + p.setPen(Qt::green); + + QStaticText staticText; + staticText.setText("<html><body>XXXXX</body></html>"); + staticText.setTextFormat(Qt::RichText); + p.drawStaticText(0, 0, staticText); + } + + QImage img = image.toImage(); + for (int x=0; x<img.width(); ++x) { + for (int y=0; y<img.height(); ++y) { + QRgb pixel = img.pixel(x, y); + QVERIFY(pixel == QColor(Qt::white).rgba() + || pixel == QColor(Qt::green).rgba()); + } + } +} + +void tst_QStaticText::richTextOverridesPen() +{ + QFont font = QApplication::font(); + font.setStyleStrategy(QFont::NoAntialias); + + QFontMetricsF fm(font); + QPixmap image(qCeil(fm.width("XXXXX")), qCeil(fm.height())); + image.fill(Qt::white); + { + QPainter p(&image); + p.setFont(font); + p.setPen(Qt::green); + + QStaticText staticText; + staticText.setText("<html><body><font color=\"#ff0000\">XXXXX</font></body></html>"); + staticText.setTextFormat(Qt::RichText); + p.drawStaticText(0, 0, staticText); + } + + QImage img = image.toImage(); + for (int x=0; x<img.width(); ++x) { + for (int y=0; y<img.height(); ++y) { + QRgb pixel = img.pixel(x, y); + QVERIFY(pixel == QColor(Qt::white).rgba() + || pixel == QColor(Qt::red).rgba()); + } + } +} + +void tst_QStaticText::drawStruckOutText() +{ + QPixmap imageDrawText(1000, 1000); + QPixmap imageDrawStaticText(1000, 1000); + + imageDrawText.fill(Qt::white); + imageDrawStaticText.fill(Qt::white); + + QString s = QString::fromLatin1("Foobar"); + + QFont font; + font.setStrikeOut(true); + + { + QPainter p(&imageDrawText); + p.setFont(font); + p.drawText(QPointF(50, 50), s); + } + + { + QPainter p(&imageDrawStaticText); + QStaticText text = QStaticText(s); + p.setFont(font); + p.drawStaticText(QPointF(50, 50 - QFontMetricsF(p.font()).ascent()), text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawStruckOutText_imageDrawText.png"); + imageDrawStaticText.save("drawStruckOutText_imageDrawStaticText.png"); +#endif + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + QCOMPARE(imageDrawText, imageDrawStaticText); +} + +void tst_QStaticText::drawOverlinedText() +{ + QPixmap imageDrawText(1000, 1000); + QPixmap imageDrawStaticText(1000, 1000); + + imageDrawText.fill(Qt::white); + imageDrawStaticText.fill(Qt::white); + + QString s = QString::fromLatin1("Foobar"); + + QFont font; + font.setOverline(true); + + { + QPainter p(&imageDrawText); + p.setFont(font); + p.drawText(QPointF(50, 50), s); + } + + { + QPainter p(&imageDrawStaticText); + QStaticText text = QStaticText(s); + p.setFont(font); + p.drawStaticText(QPointF(50, 50 - QFontMetricsF(p.font()).ascent()), text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawOverlinedText_imageDrawText.png"); + imageDrawStaticText.save("drawOverlinedText_imageDrawStaticText.png"); +#endif + + QVERIFY(imageDrawText.toImage() != m_whiteSquare); + QCOMPARE(imageDrawText, imageDrawStaticText); +} + +void tst_QStaticText::drawUnderlinedText() +{ + QPixmap imageDrawText(1000, 1000); + QPixmap imageDrawStaticText(1000, 1000); + + imageDrawText.fill(Qt::white); + imageDrawStaticText.fill(Qt::white); + + QString s = QString::fromLatin1("Foobar"); + + QFont font; + font.setUnderline(true); + + { + QPainter p(&imageDrawText); + p.setFont(font); + p.drawText(QPointF(50, 50), s); + } + + { + QPainter p(&imageDrawStaticText); + QStaticText text = QStaticText(s); + p.setFont(font); + p.drawStaticText(QPointF(50, 50 - QFontMetricsF(p.font()).ascent()), text); + } + +#if defined(DEBUG_SAVE_IMAGE) + imageDrawText.save("drawUnderlinedText_imageDrawText.png"); + imageDrawStaticText.save("drawUnderlinedText_imageDrawStaticText.png"); +#endif + + QCOMPARE(imageDrawText, imageDrawStaticText); +} + +void tst_QStaticText::unprintableCharacter_qtbug12614() +{ + QString s(QChar(0x200B)); // U+200B, ZERO WIDTH SPACE + + QStaticText staticText(s); + + QVERIFY(staticText.size().isValid()); // Force layout. Should not crash. +} + +void tst_QStaticText::underlinedColor_qtbug20159() +{ + QString multiScriptText; + multiScriptText += QChar(0x0410); // Cyrillic 'A' + multiScriptText += QLatin1Char('A'); + + QStaticText staticText(multiScriptText); + + QFont font; + font.setUnderline(true); + + staticText.prepare(QTransform(), font); + + QStaticTextPrivate *d = QStaticTextPrivate::get(&staticText); + QCOMPARE(d->itemCount, 2); + + // The pen should not be marked as dirty when drawing the underline + QVERIFY(!d->items[0].color.isValid()); + QVERIFY(!d->items[1].color.isValid()); +} + +void tst_QStaticText::textDocumentColor() +{ + QStaticText staticText("A<font color=\"red\">B</font>"); + staticText.setTextFormat(Qt::RichText); + staticText.prepare(); + + QStaticTextPrivate *d = QStaticTextPrivate::get(&staticText); + QCOMPARE(d->itemCount, 2); + + // The pen should not be marked as dirty when drawing the underline + QVERIFY(!d->items[0].color.isValid()); + QVERIFY(d->items[1].color.isValid()); + + QCOMPARE(d->items[1].color, QColor(Qt::red)); +} + +QTEST_MAIN(tst_QStaticText) +#include "tst_qstatictext.moc" diff --git a/tests/auto/gui/text/qsyntaxhighlighter/.gitignore b/tests/auto/gui/text/qsyntaxhighlighter/.gitignore new file mode 100644 index 0000000000..3efe6efbe5 --- /dev/null +++ b/tests/auto/gui/text/qsyntaxhighlighter/.gitignore @@ -0,0 +1 @@ +tst_qsyntaxhighlighter diff --git a/tests/auto/gui/text/qsyntaxhighlighter/qsyntaxhighlighter.pro b/tests/auto/gui/text/qsyntaxhighlighter/qsyntaxhighlighter.pro new file mode 100644 index 0000000000..30fb3a5283 --- /dev/null +++ b/tests/auto/gui/text/qsyntaxhighlighter/qsyntaxhighlighter.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qsyntaxhighlighter.cpp + + diff --git a/tests/auto/gui/text/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp b/tests/auto/gui/text/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp new file mode 100644 index 0000000000..24ade2dc91 --- /dev/null +++ b/tests/auto/gui/text/qsyntaxhighlighter/tst_qsyntaxhighlighter.cpp @@ -0,0 +1,549 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QTextDocument> +#include <QTextLayout> +#include <QDebug> +#include <QAbstractTextDocumentLayout> +#include <QSyntaxHighlighter> + +//TESTED_CLASS= +//TESTED_FILES= +// +class QTestDocumentLayout : public QAbstractTextDocumentLayout +{ + Q_OBJECT +public: + inline QTestDocumentLayout(QTextDocument *doc) + : QAbstractTextDocumentLayout(doc), documentChangedCalled(false) {} + + virtual void draw(QPainter *, const QAbstractTextDocumentLayout::PaintContext &) {} + + virtual int hitTest(const QPointF &, Qt::HitTestAccuracy ) const { return 0; } + + virtual void documentChanged(int, int, int) { documentChangedCalled = true; } + + virtual int pageCount() const { return 1; } + + virtual QSizeF documentSize() const { return QSize(); } + + virtual QRectF frameBoundingRect(QTextFrame *) const { return QRectF(); } + virtual QRectF blockBoundingRect(const QTextBlock &) const { return QRectF(); } + + bool documentChangedCalled; +}; + +class tst_QSyntaxHighlighter : public QObject +{ + Q_OBJECT +public: + inline tst_QSyntaxHighlighter() {} + +public slots: + void init(); + void cleanup(); + +private slots: + void basic(); + void basicTwo(); + void removeFormatsOnDelete(); + void emptyBlocks(); + void setCharFormat(); + void highlightOnInit(); + void stopHighlightingWhenStateDoesNotChange(); + void unindent(); + void highlightToEndOfDocument(); + void highlightToEndOfDocument2(); + void preservePreeditArea(); + void task108530(); + void avoidUnnecessaryRehighlight(); + void noContentsChangedDuringHighlight(); + void rehighlight(); + void rehighlightBlock(); + +private: + QTextDocument *doc; + QTestDocumentLayout *lout; + QTextCursor cursor; +}; + +void tst_QSyntaxHighlighter::init() +{ + doc = new QTextDocument; + lout = new QTestDocumentLayout(doc); + doc->setDocumentLayout(lout); + cursor = QTextCursor(doc); +} + +void tst_QSyntaxHighlighter::cleanup() +{ + delete doc; + doc = 0; +} + +class TestHighlighter : public QSyntaxHighlighter +{ +public: + inline TestHighlighter(const QList<QTextLayout::FormatRange> &fmts, QTextDocument *parent) + : QSyntaxHighlighter(parent), formats(fmts), highlighted(false), callCount(0) {} + inline TestHighlighter(QTextDocument *parent) + : QSyntaxHighlighter(parent), highlighted(false), callCount(0) {} + + virtual void highlightBlock(const QString &text) + { + for (int i = 0; i < formats.count(); ++i) { + const QTextLayout::FormatRange &range = formats.at(i); + setFormat(range.start, range.length, range.format); + } + highlighted = true; + highlightedText += text; + ++callCount; + } + + QList<QTextLayout::FormatRange> formats; + bool highlighted; + int callCount; + QString highlightedText; +}; + +QT_BEGIN_NAMESPACE +bool operator==(const QTextLayout::FormatRange &lhs, const QTextLayout::FormatRange &rhs) +{ + return lhs.start == rhs.start + && lhs.length == rhs.length + && lhs.format == rhs.format; +} +QT_END_NAMESPACE + +void tst_QSyntaxHighlighter::basic() +{ + QList<QTextLayout::FormatRange> formats; + QTextLayout::FormatRange range; + range.start = 0; + range.length = 2; + range.format.setForeground(Qt::blue); + formats.append(range); + + range.start = 4; + range.length = 2; + range.format.setFontItalic(true); + formats.append(range); + + range.start = 9; + range.length = 2; + range.format.setFontUnderline(true); + formats.append(range); + + TestHighlighter *hl = new TestHighlighter(formats, doc); + + lout->documentChangedCalled = false; + doc->setPlainText("Hello World"); + QVERIFY(hl->highlighted); + QVERIFY(lout->documentChangedCalled); + + QVERIFY(doc->begin().layout()->additionalFormats() == formats); +} + +class CommentTestHighlighter : public QSyntaxHighlighter +{ +public: + inline CommentTestHighlighter(QTextDocument *parent) + : QSyntaxHighlighter(parent), highlighted(false) {} + + inline void reset() + { + highlighted = false; + } + + virtual void highlightBlock(const QString &text) + { + QTextCharFormat commentFormat; + commentFormat.setForeground(Qt::darkGreen); + commentFormat.setFontWeight(QFont::StyleItalic); + commentFormat.setFontFixedPitch(true); + int textLength = text.length(); + + if (text.startsWith(QLatin1Char(';'))){ + // The entire line is a comment + setFormat(0, textLength, commentFormat); + highlighted = true; + } + } + bool highlighted; +}; + + +void tst_QSyntaxHighlighter::basicTwo() +{ + // Done for task 104409 + CommentTestHighlighter *hl = new CommentTestHighlighter(doc); + doc->setPlainText("; a test"); + QVERIFY(hl->highlighted); + QVERIFY(lout->documentChangedCalled); +} + +void tst_QSyntaxHighlighter::removeFormatsOnDelete() +{ + QList<QTextLayout::FormatRange> formats; + QTextLayout::FormatRange range; + range.start = 0; + range.length = 9; + range.format.setForeground(Qt::blue); + formats.append(range); + + TestHighlighter *hl = new TestHighlighter(formats, doc); + + lout->documentChangedCalled = false; + doc->setPlainText("Hello World"); + QVERIFY(hl->highlighted); + QVERIFY(lout->documentChangedCalled); + + lout->documentChangedCalled = false; + QVERIFY(!doc->begin().layout()->additionalFormats().isEmpty()); + delete hl; + QVERIFY(doc->begin().layout()->additionalFormats().isEmpty()); + QVERIFY(lout->documentChangedCalled); +} + +void tst_QSyntaxHighlighter::emptyBlocks() +{ + TestHighlighter *hl = new TestHighlighter(doc); + + cursor.insertText("Foo"); + cursor.insertBlock(); + cursor.insertBlock(); + hl->highlighted = false; + cursor.insertBlock(); + QVERIFY(hl->highlighted); +} + +void tst_QSyntaxHighlighter::setCharFormat() +{ + TestHighlighter *hl = new TestHighlighter(doc); + + cursor.insertText("FooBar"); + cursor.insertBlock(); + cursor.insertText("Blah"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + QTextCharFormat fmt; + fmt.setFontItalic(true); + hl->highlighted = false; + hl->callCount = 0; + cursor.mergeCharFormat(fmt); + QVERIFY(hl->highlighted); + QCOMPARE(hl->callCount, 2); +} + +void tst_QSyntaxHighlighter::highlightOnInit() +{ + cursor.insertText("Hello"); + cursor.insertBlock(); + cursor.insertText("World"); + + TestHighlighter *hl = new TestHighlighter(doc); + QTest::qWait(100); + QVERIFY(hl->highlighted); +} + +class StateTestHighlighter : public QSyntaxHighlighter +{ +public: + inline StateTestHighlighter(QTextDocument *parent) + : QSyntaxHighlighter(parent), state(0), highlighted(false) {} + + inline void reset() + { + highlighted = false; + state = 0; + } + + virtual void highlightBlock(const QString &text) + { + highlighted = true; + if (text == QLatin1String("changestate")) + setCurrentBlockState(state++); + } + + int state; + bool highlighted; +}; + +void tst_QSyntaxHighlighter::stopHighlightingWhenStateDoesNotChange() +{ + cursor.insertText("state"); + cursor.insertBlock(); + cursor.insertText("changestate"); + cursor.insertBlock(); + cursor.insertText("keepstate"); + cursor.insertBlock(); + cursor.insertText("changestate"); + cursor.insertBlock(); + cursor.insertText("changestate"); + + StateTestHighlighter *hl = new StateTestHighlighter(doc); + QTest::qWait(100); + QVERIFY(hl->highlighted); + + hl->reset(); + + // turn the text of the first block into 'changestate' + cursor.movePosition(QTextCursor::Start); + cursor.insertText("change"); + + // verify that we highlighted only to the 'keepstate' block, + // not beyond + QCOMPARE(hl->state, 2); +} + +void tst_QSyntaxHighlighter::unindent() +{ + const QString spaces(" "); + const QString text("Foobar"); + QString plainText; + for (int i = 0; i < 5; ++i) { + cursor.insertText(spaces + text); + cursor.insertBlock(); + + plainText += spaces; + plainText += text; + plainText += QLatin1Char('\n'); + } + QCOMPARE(doc->toPlainText(), plainText); + + TestHighlighter *hl = new TestHighlighter(doc); + hl->callCount = 0; + + cursor.movePosition(QTextCursor::Start); + cursor.beginEditBlock(); + + plainText.clear(); + for (int i = 0; i < 5; ++i) { + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 4); + cursor.removeSelectedText(); + cursor.movePosition(QTextCursor::NextBlock); + + plainText += text; + plainText += QLatin1Char('\n'); + } + + cursor.endEditBlock(); + QCOMPARE(doc->toPlainText(), plainText); + QCOMPARE(hl->callCount, 5); +} + +void tst_QSyntaxHighlighter::highlightToEndOfDocument() +{ + TestHighlighter *hl = new TestHighlighter(doc); + hl->callCount = 0; + + cursor.movePosition(QTextCursor::Start); + cursor.beginEditBlock(); + + cursor.insertText("Hello"); + cursor.insertBlock(); + cursor.insertBlock(); + cursor.insertText("World"); + cursor.insertBlock(); + + cursor.endEditBlock(); + + QCOMPARE(hl->callCount, 4); +} + +void tst_QSyntaxHighlighter::highlightToEndOfDocument2() +{ + TestHighlighter *hl = new TestHighlighter(doc); + hl->callCount = 0; + + cursor.movePosition(QTextCursor::End); + cursor.beginEditBlock(); + QTextBlockFormat fmt; + fmt.setAlignment(Qt::AlignLeft); + cursor.setBlockFormat(fmt); + cursor.insertText("Three\nLines\nHere"); + cursor.endEditBlock(); + + QCOMPARE(hl->callCount, 3); +} + +void tst_QSyntaxHighlighter::preservePreeditArea() +{ + QList<QTextLayout::FormatRange> formats; + QTextLayout::FormatRange range; + range.start = 0; + range.length = 8; + range.format.setForeground(Qt::blue); + formats << range; + range.start = 9; + range.length = 1; + range.format.setForeground(Qt::red); + formats << range; + TestHighlighter *hl = new TestHighlighter(formats, doc); + + doc->setPlainText("Hello World"); + cursor.movePosition(QTextCursor::Start); + + QTextLayout *layout = cursor.block().layout(); + + layout->setPreeditArea(5, QString("foo")); + range.start = 5; + range.length = 3; + range.format.setFontUnderline(true); + formats.clear(); + formats << range; + + hl->callCount = 0; + + cursor.beginEditBlock(); + layout->setAdditionalFormats(formats); + cursor.endEditBlock(); + + QCOMPARE(hl->callCount, 1); + + formats = layout->additionalFormats(); + QCOMPARE(formats.count(), 3); + + range = formats.at(0); + + QCOMPARE(range.start, 5); + QCOMPARE(range.length, 3); + QVERIFY(range.format.fontUnderline()); + + range = formats.at(1); + QCOMPARE(range.start, 0); + QCOMPARE(range.length, 8 + 3); + + range = formats.at(2); + QCOMPARE(range.start, 9 + 3); + QCOMPARE(range.length, 1); +} + +void tst_QSyntaxHighlighter::task108530() +{ + TestHighlighter *hl = new TestHighlighter(doc); + + cursor.insertText("test"); + hl->callCount = 0; + hl->highlightedText.clear(); + cursor.movePosition(QTextCursor::Start); + cursor.insertBlock(); + + QCOMPARE(hl->highlightedText, QString("test")); + QCOMPARE(hl->callCount, 2); +} + +void tst_QSyntaxHighlighter::avoidUnnecessaryRehighlight() +{ + TestHighlighter *hl = new TestHighlighter(doc); + QVERIFY(!hl->highlighted); + + doc->setPlainText("Hello World"); + QVERIFY(hl->highlighted); + + hl->highlighted = false; + QTest::qWait(100); + QVERIFY(!hl->highlighted); +} + +void tst_QSyntaxHighlighter::noContentsChangedDuringHighlight() +{ + QList<QTextLayout::FormatRange> formats; + QTextLayout::FormatRange range; + range.start = 0; + range.length = 10; + range.format.setForeground(Qt::blue); + formats.append(range); + + TestHighlighter *hl = new TestHighlighter(formats, doc); + + lout->documentChangedCalled = false; + QTextCursor cursor(doc); + + QSignalSpy contentsChangedSpy(doc, SIGNAL(contentsChanged())); + cursor.insertText("Hello World"); + + QCOMPARE(contentsChangedSpy.count(), 1); + QVERIFY(hl->highlighted); + QVERIFY(lout->documentChangedCalled); +} + +void tst_QSyntaxHighlighter::rehighlight() +{ + TestHighlighter *hl = new TestHighlighter(doc); + hl->callCount = 0; + doc->setPlainText("Hello"); + hl->callCount = 0; + hl->rehighlight(); + QCOMPARE(hl->callCount, 1); +} + +void tst_QSyntaxHighlighter::rehighlightBlock() +{ + TestHighlighter *hl = new TestHighlighter(doc); + + cursor.movePosition(QTextCursor::Start); + cursor.beginEditBlock(); + cursor.insertText("Hello"); + cursor.insertBlock(); + cursor.insertText("World"); + cursor.endEditBlock(); + + hl->callCount = 0; + hl->highlightedText.clear(); + QTextBlock block = doc->begin(); + hl->rehighlightBlock(block); + + QCOMPARE(hl->highlightedText, QString("Hello")); + QCOMPARE(hl->callCount, 1); + + hl->callCount = 0; + hl->highlightedText.clear(); + hl->rehighlightBlock(block.next()); + + QCOMPARE(hl->highlightedText, QString("World")); + QCOMPARE(hl->callCount, 1); +} + +QTEST_MAIN(tst_QSyntaxHighlighter) +#include "tst_qsyntaxhighlighter.moc" diff --git a/tests/auto/gui/text/qtextblock/.gitignore b/tests/auto/gui/text/qtextblock/.gitignore new file mode 100644 index 0000000000..648a522140 --- /dev/null +++ b/tests/auto/gui/text/qtextblock/.gitignore @@ -0,0 +1 @@ +tst_qtextblock diff --git a/tests/auto/gui/text/qtextblock/qtextblock.pro b/tests/auto/gui/text/qtextblock/qtextblock.pro new file mode 100644 index 0000000000..d50ef5ca78 --- /dev/null +++ b/tests/auto/gui/text/qtextblock/qtextblock.pro @@ -0,0 +1,9 @@ +load(qttest_p4) + +QT += widgets widgets-private +QT += core-private gui-private + +SOURCES += tst_qtextblock.cpp + + + diff --git a/tests/auto/gui/text/qtextblock/tst_qtextblock.cpp b/tests/auto/gui/text/qtextblock/tst_qtextblock.cpp new file mode 100644 index 0000000000..b04a6f5559 --- /dev/null +++ b/tests/auto/gui/text/qtextblock/tst_qtextblock.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#define protected public +#include <qtextdocument.h> +#undef protected +#include <qdebug.h> +#ifndef Q_WS_WIN +#include <private/qtextdocument_p.h> +#endif + + + +#include <qtextobject.h> +#include <qtextcursor.h> + + +//TESTED_FILES= + +QT_FORWARD_DECLARE_CLASS(QTextDocument) + +class tst_QTextBlock : public QObject +{ + Q_OBJECT + +public: + tst_QTextBlock(); + + +public slots: + void init(); + void cleanup(); +private slots: + void fragmentOverBlockBoundaries(); + void excludeParagraphSeparatorFragment(); + void backwardsBlockIterator(); + void previousBlock_qtbug18026(); + void removedBlock_qtbug18500(); + +private: + QTextDocument *doc; + QTextCursor cursor; +}; + +tst_QTextBlock::tst_QTextBlock() +{} + +void tst_QTextBlock::init() +{ + doc = new QTextDocument; + cursor = QTextCursor(doc); +} + +void tst_QTextBlock::cleanup() +{ + cursor = QTextCursor(); + delete doc; + doc = 0; +} + +void tst_QTextBlock::fragmentOverBlockBoundaries() +{ + /* this creates two fragments in the piecetable: + * 1) 'hello<parag separator here>world' + * 2) '<parag separator>' + * (they are not united because the former was interested after the latter, + * hence their position in the pt buffer is the other way around) + */ + cursor.insertText("Hello"); + cursor.insertBlock(); + cursor.insertText("World"); + + cursor.movePosition(QTextCursor::Start); + + const QTextDocument *doc = cursor.block().document(); + QVERIFY(doc); + // Block separators are always a fragment of their self. Thus: + // |Hello|\b|World|\b| +#if !defined(Q_WS_WIN) && !defined(Q_WS_S60) + QVERIFY(doc->docHandle()->fragmentMap().numNodes() == 4); +#endif + QCOMPARE(cursor.block().text(), QString("Hello")); + cursor.movePosition(QTextCursor::NextBlock); + QCOMPARE(cursor.block().text(), QString("World")); +} + +void tst_QTextBlock::excludeParagraphSeparatorFragment() +{ + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + cursor.insertText("Hello", fmt); + + QTextBlock block = doc->begin(); + QVERIFY(block.isValid()); + + QTextBlock::Iterator it = block.begin(); + + QTextFragment fragment = it.fragment(); + QVERIFY(fragment.isValid()); + QCOMPARE(fragment.text(), QString("Hello")); + + ++it; + QVERIFY(it.atEnd()); + QVERIFY(it == block.end()); +} + +void tst_QTextBlock::backwardsBlockIterator() +{ + QTextCharFormat fmt; + + fmt.setForeground(Qt::magenta); + cursor.insertText("A", fmt); + + fmt.setForeground(Qt::red); + cursor.insertText("A", fmt); + + fmt.setForeground(Qt::magenta); + cursor.insertText("A", fmt); + + QTextBlock block = doc->begin(); + QVERIFY(block.isValid()); + + QTextBlock::Iterator it = block.begin(); + QCOMPARE(it.fragment().position(), 0); + ++it; + QCOMPARE(it.fragment().position(), 1); + ++it; + + QCOMPARE(it.fragment().position(), 2); + + --it; + QCOMPARE(it.fragment().position(), 1); + --it; + QCOMPARE(it.fragment().position(), 0); +} + +void tst_QTextBlock::previousBlock_qtbug18026() +{ + QTextBlock last = doc->end().previous(); + QVERIFY(last.isValid()); +} + +void tst_QTextBlock::removedBlock_qtbug18500() +{ + cursor.insertText("line 1\nline 2\nline 3 \nline 4\n"); + cursor.setPosition(7); + QTextBlock block = cursor.block(); + cursor.setPosition(21, QTextCursor::KeepAnchor); + + cursor.removeSelectedText(); + QVERIFY(!block.isValid()); +} + +QTEST_MAIN(tst_QTextBlock) +#include "tst_qtextblock.moc" diff --git a/tests/auto/gui/text/qtextcursor/.gitignore b/tests/auto/gui/text/qtextcursor/.gitignore new file mode 100644 index 0000000000..b9b1f8e7d6 --- /dev/null +++ b/tests/auto/gui/text/qtextcursor/.gitignore @@ -0,0 +1 @@ +tst_qtextcursor diff --git a/tests/auto/gui/text/qtextcursor/qtextcursor.pro b/tests/auto/gui/text/qtextcursor/qtextcursor.pro new file mode 100644 index 0000000000..828b90ca16 --- /dev/null +++ b/tests/auto/gui/text/qtextcursor/qtextcursor.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qtextcursor.cpp + + + diff --git a/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp b/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp new file mode 100644 index 0000000000..2b0ba422e0 --- /dev/null +++ b/tests/auto/gui/text/qtextcursor/tst_qtextcursor.cpp @@ -0,0 +1,1862 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <qtextdocument.h> +#include <qtexttable.h> +#include <qvariant.h> +#include <qtextdocumentfragment.h> +#include <qabstracttextdocumentlayout.h> +#include <qtextlayout.h> +#include <qtextcursor.h> +#include <qdebug.h> + +//TESTED_FILES=gui/text/qtextcursor.cpp gui/text/qtextcursor_p.h + +QT_FORWARD_DECLARE_CLASS(QTextDocument) + +class tst_QTextCursor : public QObject +{ + Q_OBJECT + +public: + tst_QTextCursor(); + + +public slots: + void init(); + void cleanup(); +private slots: + void navigation1(); + void navigation2_data(); + void navigation2(); + void navigation3(); + void navigation4(); + void navigation5(); + void navigation6(); + void navigation7(); + void navigation8(); + void navigation9(); + void navigation10(); + void movePositionEndOfLine(); + void insertBlock(); + void insertWithBlockSeparator1(); + void insertWithBlockSeparator2(); + void insertWithBlockSeparator3(); + void insertWithBlockSeparator4(); + void clearObjectType1(); + void clearObjectType2(); + void clearObjectType3(); + void comparisonOperators1(); + void comparisonOperators2(); + void selection1(); + void dontCopyTableAttributes(); + + void checkFrame1(); + void checkFrame2(); + + void tableMovement(); + void selectionsInTable(); + + void insertBlockToUseCharFormat(); + + void selectedText(); + + void insertBlockShouldRemoveSelection(); + void insertBlockShouldRemoveSelection2(); + void mergeCellShouldUpdateSelection(); + + void joinPreviousEditBlock(); + + void setBlockFormatInTable(); + + void blockCharFormat(); + void blockCharFormat2(); + void blockCharFormat3(); + void blockCharFormatOnSelection(); + + void anchorInitialized1(); + void anchorInitialized2(); + void anchorInitialized3(); + + void selectWord(); + void selectWordWithSeparators_data(); + void selectWordWithSeparators(); + void startOfWord(); + void selectBlock(); + void selectVisually(); + + void insertText(); + + void insertFragmentShouldUseCurrentCharFormat(); + + void endOfLine(); + + void editBlocksDuringRemove(); + void selectAllDuringRemove(); + + void update_data(); + void update(); + + void disallowSettingObjectIndicesOnCharFormats(); + + void blockAndColumnNumber(); + + void clearCells(); + + void task244408_wordUnderCursor_data(); + void task244408_wordUnderCursor(); + + void adjustCursorsOnInsert(); + + void cursorPositionWithBlockUndoAndRedo(); + void cursorPositionWithBlockUndoAndRedo2(); + void cursorPositionWithBlockUndoAndRedo3(); + +private: + int blockCount(); + + QTextDocument *doc; + QTextCursor cursor; +}; + +Q_DECLARE_METATYPE(QList<QVariant>) + +tst_QTextCursor::tst_QTextCursor() +{} + +void tst_QTextCursor::init() +{ + doc = new QTextDocument; + cursor = QTextCursor(doc); +} + +void tst_QTextCursor::cleanup() +{ + cursor = QTextCursor(); + delete doc; + doc = 0; +} + +void tst_QTextCursor::navigation1() +{ + + cursor.insertText("Hello World"); + QVERIFY(doc->toPlainText() == "Hello World"); + + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.position() == 11); + cursor.deletePreviousChar(); + QVERIFY(cursor.position() == 10); + cursor.deletePreviousChar(); + cursor.deletePreviousChar(); + cursor.deletePreviousChar(); + cursor.deletePreviousChar(); + cursor.deletePreviousChar(); + QVERIFY(doc->toPlainText() == "Hello"); + + QTextCursor otherCursor(doc); + otherCursor.movePosition(QTextCursor::Start); + otherCursor.movePosition(QTextCursor::Right); + cursor = otherCursor; + cursor.movePosition(QTextCursor::Right); + QVERIFY(cursor != otherCursor); + otherCursor.insertText("Hey"); + QVERIFY(cursor.position() == 5); + + doc->undo(); + QVERIFY(cursor.position() == 2); + doc->redo(); + QVERIFY(cursor.position() == 5); + + doc->undo(); + + doc->undo(); + QVERIFY(doc->toPlainText() == "Hello World"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 6); + QVERIFY(cursor.position() == 6); + otherCursor = cursor; + otherCursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 2); + otherCursor.deletePreviousChar(); + otherCursor.deletePreviousChar(); + otherCursor.deletePreviousChar(); + QVERIFY(cursor.position() == 5); + + cursor.movePosition(QTextCursor::End); + cursor.insertBlock(); + { + int oldPos = cursor.position(); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.position() == oldPos); + } + QVERIFY(cursor.atBlockStart()); + QVERIFY(cursor.position() == 9); + + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + cursor.insertText("Test", fmt); + QVERIFY(fmt == cursor.charFormat()); + QVERIFY(cursor.position() == 13); +} + +void tst_QTextCursor::navigation2_data() +{ + QTest::addColumn<QStringList>("sl"); + QTest::addColumn<QList<QVariant> >("movement"); + QTest::addColumn<int>("finalPos"); + + QTest::newRow("startBlock1") << QStringList("Happy happy happy joy joy joy") + << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock)) << 0; + QTest::newRow("endBlock1") << QStringList("Happy happy happy joy joy joy") + << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock) + << QVariant(QTextCursor::EndOfBlock)) << 29; + QTest::newRow("startBlock2") << QStringList("Happy happy happy joy joy joy") + << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock) + << QVariant(QTextCursor::EndOfBlock) + << QVariant(QTextCursor::StartOfBlock)) << 0; + QTest::newRow("endBlock2") << QStringList("Happy happy happy joy joy joy") + << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock) + << QVariant(QTextCursor::EndOfBlock) + << QVariant(QTextCursor::StartOfBlock) + << QVariant(QTextCursor::EndOfBlock) + ) << 29; + QTest::newRow("multiBlock1") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock)) + << 18; + QTest::newRow("multiBlock2") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock) + << QVariant(QTextCursor::EndOfBlock)) + << 29; + QTest::newRow("multiBlock3") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::StartOfBlock) + << QVariant(QTextCursor::StartOfBlock)) + << 18; + QTest::newRow("multiBlock4") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::Start) + << QVariant(QTextCursor::EndOfBlock)) + << 17; + QTest::newRow("multiBlock5") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::Start) + << QVariant(QTextCursor::EndOfBlock) + << QVariant(QTextCursor::EndOfBlock)) + << 17; + QTest::newRow("multiBlock6") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::End) + << QVariant(QTextCursor::StartOfBlock)) + << 18; + QTest::newRow("multiBlock7") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock)) + << 0; + QTest::newRow("multiBlock8") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock) + << QVariant(QTextCursor::EndOfBlock)) + << 17; + QTest::newRow("multiBlock9") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock) + << QVariant(QTextCursor::NextBlock)) + << 18; + QTest::newRow("multiBlock10") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock) + << QVariant(QTextCursor::NextBlock) + << QVariant(QTextCursor::NextBlock)) + << 18; + QTest::newRow("multiBlock11") << (QStringList() << QString("Happy happy happy") + << QString("Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousBlock) + << QVariant(QTextCursor::NextBlock) + << QVariant(QTextCursor::EndOfBlock)) + << 29; + QTest::newRow("PreviousWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord)) + << 26; + QTest::newRow("PreviousWord2") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord) + << QVariant(QTextCursor::PreviousWord)) + << 22; + QTest::newRow("EndWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord) + << QVariant(QTextCursor::PreviousWord) + << QVariant(QTextCursor::EndOfWord)) + << 25; + QTest::newRow("NextWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord) + << QVariant(QTextCursor::PreviousWord) + << QVariant(QTextCursor::NextWord)) + << 26; + QTest::newRow("NextWord2") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::Start) + << QVariant(QTextCursor::NextWord) + << QVariant(QTextCursor::EndOfWord)) + << 11; + QTest::newRow("StartWord1") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousWord) + << QVariant(QTextCursor::PreviousWord) + << QVariant(QTextCursor::StartOfWord)) + << 22; + QTest::newRow("StartWord3") << (QStringList() << QString("Happy happy happy Joy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::Start) + << QVariant(QTextCursor::NextWord) + << QVariant(QTextCursor::EndOfWord) + << QVariant(QTextCursor::StartOfWord)) + << 6; + + QTest::newRow("PreviousCharacter") << (QStringList() << QString("Happy happy Joy Joy")) + << (QList<QVariant>() << QVariant(QTextCursor::PreviousCharacter) + << QVariant(QTextCursor::PreviousCharacter)) + << 17; +} + +void tst_QTextCursor::navigation2() +{ + QFETCH(QStringList, sl); + QFETCH(QList<QVariant>, movement); + int i; + for (i = 0; i < sl.size(); ++i) { + cursor.insertText(sl.at(i)); + if (i < sl.size() - 1) + cursor.insertBlock(); + } + + for (i = 0; i < movement.size(); ++i) + cursor.movePosition(QTextCursor::MoveOperation(movement.at(i).toInt())); + QTEST(cursor.position(), "finalPos"); +} + +void tst_QTextCursor::navigation3() +{ + cursor.insertText("a"); + cursor.deletePreviousChar(); + QCOMPARE(cursor.position(), 0); + QVERIFY(doc->toPlainText().isEmpty()); +} + +void tst_QTextCursor::navigation4() +{ + cursor.insertText(" Test "); + + cursor.setPosition(4); + cursor.movePosition(QTextCursor::EndOfWord); + QCOMPARE(cursor.position(), 6); +} + +void tst_QTextCursor::navigation5() +{ + cursor.insertText("Test"); + cursor.insertBlock(); + cursor.insertText("Test"); + + cursor.setPosition(0); + cursor.movePosition(QTextCursor::EndOfBlock); + QCOMPARE(cursor.position(), 4); +} + +void tst_QTextCursor::navigation6() +{ + // triger creation of document layout, so that QTextLines are there + doc->documentLayout(); + doc->setTextWidth(1000); + + cursor.insertText("Test "); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::EndOfLine); + QCOMPARE(cursor.position(), 8); +} + +void tst_QTextCursor::navigation7() +{ + QVERIFY(doc->isEmpty()); + for (int i = QTextCursor::Start; i <= QTextCursor::WordRight; ++i) + QVERIFY(!cursor.movePosition(QTextCursor::MoveOperation(i))); + + doc->setPlainText("Hello World"); + cursor.movePosition(QTextCursor::Start); + do { + } while (cursor.movePosition(QTextCursor::NextCharacter)); + QVERIFY(true /*reached*/); +} + +void tst_QTextCursor::navigation8() +{ + cursor.insertList(QTextListFormat::ListDecimal); + QCOMPARE(cursor.position(), 1); + cursor.insertText("foo"); + QCOMPARE(cursor.position(), 4); + + cursor.insertList(QTextListFormat::ListCircle); + QCOMPARE(cursor.position(), 5); + cursor.insertText("something"); + QCOMPARE(cursor.position(), 14); + + cursor.movePosition(QTextCursor::PreviousCharacter); + QCOMPARE(cursor.position(), 13); + + cursor.setPosition(2); + cursor.movePosition(QTextCursor::NextCharacter); + QCOMPARE(cursor.position(), 3); +} + +void tst_QTextCursor::navigation9() +{ + cursor.insertText("Hello &-=+\t World"); + cursor.movePosition(QTextCursor::PreviousWord); + QCOMPARE(cursor.position(), 15); + cursor.movePosition(QTextCursor::PreviousWord); + QCOMPARE(cursor.position(), 7); + cursor.movePosition(QTextCursor::PreviousWord); + QCOMPARE(cursor.position(), 0); + cursor.movePosition(QTextCursor::NextWord); + QCOMPARE(cursor.position(), 7); + cursor.movePosition(QTextCursor::NextWord); + QCOMPARE(cursor.position(), 15); +} + +void tst_QTextCursor::navigation10() +{ + doc->setHtml("<html><p>just a simple paragraph.</p>" + "<table>" + "<tr><td>Cell number 1</td><td>another cell</td><td></td><td>previous</br>is</br>empty</td></tr>" + "<tr><td>row 2</td><td colspan=\"2\">foo bar</td><td>last cell</td></tr>" + "<tr><td colspan=\"3\">row 3</td><td>a</td></tr>" + "</table></html"); + QCOMPARE(cursor.position(), 101); // end of document + cursor.setPosition(0); + QCOMPARE(cursor.position(), 0); + bool ok = cursor.movePosition(QTextCursor::EndOfLine); + QVERIFY(ok); + QCOMPARE(cursor.position(), 24); + ok = cursor.movePosition(QTextCursor::NextBlock); + QCOMPARE(cursor.position(), 25); // cell 1 + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 39); // another.. + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 52); // empty + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 53); // last on row 1 + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 69); // row 2 + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 75); + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 83); + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 93); // row 3 + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 99); + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok == false); + QCOMPARE(cursor.position(), 99); // didn't move. + QVERIFY(cursor.currentTable()); + + // same thing in reverse... + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 93); + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 83); + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 75); + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 69); + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 53); + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 52); + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 39); + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 25); + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(!ok); + QCOMPARE(cursor.position(), 25); // can't leave the table + + ok = cursor.movePosition(QTextCursor::NextRow); + QVERIFY(ok); + QCOMPARE(cursor.position(), 69); + ok = cursor.movePosition(QTextCursor::NextRow); + QVERIFY(ok); + QCOMPARE(cursor.position(), 93); + ok = cursor.movePosition(QTextCursor::NextRow); + QVERIFY(!ok); + QCOMPARE(cursor.position(), 93); // didn't move + + ok = cursor.movePosition(QTextCursor::PreviousRow); + QVERIFY(ok); + QCOMPARE(cursor.position(), 83); // last col in row 2 + ok = cursor.movePosition(QTextCursor::PreviousRow); + QVERIFY(ok); + QCOMPARE(cursor.position(), 53); // last col in row 1 + ok = cursor.movePosition(QTextCursor::PreviousRow); + QVERIFY(!ok); + QCOMPARE(cursor.position(), 53); + + // test usecase of jumping over a cell + doc->clear(); + doc->setHtml("<html><table>tr><td rowspan=\"2\">a</td><td>b</td></tr><tr><td>c</td></tr></table></html>"); + cursor.setPosition(1); // a + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 3); // b + ok = cursor.movePosition(QTextCursor::NextCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 5); // c + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 3); // b + ok = cursor.movePosition(QTextCursor::PreviousCell); + QVERIFY(ok); + QCOMPARE(cursor.position(), 1); // a +} + +void tst_QTextCursor::insertBlock() +{ + QTextBlockFormat fmt; + fmt.setTopMargin(100); + cursor.insertBlock(fmt); + QVERIFY(cursor.position() == 1); + QVERIFY(cursor.blockFormat() == fmt); +} + +void tst_QTextCursor::insertWithBlockSeparator1() +{ + QString text = "Hello" + QString(QChar::ParagraphSeparator) + "World"; + + cursor.insertText(text); + + cursor.movePosition(QTextCursor::PreviousBlock); + QVERIFY(cursor.position() == 0); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.position() == 6); +} + +void tst_QTextCursor::insertWithBlockSeparator2() +{ + cursor.insertText(QString(QChar::ParagraphSeparator)); + QVERIFY(cursor.position() == 1); +} + +void tst_QTextCursor::insertWithBlockSeparator3() +{ + cursor.insertText(QString(QChar::ParagraphSeparator) + "Hi" + QString(QChar::ParagraphSeparator)); + QVERIFY(cursor.position() == 4); +} + +void tst_QTextCursor::insertWithBlockSeparator4() +{ + cursor.insertText(QString(QChar::ParagraphSeparator) + QString(QChar::ParagraphSeparator)); + QVERIFY(cursor.position() == 2); +} + +void tst_QTextCursor::clearObjectType1() +{ + cursor.insertImage("test.png"); + QVERIFY(cursor.charFormat().isValid()); + QVERIFY(cursor.charFormat().isImageFormat()); + cursor.insertText("Hey"); + QVERIFY(cursor.charFormat().isValid()); + QVERIFY(!cursor.charFormat().isImageFormat()); +} + +void tst_QTextCursor::clearObjectType2() +{ + cursor.insertImage("test.png"); + QVERIFY(cursor.charFormat().isValid()); + QVERIFY(cursor.charFormat().isImageFormat()); + cursor.insertBlock(); + QVERIFY(cursor.charFormat().isValid()); + QVERIFY(!cursor.charFormat().isImageFormat()); +} + +void tst_QTextCursor::clearObjectType3() +{ + // like clearObjectType2 but tests different insertBlock overload + cursor.insertImage("test.png"); + QVERIFY(cursor.charFormat().isValid()); + QVERIFY(cursor.charFormat().isImageFormat()); + QTextBlockFormat bfmt; + bfmt.setAlignment(Qt::AlignRight); + cursor.insertBlock(bfmt); + QVERIFY(cursor.charFormat().isValid()); + QVERIFY(!cursor.charFormat().isImageFormat()); +} + +void tst_QTextCursor::comparisonOperators1() +{ + cursor.insertText("Hello World"); + + cursor.movePosition(QTextCursor::PreviousWord); + + QTextCursor startCursor = cursor; + startCursor.movePosition(QTextCursor::Start); + + QVERIFY(startCursor < cursor); + + QTextCursor midCursor = startCursor; + midCursor.movePosition(QTextCursor::NextWord); + + QVERIFY(midCursor <= cursor); + QVERIFY(midCursor == cursor); + QVERIFY(midCursor >= cursor); + + QVERIFY(midCursor > startCursor); + + QVERIFY(midCursor != startCursor); + QVERIFY(!(midCursor == startCursor)); + + QTextCursor nullCursor; + + QVERIFY(!(startCursor < nullCursor)); + QVERIFY(!(nullCursor < nullCursor)); + QVERIFY(nullCursor < startCursor); + + QVERIFY(nullCursor <= startCursor); + QVERIFY(!(startCursor <= nullCursor)); + + QVERIFY(!(nullCursor >= startCursor)); + QVERIFY(startCursor >= nullCursor); + + QVERIFY(!(nullCursor > startCursor)); + QVERIFY(!(nullCursor > nullCursor)); + QVERIFY(startCursor > nullCursor); +} + +void tst_QTextCursor::comparisonOperators2() +{ + QTextDocument doc1; + QTextDocument doc2; + + QTextCursor cursor1(&doc1); + QTextCursor cursor2(&doc2); + + QVERIFY(cursor1 != cursor2); + QVERIFY(cursor1 == QTextCursor(&doc1)); +} + +void tst_QTextCursor::selection1() +{ + cursor.insertText("Hello World"); + + cursor.setPosition(0); + cursor.clearSelection(); + cursor.setPosition(4, QTextCursor::KeepAnchor); + + QCOMPARE(cursor.selectionStart(), 0); + QCOMPARE(cursor.selectionEnd(), 4); +} + +void tst_QTextCursor::dontCopyTableAttributes() +{ + /* when pressing 'enter' inside a cell it shouldn't + * enlarge the table by adding another cell but just + * extend the cell */ + QTextTable *table = cursor.insertTable(2, 2); + QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition()); + cursor.insertBlock(); + QCOMPARE(table->columns(), 2); +} + +void tst_QTextCursor::checkFrame1() +{ + QVERIFY(cursor.position() == 0); + QPointer<QTextFrame> frame = cursor.insertFrame(QTextFrameFormat()); + QVERIFY(frame != 0); + + QTextFrame *root = frame->parentFrame(); + QVERIFY(root != 0); + + QVERIFY(frame->firstPosition() == 1); + QVERIFY(frame->lastPosition() == 1); + QVERIFY(frame->parentFrame() != 0); + QVERIFY(root->childFrames().size() == 1); + + QVERIFY(cursor.position() == 1); + QVERIFY(cursor.selectionStart() == 1); + QVERIFY(cursor.selectionEnd() == 1); + + doc->undo(); + + QVERIFY(!frame); + QVERIFY(root->childFrames().size() == 0); + + QVERIFY(cursor.position() == 0); + QVERIFY(cursor.selectionStart() == 0); + QVERIFY(cursor.selectionEnd() == 0); + + doc->redo(); + + frame = doc->frameAt(1); + + QVERIFY(frame); + QVERIFY(frame->firstPosition() == 1); + QVERIFY(frame->lastPosition() == 1); + QVERIFY(frame->parentFrame() != 0); + QVERIFY(root->childFrames().size() == 1); + + QVERIFY(cursor.position() == 1); + QVERIFY(cursor.selectionStart() == 1); + QVERIFY(cursor.selectionEnd() == 1); + +// cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); +// QVERIFY(cursor.position() == 2); +// QVERIFY(cursor.selectionStart() == 0); +// QVERIFY(cursor.selectionEnd() == 2); +} + +void tst_QTextCursor::checkFrame2() +{ + QVERIFY(cursor.position() == 0); + cursor.insertText("A"); + QVERIFY(cursor.position() == 1); + cursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); + + QPointer<QTextFrame> frame = cursor.insertFrame(QTextFrameFormat()); + QTextFrame *root = frame->parentFrame(); + + QVERIFY(frame->firstPosition() == 1); + QVERIFY(frame->lastPosition() == 2); + QVERIFY(frame->parentFrame() != 0); + QVERIFY(root->childFrames().size() == 1); + + QVERIFY(cursor.position() == 1); + QVERIFY(cursor.selectionStart() == 1); + QVERIFY(cursor.selectionEnd() == 2); + + doc->undo(); + + QVERIFY(!frame); + QVERIFY(root->childFrames().size() == 0); + + QVERIFY(cursor.position() == 0); + QVERIFY(cursor.selectionStart() == 0); + QVERIFY(cursor.selectionEnd() == 1); + + doc->redo(); + + frame = doc->frameAt(1); + + QVERIFY(frame); + QVERIFY(frame->firstPosition() == 1); + QVERIFY(frame->lastPosition() == 2); + QVERIFY(frame->parentFrame() != 0); + QVERIFY(root->childFrames().size() == 1); + + QVERIFY(cursor.position() == 1); + QVERIFY(cursor.selectionStart() == 1); + QVERIFY(cursor.selectionEnd() == 2); + + cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor); + QVERIFY(cursor.position() == 0); + QVERIFY(cursor.selectionStart() == 0); + QVERIFY(cursor.selectionEnd() == 3); +} + +void tst_QTextCursor::insertBlockToUseCharFormat() +{ + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + cursor.insertText("Hello", fmt); + QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::blue)); + + cursor.insertBlock(); + QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::blue)); + + fmt.setForeground(Qt::red); + cursor.insertText("Hello\nWorld", fmt); + cursor.insertText("Blah"); + QCOMPARE(cursor.charFormat().foreground().color(), QColor(Qt::red)); + + // ### we might want a testcase for createTable, too, as it calls insertBlock, too, + // and we might want to have the char format copied (the one that gets inserted + // as table separators, that are undeletable) +} + +void tst_QTextCursor::tableMovement() +{ + QVERIFY(cursor.position() == 0); + cursor.insertText("AA"); + QVERIFY(cursor.position() == 2); + cursor.movePosition(QTextCursor::Left); + + cursor.insertTable(3, 3); + QCOMPARE(cursor.position(), 2); + + cursor.movePosition(QTextCursor::Down); + QCOMPARE(cursor.position(), 5); + + cursor.movePosition(QTextCursor::Right); + QCOMPARE(cursor.position(), 6); + + cursor.movePosition(QTextCursor::Up); + QCOMPARE(cursor.position(), 3); + + cursor.movePosition(QTextCursor::Right); + QCOMPARE(cursor.position(), 4); + + cursor.movePosition(QTextCursor::Right); + QCOMPARE(cursor.position(), 5); + + cursor.movePosition(QTextCursor::Up); + QCOMPARE(cursor.position(), 2); + + cursor.movePosition(QTextCursor::Up); + QCOMPARE(cursor.position(), 0); + +} + +void tst_QTextCursor::selectionsInTable() +{ + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + + cursor = table->cellAt(0, 0).lastCursorPosition(); + QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor)); + QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor) == false); + + cursor = table->cellAt(1, 0).lastCursorPosition(); + QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor)); + QVERIFY(cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor) == false); + + cursor = table->cellAt(0, 1).firstCursorPosition(); + QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor)); + QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor) == false); + + cursor = table->cellAt(1, 1).firstCursorPosition(); + QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor)); + QVERIFY(cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor) == false); +} + +void tst_QTextCursor::selectedText() +{ + cursor.insertText("Hello World"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + + QCOMPARE(cursor.selectedText(), QString("Hello World")); +} + +void tst_QTextCursor::insertBlockShouldRemoveSelection() +{ + cursor.insertText("Hello World"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + + QVERIFY(cursor.hasSelection()); + QCOMPARE(cursor.selectedText(), QString("Hello")); + + cursor.insertBlock(); + + QVERIFY(!cursor.hasSelection()); + QVERIFY(doc->toPlainText().indexOf("Hello") == -1); +} + +void tst_QTextCursor::insertBlockShouldRemoveSelection2() +{ + cursor.insertText("Hello World"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + + QVERIFY(cursor.hasSelection()); + QCOMPARE(cursor.selectedText(), QString("Hello")); + + QTextBlockFormat fmt = cursor.blockFormat(); + cursor.insertBlock(fmt); + + QVERIFY(!cursor.hasSelection()); + QVERIFY(doc->toPlainText().indexOf("Hello") == -1); +} + +void tst_QTextCursor::mergeCellShouldUpdateSelection() +{ + QTextTable *table = cursor.insertTable(4, 4); + cursor.setPosition(table->cellAt(0, 0).firstPosition()); + cursor.setPosition(table->cellAt(3, 0).firstPosition(), QTextCursor::KeepAnchor); // aka bottom left + int firstRow, numRows, firstColumn, numColumns; + cursor.selectedTableCells(&firstRow, &numRows, &firstColumn, &numColumns); + QCOMPARE(firstRow, 0); + QCOMPARE(numRows, 4); + QCOMPARE(firstColumn, 0); + QCOMPARE(numColumns, 1); + + table->removeColumns(firstColumn, numColumns); + + QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition()); + QCOMPARE(cursor.position(), table->cellAt(0, 0).firstPosition()); + QCOMPARE(cursor.position(), cursor.anchor()); // empty. I don't really care where it ends up. + + // prepare for another test with multiple cursors. + // note we have a 4 rows, 3 cols table now. + cursor.setPosition(table->cellAt(0, 0).firstPosition()); + cursor.setPosition(table->cellAt(0, 2).firstPosition(), QTextCursor::KeepAnchor); + + // now create a selection of a whole row. + QTextCursor c2 = table->cellAt(2, 0).firstCursorPosition(); + c2.setPosition(table->cellAt(2, 2).firstPosition(), QTextCursor::KeepAnchor); + + // just for good measure, another one for a block of cells. + QTextCursor c3 = table->cellAt(2, 1).firstCursorPosition(); + c3.setPosition(table->cellAt(3, 2).firstPosition(), QTextCursor::KeepAnchor); + + table->removeRows(2, 1); + + QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition()); + QCOMPARE(cursor.position(), table->cellAt(0, 2).firstPosition()); + + QCOMPARE(c2.position(), c2.anchor()); // empty. I don't really care where it ends up. + + QCOMPARE(c3.anchor(), table->cellAt(2, 1).firstPosition()); + QCOMPARE(c3.position(), table->cellAt(2, 2).firstPosition()); + + + // prepare for another test where we remove a column + // note we have a 3 rows, 3 cols table now. + cursor.setPosition(table->cellAt(0, 0).firstPosition()); + cursor.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor); + + c2.setPosition(table->cellAt(0, 1).firstPosition()); + c2.setPosition(table->cellAt(2, 2).firstPosition(), QTextCursor::KeepAnchor); + + table->removeColumns(1, 1); + + QCOMPARE(cursor.anchor(), table->cellAt(0, 0).firstPosition()); + QCOMPARE(cursor.position(), table->cellAt(2, 0).firstPosition()); + + QCOMPARE(c2.anchor(), table->cellAt(0, 1).firstPosition()); + QCOMPARE(c2.position(), table->cellAt(2, 1).firstPosition()); + + // test for illegal cursor positions. + // note we have a 3 rows, 2 cols table now. + cursor.setPosition(table->cellAt(2, 0).firstPosition()); + cursor.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor); + + c2.setPosition(table->cellAt(0, 0).firstPosition()); + c2.setPosition(table->cellAt(2, 1).firstPosition(), QTextCursor::KeepAnchor); + + c3.setPosition(table->cellAt(2, 1).firstPosition()); + + table->removeRows(2, 1); + + QCOMPARE(cursor.anchor(), table->cellAt(1, 1).lastPosition()+1); + QCOMPARE(cursor.position(), cursor.anchor()); + + QCOMPARE(c2.anchor(), table->cellAt(0, 0).firstPosition()); + QCOMPARE(c2.position(), table->cellAt(1, 1).firstPosition()); + + QCOMPARE(c3.anchor(), table->cellAt(1, 1).firstPosition()); + QCOMPARE(c3.position(), table->cellAt(1, 1).firstPosition()); +} + +void tst_QTextCursor::joinPreviousEditBlock() +{ + cursor.beginEditBlock(); + cursor.insertText("Hello"); + cursor.insertText("World"); + cursor.endEditBlock(); + QVERIFY(doc->toPlainText().startsWith("HelloWorld")); + + cursor.joinPreviousEditBlock(); + cursor.insertText("Hey"); + cursor.endEditBlock(); + QVERIFY(doc->toPlainText().startsWith("HelloWorldHey")); + + doc->undo(); + QVERIFY(!doc->toPlainText().contains("HelloWorldHey")); +} + +void tst_QTextCursor::setBlockFormatInTable() +{ + // someone reported this on qt4-preview-feedback + QTextBlockFormat fmt; + fmt.setBackground(Qt::blue); + cursor.setBlockFormat(fmt); + + QTextTable *table = cursor.insertTable(2, 2); + cursor = table->cellAt(0, 0).firstCursorPosition(); + fmt.setBackground(Qt::red); + cursor.setBlockFormat(fmt); + + cursor.movePosition(QTextCursor::Start); + QVERIFY(cursor.blockFormat().background().color() == Qt::blue); +} + +void tst_QTextCursor::blockCharFormat2() +{ + QTextCharFormat fmt; + fmt.setForeground(Qt::green); + cursor.mergeBlockCharFormat(fmt); + + fmt.setForeground(Qt::red); + + cursor.insertText("Test", fmt); + cursor.movePosition(QTextCursor::Start); + cursor.insertText("Red"); + cursor.movePosition(QTextCursor::PreviousCharacter); + QVERIFY(cursor.charFormat().foreground().color() == Qt::red); +} + +void tst_QTextCursor::blockCharFormat3() +{ + QVERIFY(cursor.atBlockStart()); + QVERIFY(cursor.atBlockEnd()); + QVERIFY(cursor.atStart()); + + QTextCharFormat fmt; + fmt.setForeground(Qt::green); + cursor.setBlockCharFormat(fmt); + cursor.insertText("Test"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground().color() == Qt::green); + + cursor.movePosition(QTextCursor::Start); + QVERIFY(cursor.charFormat().foreground().color() == Qt::green); + + fmt.setForeground(Qt::red); + cursor.setBlockCharFormat(fmt); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::red); + + cursor.movePosition(QTextCursor::End); + cursor.movePosition(QTextCursor::Start); + QVERIFY(cursor.charFormat().foreground().color() == Qt::green); + + cursor.insertText("Test"); + QVERIFY(cursor.charFormat().foreground().color() == Qt::green); + + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); + QVERIFY(cursor.atBlockStart()); + QVERIFY(cursor.atBlockEnd()); + QVERIFY(cursor.atStart()); + + cursor.insertText("Test"); + QVERIFY(cursor.charFormat().foreground().color() == Qt::red); +} + +void tst_QTextCursor::blockCharFormat() +{ + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + cursor.insertBlock(QTextBlockFormat(), fmt); + cursor.insertText("Hm"); + + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::blue); + + fmt.setForeground(Qt::red); + + cursor.setBlockCharFormat(fmt); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::red); +} + +void tst_QTextCursor::blockCharFormatOnSelection() +{ + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + cursor.insertBlock(QTextBlockFormat(), fmt); + + fmt.setForeground(Qt::green); + cursor.insertText("Hm", fmt); + + fmt.setForeground(Qt::red); + cursor.insertBlock(QTextBlockFormat(), fmt); + cursor.insertText("Ah"); + + fmt.setForeground(Qt::white); + cursor.insertBlock(QTextBlockFormat(), fmt); + cursor.insertText("bleh"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::blue); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::red); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::white); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor); + + fmt.setForeground(Qt::cyan); + cursor.setBlockCharFormat(fmt); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::cyan); + + cursor.movePosition(QTextCursor::Right); + cursor.movePosition(QTextCursor::Right); + QVERIFY(cursor.charFormat().foreground().color() == Qt::green); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::cyan); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::white); +} + +void tst_QTextCursor::anchorInitialized1() +{ + cursor.insertBlock(); + cursor = QTextCursor(cursor.block()); + QCOMPARE(cursor.position(), 1); + QCOMPARE(cursor.anchor(), 1); + QCOMPARE(cursor.selectionStart(), 1); + QCOMPARE(cursor.selectionEnd(), 1); +} + +void tst_QTextCursor::anchorInitialized2() +{ + cursor.insertBlock(); + cursor = QTextCursor(cursor.block().docHandle(), 1); + QCOMPARE(cursor.position(), 1); + QCOMPARE(cursor.anchor(), 1); + QCOMPARE(cursor.selectionStart(), 1); + QCOMPARE(cursor.selectionEnd(), 1); +} + +void tst_QTextCursor::anchorInitialized3() +{ + QTextFrame *frame = cursor.insertFrame(QTextFrameFormat()); + cursor = QTextCursor(frame); + QCOMPARE(cursor.position(), 1); + QCOMPARE(cursor.anchor(), 1); + QCOMPARE(cursor.selectionStart(), 1); + QCOMPARE(cursor.selectionEnd(), 1); +} + +void tst_QTextCursor::selectWord() +{ + cursor.insertText("first second third"); + cursor.insertBlock(); + cursor.insertText("words in second paragraph"); + + cursor.setPosition(9); + cursor.select(QTextCursor::WordUnderCursor); + QVERIFY(cursor.hasSelection()); + QCOMPARE(cursor.selectionStart(), 6); + QCOMPARE(cursor.selectionEnd(), 12); + + cursor.setPosition(5); + cursor.select(QTextCursor::WordUnderCursor); + QVERIFY(cursor.hasSelection()); + QCOMPARE(cursor.selectionStart(), 0); + QCOMPARE(cursor.selectionEnd(), 5); + + cursor.setPosition(6); + cursor.select(QTextCursor::WordUnderCursor); + QVERIFY(cursor.hasSelection()); + QCOMPARE(cursor.selectionStart(), 6); + QCOMPARE(cursor.selectionEnd(), 12); + + cursor.setPosition(14); + cursor.select(QTextCursor::WordUnderCursor); + QVERIFY(cursor.hasSelection()); + QCOMPARE(cursor.selectionStart(), 6); + QCOMPARE(cursor.selectionEnd(), 12); + + cursor.movePosition(QTextCursor::Start); + cursor.select(QTextCursor::WordUnderCursor); + QVERIFY(cursor.hasSelection()); + QCOMPARE(cursor.selectionStart(), 0); + QCOMPARE(cursor.selectionEnd(), 5); + + cursor.movePosition(QTextCursor::EndOfBlock); + cursor.select(QTextCursor::WordUnderCursor); + QVERIFY(cursor.hasSelection()); + QCOMPARE(cursor.selectionStart(), 17); + QCOMPARE(cursor.selectionEnd(), 22); +} + +void tst_QTextCursor::selectWordWithSeparators_data() +{ + QTest::addColumn<QString>("text"); + QTest::addColumn<int>("initialPosition"); + QTest::addColumn<QString>("expectedSelectedText"); + + QTest::newRow("dereference") << QString::fromLatin1("foo->bar()") << 1 << QString::fromLatin1("foo"); + QTest::newRow("funcsignature") << QString::fromLatin1("bar(int x);") << 1 << QString::fromLatin1("bar"); + QTest::newRow("def") << QString::fromLatin1("foo *f;") << 1 << QString::fromLatin1("foo"); +} + +void tst_QTextCursor::selectWordWithSeparators() +{ + QFETCH(QString, text); + QFETCH(int, initialPosition); + QFETCH(QString, expectedSelectedText); + + cursor.insertText(text); + cursor.setPosition(initialPosition); + cursor.select(QTextCursor::WordUnderCursor); + + QCOMPARE(cursor.selectedText(), expectedSelectedText); +} + +void tst_QTextCursor::startOfWord() +{ + cursor.insertText("first second"); + cursor.setPosition(7); + cursor.movePosition(QTextCursor::StartOfWord); + QCOMPARE(cursor.position(), 0); +} + +void tst_QTextCursor::selectBlock() +{ + cursor.insertText("foobar"); + QTextBlockFormat blockFmt; + blockFmt.setAlignment(Qt::AlignHCenter); + cursor.insertBlock(blockFmt); + cursor.insertText("blah"); + cursor.insertBlock(QTextBlockFormat()); + + cursor.movePosition(QTextCursor::PreviousBlock); + QCOMPARE(cursor.block().text(), QString("blah")); + + cursor.select(QTextCursor::BlockUnderCursor); + QVERIFY(cursor.hasSelection()); + + QTextDocumentFragment fragment(cursor); + doc->clear(); + cursor.insertFragment(fragment); + QCOMPARE(blockCount(), 2); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); + QCOMPARE(cursor.block().text(), QString("blah")); +} + +void tst_QTextCursor::selectVisually() +{ + cursor.insertText("Foo\nlong line which is probably going to be cut in two when shown in a widget\nparagraph 3\n"); + + cursor.setPosition(6); // somewhere in the long paragraph. + cursor.select(QTextCursor::LineUnderCursor); + // since we are not yet laid-out, we expect the whole paragraph to be selected. + QCOMPARE(cursor.position(), 77); + QCOMPARE(cursor.anchor(), 4); +} + +void tst_QTextCursor::insertText() +{ + QString txt = "Foo\nBar\r\nMeep"; + txt += QChar::LineSeparator; + txt += "Baz"; + txt += QChar::ParagraphSeparator; + txt += "yoyodyne"; + cursor.insertText(txt); + QCOMPARE(blockCount(), 4); + cursor.movePosition(QTextCursor::Start); + QCOMPARE(cursor.block().text(), QString("Foo")); + cursor.movePosition(QTextCursor::NextBlock); + QCOMPARE(cursor.block().text(), QString("Bar")); + cursor.movePosition(QTextCursor::NextBlock); + QCOMPARE(cursor.block().text(), QString(QString("Meep") + QChar(QChar::LineSeparator) + QString("Baz"))); + cursor.movePosition(QTextCursor::NextBlock); + QCOMPARE(cursor.block().text(), QString("yoyodyne")); +} + +void tst_QTextCursor::insertFragmentShouldUseCurrentCharFormat() +{ + QTextDocumentFragment fragment = QTextDocumentFragment::fromPlainText("Hello World"); + QTextCharFormat fmt; + fmt.setFontUnderline(true); + + cursor.clearSelection(); + cursor.setCharFormat(fmt); + cursor.insertFragment(fragment); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat() == fmt); +} + +int tst_QTextCursor::blockCount() +{ + int cnt = 0; + for (QTextBlock blk = doc->begin(); blk.isValid(); blk = blk.next()) + ++cnt; + return cnt; +} + +void tst_QTextCursor::endOfLine() +{ + doc->setPageSize(QSizeF(100000, INT_MAX)); + + QString text("First Line \nSecond Line "); + text.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator)); + cursor.insertText(text); + + // ensure layouted + doc->documentLayout()->documentSize(); + + cursor.movePosition(QTextCursor::Start); + + QCOMPARE(cursor.block().layout()->lineCount(), 2); + + cursor.movePosition(QTextCursor::EndOfLine); + QCOMPARE(cursor.position(), 14); + cursor.movePosition(QTextCursor::NextCharacter); + QCOMPARE(cursor.position(), 15); + cursor.movePosition(QTextCursor::EndOfLine); + QCOMPARE(cursor.position(), 28); +} + +class CursorListener : public QObject +{ + Q_OBJECT +public: + CursorListener(QTextCursor *_cursor) : lastRecordedPosition(-1), lastRecordedAnchor(-1), recordingCount(0), cursor(_cursor) {} + + int lastRecordedPosition; + int lastRecordedAnchor; + int recordingCount; + +public slots: + void recordCursorPosition() + { + lastRecordedPosition = cursor->position(); + lastRecordedAnchor = cursor->anchor(); + ++recordingCount; + } + + void selectAllContents() + { + // Only test the first time + if (!recordingCount) { + recordingCount++; + cursor->select(QTextCursor::Document); + lastRecordedPosition = cursor->position(); + lastRecordedAnchor = cursor->anchor(); + } + } + +private: + QTextCursor *cursor; +}; + +void tst_QTextCursor::editBlocksDuringRemove() +{ + CursorListener listener(&cursor); + + cursor.insertText("Hello World"); + cursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); + QCOMPARE(cursor.selectedText(), QString("Hello World")); + + connect(doc, SIGNAL(contentsChanged()), &listener, SLOT(recordCursorPosition())); + listener.recordingCount = 0; + cursor.deleteChar(); + + QCOMPARE(listener.recordingCount, 1); + QCOMPARE(listener.lastRecordedPosition, 0); + QCOMPARE(listener.lastRecordedAnchor, 0); + + QVERIFY(doc->toPlainText().isEmpty()); +} + +void tst_QTextCursor::selectAllDuringRemove() +{ + CursorListener listener(&cursor); + + cursor.insertText("Hello World"); + cursor.movePosition(QTextCursor::End); + + connect(doc, SIGNAL(contentsChanged()), &listener, SLOT(selectAllContents())); + listener.recordingCount = 0; + QTextCursor localCursor = cursor; + localCursor.deletePreviousChar(); + + QCOMPARE(listener.lastRecordedPosition, 10); + QCOMPARE(listener.lastRecordedAnchor, 0); +} + +void tst_QTextCursor::update_data() +{ + QTest::addColumn<QString>("text"); + QTest::addColumn<int>("position"); + QTest::addColumn<int>("anchor"); + QTest::addColumn<int>("modifyPosition"); + QTest::addColumn<int>("modifyAnchor"); + QTest::addColumn<QString>("insertText"); + QTest::addColumn<int>("expectedPosition"); + QTest::addColumn<int>("expectedAnchor"); + + QString text("Hello big world"); + int charsToDelete = 3; + QTest::newRow("removeInsideSelection") + << text + << /*position*/ 0 + << /*anchor*/ text.length() + // delete 'big' + << 6 + << 6 + charsToDelete + << QString() // don't insert anything, just remove + << /*expectedPosition*/ 0 + << /*expectedAnchor*/ text.length() - charsToDelete + ; + + text = "Hello big world"; + charsToDelete = 3; + QTest::newRow("removeInsideSelectionWithSwappedAnchorAndPosition") + << text + << /*position*/ text.length() + << /*anchor*/ 0 + // delete 'big' + << 6 + << 6 + charsToDelete + << QString() // don't insert anything, just remove + << /*expectedPosition*/ text.length() - charsToDelete + << /*expectedAnchor*/ 0 + ; + + + text = "Hello big world"; + charsToDelete = 3; + QString textToInsert("small"); + QTest::newRow("replaceInsideSelection") + << text + << /*position*/ 0 + << /*anchor*/ text.length() + // delete 'big' ... + << 6 + << 6 + charsToDelete + << textToInsert // ... and replace 'big' with 'small' + << /*expectedPosition*/ 0 + << /*expectedAnchor*/ text.length() - charsToDelete + textToInsert.length() + ; + + text = "Hello big world"; + charsToDelete = 3; + textToInsert = "small"; + QTest::newRow("replaceInsideSelectionWithSwappedAnchorAndPosition") + << text + << /*position*/ text.length() + << /*anchor*/ 0 + // delete 'big' ... + << 6 + << 6 + charsToDelete + << textToInsert // ... and replace 'big' with 'small' + << /*expectedPosition*/ text.length() - charsToDelete + textToInsert.length() + << /*expectedAnchor*/ 0 + ; + + + text = "Hello big world"; + charsToDelete = 3; + QTest::newRow("removeBeforeSelection") + << text + << /*position*/ text.length() - 5 + << /*anchor*/ text.length() + // delete 'big' + << 6 + << 6 + charsToDelete + << QString() // don't insert anything, just remove + << /*expectedPosition*/ text.length() - 5 - charsToDelete + << /*expectedAnchor*/ text.length() - charsToDelete + ; + + text = "Hello big world"; + charsToDelete = 3; + QTest::newRow("removeAfterSelection") + << text + << /*position*/ 0 + << /*anchor*/ 4 + // delete 'big' + << 6 + << 6 + charsToDelete + << QString() // don't insert anything, just remove + << /*expectedPosition*/ 0 + << /*expectedAnchor*/ 4 + ; + +} + +void tst_QTextCursor::update() +{ + QFETCH(QString, text); + + doc->setPlainText(text); + + QFETCH(int, position); + QFETCH(int, anchor); + + cursor.setPosition(anchor); + cursor.setPosition(position, QTextCursor::KeepAnchor); + + QCOMPARE(cursor.position(), position); + QCOMPARE(cursor.anchor(), anchor); + + QFETCH(int, modifyPosition); + QFETCH(int, modifyAnchor); + + QTextCursor modifyCursor = cursor; + modifyCursor.setPosition(modifyAnchor); + modifyCursor.setPosition(modifyPosition, QTextCursor::KeepAnchor); + + QCOMPARE(modifyCursor.position(), modifyPosition); + QCOMPARE(modifyCursor.anchor(), modifyAnchor); + + QFETCH(QString, insertText); + modifyCursor.insertText(insertText); + + QFETCH(int, expectedPosition); + QFETCH(int, expectedAnchor); + + QCOMPARE(cursor.position(), expectedPosition); + QCOMPARE(cursor.anchor(), expectedAnchor); +} + +void tst_QTextCursor::disallowSettingObjectIndicesOnCharFormats() +{ + QTextCharFormat fmt; + fmt.setObjectIndex(42); + cursor.insertText("Hey", fmt); + QCOMPARE(cursor.charFormat().objectIndex(), -1); + + cursor.select(QTextCursor::Document); + cursor.mergeCharFormat(fmt); + QCOMPARE(doc->begin().begin().fragment().charFormat().objectIndex(), -1); + + cursor.select(QTextCursor::Document); + cursor.setCharFormat(fmt); + QCOMPARE(doc->begin().begin().fragment().charFormat().objectIndex(), -1); + + cursor.setBlockCharFormat(fmt); + QCOMPARE(cursor.blockCharFormat().objectIndex(), -1); + + cursor.movePosition(QTextCursor::End); + cursor.insertBlock(QTextBlockFormat(), fmt); + QCOMPARE(cursor.blockCharFormat().objectIndex(), -1); + + doc->clear(); + + QTextTable *table = cursor.insertTable(1, 1); + cursor.select(QTextCursor::Document); + cursor.setCharFormat(fmt); + + cursor = table->cellAt(0, 0).firstCursorPosition(); + QVERIFY(!cursor.isNull()); + QCOMPARE(cursor.blockCharFormat().objectIndex(), table->objectIndex()); +} + +void tst_QTextCursor::blockAndColumnNumber() +{ + QCOMPARE(QTextCursor().columnNumber(), 0); + QCOMPARE(QTextCursor().blockNumber(), 0); + + QCOMPARE(cursor.columnNumber(), 0); + QCOMPARE(cursor.blockNumber(), 0); + cursor.insertText("Hello"); + QCOMPARE(cursor.columnNumber(), 5); + QCOMPARE(cursor.blockNumber(), 0); + + cursor.insertBlock(); + QCOMPARE(cursor.columnNumber(), 0); + QCOMPARE(cursor.blockNumber(), 1); + cursor.insertText("Blah"); + QCOMPARE(cursor.blockNumber(), 1); + + // trigger a layout + doc->documentLayout(); + + cursor.insertBlock(); + QCOMPARE(cursor.columnNumber(), 0); + QCOMPARE(cursor.blockNumber(), 2); + cursor.insertText("Test"); + QCOMPARE(cursor.columnNumber(), 4); + QCOMPARE(cursor.blockNumber(), 2); + cursor.insertText(QString(QChar(QChar::LineSeparator))); + QCOMPARE(cursor.columnNumber(), 0); + QCOMPARE(cursor.blockNumber(), 2); + cursor.insertText("A"); + QCOMPARE(cursor.columnNumber(), 1); + QCOMPARE(cursor.blockNumber(), 2); +} + +void tst_QTextCursor::movePositionEndOfLine() +{ + cursor.insertText("blah\nblah\n"); + // Select part of the second line ("la") + cursor.setPosition(6); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2); + QCOMPARE(cursor.selectedText(), QLatin1String("la")); + + // trigger a layout + doc->documentLayout(); + + // Remove "la" and append "something" to the end in one undo operation + cursor.beginEditBlock(); + cursor.removeSelectedText(); + QTextCursor c2(doc); + c2.setPosition(7); + c2.insertText("foo"); // append to doc without touching the cursor. + + QCOMPARE(cursor.position(), 6); + cursor.movePosition(QTextCursor::EndOfLine); // in an edit block visual movement is moved to the end of the paragraph + QCOMPARE(cursor.position(), 10); + cursor.endEditBlock(); +} + +void tst_QTextCursor::clearCells() +{ + QTextTable *table = cursor.insertTable(3, 5); + cursor.setPosition(table->cellAt(0,0).firstPosition()); // select cell 1 and cell 2 + cursor.setPosition(table->cellAt(0,1).firstPosition(), QTextCursor::KeepAnchor); + cursor.deleteChar(); // should clear the cells, and not crash ;) +} + +void tst_QTextCursor::task244408_wordUnderCursor_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("expected"); + QTest::newRow("trailingSpace") << QString::fromLatin1("foo ") << QString::fromLatin1(""); + QTest::newRow("noTrailingSpace") << QString::fromLatin1("foo") << QString::fromLatin1("foo"); +} + +void tst_QTextCursor::task244408_wordUnderCursor() +{ + QFETCH(QString, input); + QFETCH(QString, expected); + cursor.insertText(input); + cursor.movePosition(QTextCursor::End); + cursor.select(QTextCursor::WordUnderCursor); + QCOMPARE(cursor.selectedText(), expected); +} + +void tst_QTextCursor::adjustCursorsOnInsert() +{ + cursor.insertText("Some text before "); + int posBefore = cursor.position(); + cursor.insertText("selected text"); + int posAfter = cursor.position(); + cursor.insertText(" some text afterwards"); + + QTextCursor selection = cursor; + selection.setPosition(posBefore); + selection.setPosition(posAfter, QTextCursor::KeepAnchor); + + cursor.setPosition(posBefore-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore+1); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore+1); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter+1); + doc->undo(); + + selection.setKeepPositionOnInsert(true); + cursor.setPosition(posAfter); + cursor.insertText(QLatin1String("x")); + selection.setKeepPositionOnInsert(false); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter); + doc->undo(); + + cursor.setPosition(posAfter+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.anchor(), posBefore); + QCOMPARE(selection.position(), posAfter); + doc->undo(); + + selection.setPosition(posAfter); + selection.setPosition(posBefore, QTextCursor::KeepAnchor); + + cursor.setPosition(posBefore-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore+1); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore+1); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posBefore+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter-1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter+1); + doc->undo(); + + cursor.setPosition(posAfter+1); + cursor.insertText(QLatin1String("x")); + QCOMPARE(selection.position(), posBefore); + QCOMPARE(selection.anchor(), posAfter); + doc->undo(); + +} +void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo() +{ + cursor.insertText("AAAABBBBCCCCDDDD"); + cursor.setPosition(12); + int cursorPositionBefore = cursor.position(); + cursor.beginEditBlock(); + cursor.insertText("*"); + cursor.setPosition(8); + cursor.insertText("*"); + cursor.setPosition(4); + cursor.insertText("*"); + cursor.setPosition(0); + cursor.insertText("*"); + int cursorPositionAfter = cursor.position(); + cursor.endEditBlock(); + + QVERIFY(doc->toPlainText() == "*AAAA*BBBB*CCCC*DDDD"); + QCOMPARE(12, cursorPositionBefore); + QCOMPARE(1, cursorPositionAfter); + + doc->undo(&cursor); + QVERIFY(doc->toPlainText() == "AAAABBBBCCCCDDDD"); + QCOMPARE(cursor.position(), cursorPositionBefore); + doc->redo(&cursor); + QVERIFY(doc->toPlainText() == "*AAAA*BBBB*CCCC*DDDD"); + QCOMPARE(cursor.position(), cursorPositionAfter); +} + +void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo2() +{ + cursor.insertText("AAAABBBB"); + int cursorPositionBefore = cursor.position(); + cursor.setPosition(0, QTextCursor::KeepAnchor); + cursor.beginEditBlock(); + cursor.removeSelectedText(); + cursor.insertText("AAAABBBBCCCCDDDD"); + cursor.endEditBlock(); + doc->undo(&cursor); + QVERIFY(doc->toPlainText() == "AAAABBBB"); + QCOMPARE(cursor.position(), cursorPositionBefore); + + cursor.insertText("CCCC"); + QVERIFY(doc->toPlainText() == "AAAABBBBCCCC"); + + cursorPositionBefore = cursor.position(); + cursor.setPosition(0, QTextCursor::KeepAnchor); + cursor.beginEditBlock(); + cursor.removeSelectedText(); + cursor.insertText("AAAABBBBCCCCDDDD"); + cursor.endEditBlock(); + + /* this undo now implicitely reinserts two segments, first "CCCCC", then + "AAAABBBB". The test ensures that the two are combined in order to + reconstruct the correct cursor position */ + doc->undo(&cursor); + + + QVERIFY(doc->toPlainText() == "AAAABBBBCCCC"); + QCOMPARE(cursor.position(), cursorPositionBefore); +} + +void tst_QTextCursor::cursorPositionWithBlockUndoAndRedo3() +{ + // verify that it's the position of the beginEditBlock that counts, and not the last edit position + cursor.insertText("AAAABBBB"); + int cursorPositionBefore = cursor.position(); + cursor.beginEditBlock(); + cursor.setPosition(4); + QVERIFY(cursor.position() != cursorPositionBefore); + cursor.insertText("*"); + cursor.endEditBlock(); + QCOMPARE(cursor.position(), 5); + doc->undo(&cursor); + QCOMPARE(cursor.position(), cursorPositionBefore); +} + +QTEST_MAIN(tst_QTextCursor) +#include "tst_qtextcursor.moc" diff --git a/tests/auto/gui/text/qtextdocument/.gitignore b/tests/auto/gui/text/qtextdocument/.gitignore new file mode 100644 index 0000000000..c14f0e2422 --- /dev/null +++ b/tests/auto/gui/text/qtextdocument/.gitignore @@ -0,0 +1 @@ +tst_qtextdocument diff --git a/tests/auto/gui/text/qtextdocument/common.h b/tests/auto/gui/text/qtextdocument/common.h new file mode 100644 index 0000000000..1eaefdbfbe --- /dev/null +++ b/tests/auto/gui/text/qtextdocument/common.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QAbstractTextDocumentLayout> +#include <private/qtextdocument_p.h> + +#ifndef COMMON_H +#define COMMON_H + +class QTestDocumentLayout : public QAbstractTextDocumentLayout +{ + Q_OBJECT +public: + QTestDocumentLayout(QTextDocument *doc) : QAbstractTextDocumentLayout(doc), f(-1), called(false) {} + virtual void draw(QPainter *, const PaintContext &) {} + virtual int hitTest(const QPointF &, Qt::HitTestAccuracy ) const { return 0; } + + virtual void documentChanged(int from, int oldLength, int length) + { + called = true; + lastDocumentLengths.append(document()->docHandle()->length()); + + if (f < 0) + return; + + if(from != f || + o != oldLength || + l != length) { + qDebug("checkDocumentChanged: got %d %d %d, expected %d %d %d", from, oldLength, length, f, o, l); + error = true; + } + } + + virtual int pageCount() const { return 1; } + virtual QSizeF documentSize() const { return QSizeF(); } + + virtual QRectF frameBoundingRect(QTextFrame *) const { return QRectF(); } + virtual QRectF blockBoundingRect(const QTextBlock &) const { return QRectF(); } + + int f; + int o; + int l; + + void expect(int from, int oldLength, int length) { + f = from; + o = oldLength; + l = length; + error = false; + called = false; + } + bool error; + bool called; + QList<int> lastDocumentLengths; +}; + +#endif diff --git a/tests/auto/gui/text/qtextdocument/qtextdocument.pro b/tests/auto/gui/text/qtextdocument/qtextdocument.pro new file mode 100644 index 0000000000..69517589cc --- /dev/null +++ b/tests/auto/gui/text/qtextdocument/qtextdocument.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += core-private gui-private xml +HEADERS += common.h +SOURCES += tst_qtextdocument.cpp + + diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp new file mode 100644 index 0000000000..c98a703acc --- /dev/null +++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp @@ -0,0 +1,2788 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <qtextdocument.h> +#include <qdebug.h> + +#include <qtextcursor.h> +#include <qtextdocumentfragment.h> +#include <qtextformat.h> +#include <qtextobject.h> +#include <qtexttable.h> +#include <qabstracttextdocumentlayout.h> +#include <qtextlist.h> +#include <qtextcodec.h> +#include <qurl.h> +#include <qpainter.h> +#include <qfontmetrics.h> +#include <qimage.h> +#include <qtextlayout.h> +#include <QDomDocument> +#include "common.h" + + +QT_FORWARD_DECLARE_CLASS(QTextDocument) + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QTextDocument : public QObject +{ + Q_OBJECT + +public: + tst_QTextDocument(); + virtual ~tst_QTextDocument(); + +public slots: + void init(); + void cleanup(); +private slots: + void getSetCheck(); + void isEmpty(); + void find_data(); + void find(); + void find2(); + void findWithRegExp_data(); + void findWithRegExp(); + void findMultiple(); + void basicIsModifiedChecks(); + void moreIsModified(); + void isModified2(); + void isModified3(); + void isModified4(); + void noundo_basicIsModifiedChecks(); + void noundo_moreIsModified(); + void noundo_isModified2(); + void noundo_isModified3(); + void mightBeRichText(); + void mightBeRichText_data(); + + void task240325(); + + void stylesheetFont_data(); + void stylesheetFont(); + + void toHtml_data(); + void toHtml(); + void toHtml2(); + + void setFragmentMarkersInHtmlExport(); + + void toHtmlBodyBgColor(); + void toHtmlRootFrameProperties(); + void capitalizationHtmlInExport(); + void wordspacingHtmlExport(); + + void cursorPositionChanged(); + void cursorPositionChangedOnSetText(); + + void textFrameIterator(); + + void codecForHtml(); + + void markContentsDirty(); + + void clonePreservesMetaInformation(); + void clonePreservesPageSize(); + void clonePreservesPageBreakPolicies(); + void clonePreservesDefaultFont(); + void clonePreservesRootFrameFormat(); + void clonePreservesResources(); + void clonePreservesUserStates(); + void clonePreservesIndentWidth(); + void blockCount(); + void defaultStyleSheet(); + + void resolvedFontInEmptyFormat(); + + void defaultRootFrameMargin(); + + void clearResources(); + + void setPlainText(); + void toPlainText(); + + void deleteTextObjectsOnClear(); + + void maximumBlockCount(); + void adjustSize(); + void initialUserData(); + + void html_defaultFont(); + + void blockCountChanged(); + + void nonZeroDocumentLengthOnClear(); + + void setTextPreservesUndoRedoEnabled(); + + void firstLast(); + + void backgroundImage_toHtml(); + void backgroundImage_toHtml2(); + void backgroundImage_clone(); + void backgroundImage_copy(); + + void documentCleanup(); + + void characterAt(); + void revisions(); + void revisionWithUndoCompressionAndUndo(); + + void testUndoCommandAdded(); + + void testUndoBlocks(); + + void receiveCursorPositionChangedAfterContentsChange(); + void escape_data(); + void escape(); + + void copiedFontSize(); + + void htmlExportImportBlockCount(); + +private: + void backgroundImage_checkExpectedHtml(const QTextDocument &doc); + + QTextDocument *doc; + QTextCursor cursor; + QFont defaultFont; + QString htmlHead; + QString htmlTail; +}; + +class MyAbstractTextDocumentLayout : public QAbstractTextDocumentLayout +{ +public: + MyAbstractTextDocumentLayout(QTextDocument *doc) : QAbstractTextDocumentLayout(doc) {} + void draw(QPainter *, const PaintContext &) {} + int hitTest(const QPointF &, Qt::HitTestAccuracy) const { return 0; } + int pageCount() const { return 0; } + QSizeF documentSize() const { return QSizeF(); } + QRectF frameBoundingRect(QTextFrame *) const { return QRectF(); } + QRectF blockBoundingRect(const QTextBlock &) const { return QRectF(); } + void documentChanged(int, int, int) {} +}; + +// Testing get/set functions +void tst_QTextDocument::getSetCheck() +{ + QTextDocument obj1; + // QAbstractTextDocumentLayout * QTextDocument::documentLayout() + // void QTextDocument::setDocumentLayout(QAbstractTextDocumentLayout *) + QPointer<MyAbstractTextDocumentLayout> var1 = new MyAbstractTextDocumentLayout(0); + obj1.setDocumentLayout(var1); + QCOMPARE(static_cast<QAbstractTextDocumentLayout *>(var1), obj1.documentLayout()); + obj1.setDocumentLayout((QAbstractTextDocumentLayout *)0); + QVERIFY(var1.isNull()); + QVERIFY(obj1.documentLayout()); + + // bool QTextDocument::useDesignMetrics() + // void QTextDocument::setUseDesignMetrics(bool) + obj1.setUseDesignMetrics(false); + QCOMPARE(false, obj1.useDesignMetrics()); + obj1.setUseDesignMetrics(true); + QCOMPARE(true, obj1.useDesignMetrics()); +} + +tst_QTextDocument::tst_QTextDocument() +{ + QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); + img.save("foo.png"); +} + +tst_QTextDocument::~tst_QTextDocument() +{ + QFile::remove(QLatin1String("foo.png")); +} + +void tst_QTextDocument::init() +{ + doc = new QTextDocument; + cursor = QTextCursor(doc); + defaultFont = QFont(); + + htmlHead = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " + "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" + "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" + "p, li { white-space: pre-wrap; }\n" + "</style></head>" + "<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:%4;\">\n"); + htmlHead = htmlHead.arg(defaultFont.family()).arg(defaultFont.pointSizeF()).arg(defaultFont.weight() * 8).arg((defaultFont.italic() ? "italic" : "normal")); + + htmlTail = QString("</body></html>"); +} + +void tst_QTextDocument::cleanup() +{ + cursor = QTextCursor(); + delete doc; + doc = 0; +} + +void tst_QTextDocument::isEmpty() +{ + QVERIFY(doc->isEmpty()); +} + +void tst_QTextDocument::find_data() +{ + QTest::addColumn<QString>("haystack"); + QTest::addColumn<QString>("needle"); + QTest::addColumn<int>("flags"); + QTest::addColumn<int>("from"); + QTest::addColumn<int>("anchor"); + QTest::addColumn<int>("position"); + + QTest::newRow("1") << "Hello World" << "World" << int(QTextDocument::FindCaseSensitively) << 0 << 6 << 11; + + QTest::newRow("2") << QString::fromAscii("Hello") + QString(QChar::ParagraphSeparator) + QString::fromAscii("World") + << "World" << int(QTextDocument::FindCaseSensitively) << 1 << 6 << 11; + + QTest::newRow("3") << QString::fromAscii("Hello") + QString(QChar::ParagraphSeparator) + QString::fromAscii("World") + << "Hello" << int(QTextDocument::FindCaseSensitively | QTextDocument::FindBackward) << 10 << 0 << 5; + QTest::newRow("4wholewords") << QString::fromAscii("Hello Blah World") + << "Blah" << int(QTextDocument::FindWholeWords) << 0 << 6 << 10; + QTest::newRow("5wholewords") << QString::fromAscii("HelloBlahWorld") + << "Blah" << int(QTextDocument::FindWholeWords) << 0 << -1 << -1; + QTest::newRow("6wholewords") << QString::fromAscii("HelloBlahWorld Blah Hah") + << "Blah" << int(QTextDocument::FindWholeWords) << 0 << 15 << 19; + QTest::newRow("7wholewords") << QString::fromAscii("HelloBlahWorld Blah Hah") + << "Blah" << int(QTextDocument::FindWholeWords | QTextDocument::FindBackward) << 23 << 15 << 19; + QTest::newRow("8wholewords") << QString::fromAscii("Hello: World\n") + << "orld" << int(QTextDocument::FindWholeWords) << 0 << -1 << -1; + + QTest::newRow("across-paragraphs") << QString::fromAscii("First Parag\nSecond Parag with a lot more text") + << "Parag" << int(QTextDocument::FindBackward) + << 15 << 6 << 11; + + QTest::newRow("nbsp") << "Hello" + QString(QChar(QChar::Nbsp)) +"World" << " " << int(QTextDocument::FindCaseSensitively) << 0 << 5 << 6; +} + +void tst_QTextDocument::find() +{ + QFETCH(QString, haystack); + QFETCH(QString, needle); + QFETCH(int, flags); + QFETCH(int, from); + QFETCH(int, anchor); + QFETCH(int, position); + + cursor.insertText(haystack); + cursor = doc->find(needle, from, QTextDocument::FindFlags(flags)); + + if (anchor != -1) { + QCOMPARE(cursor.anchor(), anchor); + QCOMPARE(cursor.position(), position); + } else { + QVERIFY(cursor.isNull()); + } + + //search using a regular expression + QRegExp expr(needle); + expr.setPatternSyntax(QRegExp::FixedString); + QTextDocument::FindFlags flg(flags); + expr.setCaseSensitivity((flg & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive); + cursor = doc->find(expr, from, flg); + + if (anchor != -1) { + QCOMPARE(cursor.anchor(), anchor); + QCOMPARE(cursor.position(), position); + } else { + QVERIFY(cursor.isNull()); + } +} + +void tst_QTextDocument::findWithRegExp_data() +{ + QTest::addColumn<QString>("haystack"); + QTest::addColumn<QString>("needle"); + QTest::addColumn<int>("flags"); + QTest::addColumn<int>("from"); + QTest::addColumn<int>("anchor"); + QTest::addColumn<int>("position"); + + // match integers 0 to 99 + QTest::newRow("1") << "23" << "^\\d\\d?$" << int(QTextDocument::FindCaseSensitively) << 0 << 0 << 2; + // match ampersands but not & + QTest::newRow("2") << "His & hers & theirs" << "&(?!amp;)"<< int(QTextDocument::FindCaseSensitively) << 0 << 15 << 16; + //backward search + QTest::newRow("3") << QString::fromAscii("HelloBlahWorld Blah Hah") + << "h" << int(QTextDocument::FindBackward) << 18 << 8 << 9; + +} + +void tst_QTextDocument::findWithRegExp() +{ + QFETCH(QString, haystack); + QFETCH(QString, needle); + QFETCH(int, flags); + QFETCH(int, from); + QFETCH(int, anchor); + QFETCH(int, position); + + cursor.insertText(haystack); + //search using a regular expression + QRegExp expr(needle); + QTextDocument::FindFlags flg(flags); + expr.setCaseSensitivity((flg & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive); + cursor = doc->find(expr, from, flg); + + if (anchor != -1) { + QCOMPARE(cursor.anchor(), anchor); + QCOMPARE(cursor.position(), position); + } else { + QVERIFY(cursor.isNull()); + } +} + +void tst_QTextDocument::find2() +{ + doc->setPlainText("aaa"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); + QTextCursor hit = doc->find("a", cursor); + QCOMPARE(hit.position(), 2); + QCOMPARE(hit.anchor(), 1); +} + +void tst_QTextDocument::findMultiple() +{ + const QString text("foo bar baz foo bar baz"); + doc->setPlainText(text); + + cursor.movePosition(QTextCursor::Start); + cursor = doc->find("bar", cursor); + QCOMPARE(cursor.selectionStart(), text.indexOf("bar")); + QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); + cursor = doc->find("bar", cursor); + QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); + QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); + + cursor.movePosition(QTextCursor::End); + cursor = doc->find("bar", cursor, QTextDocument::FindBackward); + QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); + QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); + cursor = doc->find("bar", cursor, QTextDocument::FindBackward); + QCOMPARE(cursor.selectionStart(), text.indexOf("bar")); + QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); + + + QRegExp expr("bar"); + expr.setPatternSyntax(QRegExp::FixedString); + + cursor.movePosition(QTextCursor::End); + cursor = doc->find(expr, cursor, QTextDocument::FindBackward); + QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); + QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); + cursor = doc->find(expr, cursor, QTextDocument::FindBackward); + QCOMPARE(cursor.selectionStart(), text.indexOf("bar")); + QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); + + cursor.movePosition(QTextCursor::Start); + cursor = doc->find(expr, cursor); + QCOMPARE(cursor.selectionStart(), text.indexOf("bar")); + QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); + cursor = doc->find(expr, cursor); + QCOMPARE(cursor.selectionStart(), text.lastIndexOf("bar")); + QCOMPARE(cursor.selectionEnd(), cursor.selectionStart() + 3); +} + +void tst_QTextDocument::basicIsModifiedChecks() +{ + QSignalSpy spy(doc, SIGNAL(modificationChanged(bool))); + + QVERIFY(!doc->isModified()); + cursor.insertText("Hello World"); + QVERIFY(doc->isModified()); + QCOMPARE(spy.count(), 1); + QVERIFY(spy.takeFirst().at(0).toBool()); + + doc->undo(); + QVERIFY(!doc->isModified()); + QCOMPARE(spy.count(), 1); + QVERIFY(!spy.takeFirst().at(0).toBool()); + + doc->redo(); + QVERIFY(doc->isModified()); + QCOMPARE(spy.count(), 1); + QVERIFY(spy.takeFirst().at(0).toBool()); +} + +void tst_QTextDocument::moreIsModified() +{ + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + QVERIFY(doc->isModified()); + + doc->undo(); + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + + doc->undo(); + QVERIFY(!doc->isModified()); +} + +void tst_QTextDocument::isModified2() +{ + // reported on qt4-preview-feedback + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + QVERIFY(doc->isModified()); + + doc->setModified(false); + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + QVERIFY(doc->isModified()); +} + +void tst_QTextDocument::isModified3() +{ + QVERIFY(!doc->isModified()); + + doc->setUndoRedoEnabled(false); + doc->setUndoRedoEnabled(true); + + cursor.insertText("Hello"); + + QVERIFY(doc->isModified()); + doc->undo(); + QVERIFY(!doc->isModified()); +} + +void tst_QTextDocument::isModified4() +{ + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + cursor.insertText("World"); + + doc->setModified(false); + + QVERIFY(!doc->isModified()); + + cursor.insertText("Again"); + QVERIFY(doc->isModified()); + + doc->undo(); + QVERIFY(!doc->isModified()); + doc->undo(); + QVERIFY(doc->isModified()); + + doc->redo(); + QVERIFY(!doc->isModified()); + doc->redo(); + QVERIFY(doc->isModified()); + + doc->undo(); + QVERIFY(!doc->isModified()); + doc->undo(); + QVERIFY(doc->isModified()); + + //task 197769 + cursor.insertText("Hello"); + QVERIFY(doc->isModified()); +} + +void tst_QTextDocument::noundo_basicIsModifiedChecks() +{ + doc->setUndoRedoEnabled(false); + QSignalSpy spy(doc, SIGNAL(modificationChanged(bool))); + + QVERIFY(!doc->isModified()); + cursor.insertText("Hello World"); + QVERIFY(doc->isModified()); + QCOMPARE(spy.count(), 1); + QVERIFY(spy.takeFirst().at(0).toBool()); + + doc->undo(); + QVERIFY(doc->isModified()); + QCOMPARE(spy.count(), 0); + + doc->redo(); + QVERIFY(doc->isModified()); + QCOMPARE(spy.count(), 0); +} + +void tst_QTextDocument::task240325() +{ + doc->setHtml("<html><img width=\"100\" height=\"100\" align=\"right\"/>Foobar Foobar Foobar Foobar</html>"); + + QImage img(1000, 7000, QImage::Format_ARGB32_Premultiplied); + QPainter p(&img); + QFontMetrics fm(p.font()); + + // Set page size to contain image and one "Foobar" + doc->setPageSize(QSize(100 + fm.width("Foobar")*2, 1000)); + + // Force layout + doc->drawContents(&p); + + QCOMPARE(doc->blockCount(), 1); + for (QTextBlock block = doc->begin() ; block!=doc->end() ; block = block.next()) { + QTextLayout *layout = block.layout(); + QCOMPARE(layout->lineCount(), 4); + for (int lineIdx=0;lineIdx<layout->lineCount();++lineIdx) { + QTextLine line = layout->lineAt(lineIdx); + + QString text = block.text().mid(line.textStart(), line.textLength()).trimmed(); + + // Remove start token + if (lineIdx == 0) + text = text.mid(1); + + QCOMPARE(text, QString::fromLatin1("Foobar")); + } + } +} + +void tst_QTextDocument::stylesheetFont_data() +{ + QTest::addColumn<QString>("stylesheet"); + QTest::addColumn<QFont>("font"); + + { + QFont font; + font.setBold(true); + font.setPixelSize(64); + + QTest::newRow("Regular font specification") + << "font-size: 64px; font-weight: bold;" + << font; + } + + + { + QFont font; + font.setBold(true); + font.setPixelSize(64); + + QTest::newRow("Shorthand font specification") + << "font: normal bold 64px Arial;" + << font; + } + +} + +void tst_QTextDocument::stylesheetFont() +{ + QFETCH(QString, stylesheet); + QFETCH(QFont, font); + + QString html = QString::fromLatin1("<html>" + "<body>" + "<div style=\"%1\" >" + "Foobar" + "</div>" + "</body>" + "</html>").arg(stylesheet); + + qDebug() << html; + doc->setHtml(html); + QCOMPARE(doc->blockCount(), 1); + + // First and only block + QTextBlock block = doc->firstBlock(); + + QString text = block.text(); + QCOMPARE(text, QString::fromLatin1("Foobar")); + + QFont actualFont = block.charFormat().font(); + + QCOMPARE(actualFont.bold(), font.bold()); + QCOMPARE(actualFont.pixelSize(), font.pixelSize()); +} + +void tst_QTextDocument::noundo_moreIsModified() +{ + doc->setUndoRedoEnabled(false); + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + QVERIFY(doc->isModified()); + + doc->undo(); + QVERIFY(doc->isModified()); + + cursor.insertText("Hello"); + + doc->undo(); + QVERIFY(doc->isModified()); +} + +void tst_QTextDocument::noundo_isModified2() +{ + // reported on qt4-preview-feedback + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + QVERIFY(doc->isModified()); + + doc->setModified(false); + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + QVERIFY(doc->isModified()); +} + +void tst_QTextDocument::noundo_isModified3() +{ + doc->setUndoRedoEnabled(false); + QVERIFY(!doc->isModified()); + + cursor.insertText("Hello"); + + QVERIFY(doc->isModified()); + doc->undo(); + QVERIFY(doc->isModified()); +} + +void tst_QTextDocument::mightBeRichText_data() +{ + const char qtDocuHeader[] = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" + "<!DOCTYPE html\n" + " PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"; + QVERIFY(Qt::mightBeRichText(QString::fromLatin1(qtDocuHeader))); + QTest::addColumn<QString>("input"); + QTest::addColumn<bool>("result"); + + QTest::newRow("documentation-header") << QString("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" + "<!DOCTYPE html\n" + " PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">") + << true; + QTest::newRow("br-nospace") << QString("Test <br/> new line") << true; + QTest::newRow("br-space") << QString("Test <br /> new line") << true; + QTest::newRow("br-invalidspace") << QString("Test <br/ > new line") << false; + QTest::newRow("invalid closing tag") << QString("Test <br/ line") << false; +} + +void tst_QTextDocument::mightBeRichText() +{ + QFETCH(QString, input); + QFETCH(bool, result); + QVERIFY(result == Qt::mightBeRichText(input)); +} + +Q_DECLARE_METATYPE(QTextDocumentFragment) + +#define CREATE_DOC_AND_CURSOR() \ + QTextDocument doc; \ + doc.setDefaultFont(defaultFont); \ + QTextCursor cursor(&doc); + +void tst_QTextDocument::toHtml_data() +{ + QTest::addColumn<QTextDocumentFragment>("input"); + QTest::addColumn<QString>("expectedOutput"); + + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertText("Blah"); + + QTest::newRow("simple") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE>Blah</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertText("&<>"); + + QTest::newRow("entities") << QTextDocumentFragment(&doc) << QString("<p DEFAULTBLOCKSTYLE>&<></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setFontFamily("Times"); + cursor.insertText("Blah", fmt); + + QTest::newRow("font-family") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-family:'Times';\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setFontFamily("Foo's Family"); + cursor.insertText("Blah", fmt); + + QTest::newRow("font-family-with-quotes1") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-family:"Foo's Family";\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setFontFamily("Foo\"s Family"); + cursor.insertText("Blah", fmt); + + QTest::newRow("font-family-with-quotes2") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-family:'Foo"s Family';\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setNonBreakableLines(true); + cursor.insertBlock(fmt); + cursor.insertText("Blah"); + + QTest::newRow("pre") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<pre DEFAULTBLOCKSTYLE>Blah</pre>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setFontPointSize(40); + cursor.insertText("Blah", fmt); + + QTest::newRow("font-size") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-size:40pt;\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setProperty(QTextFormat::FontSizeIncrement, 2); + cursor.insertText("Blah", fmt); + + QTest::newRow("logical-font-size") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-size:x-large;\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertText("Foo"); + + QTextCharFormat fmt; + fmt.setFontPointSize(40); + cursor.insertBlock(QTextBlockFormat(), fmt); + + fmt.clearProperty(QTextFormat::FontPointSize); + cursor.insertText("Blub", fmt); + + QTest::newRow("no-font-size") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE>Foo</p>\n<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blub</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setLayoutDirection(Qt::RightToLeft); + cursor.insertBlock(fmt); + cursor.insertText("Blah"); + + QTest::newRow("rtl") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<p dir='rtl' DEFAULTBLOCKSTYLE>Blah</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setAlignment(Qt::AlignJustify); + cursor.insertBlock(fmt); + cursor.insertText("Blah"); + + QTest::newRow("blockalign") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<p align=\"justify\" DEFAULTBLOCKSTYLE>Blah</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setAlignment(Qt::AlignCenter); + cursor.insertBlock(fmt); + cursor.insertText("Blah"); + + QTest::newRow("blockalign2") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<p align=\"center\" DEFAULTBLOCKSTYLE>Blah</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setAlignment(Qt::AlignRight | Qt::AlignAbsolute); + cursor.insertBlock(fmt); + cursor.insertText("Blah"); + + QTest::newRow("blockalign3") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<p align=\"right\" DEFAULTBLOCKSTYLE>Blah</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setBackground(QColor("#0000ff")); + cursor.insertBlock(fmt); + cursor.insertText("Blah"); + + QTest::newRow("bgcolor") << QTextDocumentFragment(&doc) + << QString("EMPTYBLOCK") + + QString("<p OPENDEFAULTBLOCKSTYLE background-color:#0000ff;\">Blah</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setFontWeight(40); + cursor.insertText("Blah", fmt); + + QTest::newRow("font-weight") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-weight:320;\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setFontItalic(true); + cursor.insertText("Blah", fmt); + + QTest::newRow("font-italic") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" font-style:italic;\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setFontUnderline(true); + fmt.setFontOverline(false); + cursor.insertText("Blah", fmt); + + QTest::newRow("text-decoration-1") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" text-decoration: underline;\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setForeground(QColor("#00ff00")); + cursor.insertText("Blah", fmt); + + QTest::newRow("color") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" color:#00ff00;\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setBackground(QColor("#00ff00")); + cursor.insertText("Blah", fmt); + + QTest::newRow("span-bgcolor") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" background-color:#00ff00;\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setVerticalAlignment(QTextCharFormat::AlignSubScript); + cursor.insertText("Blah", fmt); + + QTest::newRow("valign-sub") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" vertical-align:sub;\">Blah</span></p>"); + + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setVerticalAlignment(QTextCharFormat::AlignSuperScript); + cursor.insertText("Blah", fmt); + + QTest::newRow("valign-super") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" vertical-align:super;\">Blah</span></p>"); + + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setAnchor(true); + fmt.setAnchorName("blub"); + cursor.insertText("Blah", fmt); + + QTest::newRow("named anchor") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><a name=\"blub\"></a>Blah</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setAnchor(true); + fmt.setAnchorHref("http://www.kde.org/"); + cursor.insertText("Blah", fmt); + + QTest::newRow("href anchor") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><a href=\"http://www.kde.org/\">Blah</a></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setAnchor(true); + fmt.setAnchorHref("http://www.kde.org/?a=1&b=2"); + cursor.insertText("Blah", fmt); + + QTest::newRow("href anchor with &") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><a href=\"http://www.kde.org/?a=1&b=2\">Blah</a></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setAnchor(true); + fmt.setAnchorHref("http://www.kde.org/?a='&b=\""); + cursor.insertText("Blah", fmt); + + QTest::newRow("href anchor with ' and \"") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><a href=\"http://www.kde.org/?a='&b="\">Blah</a></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertTable(2, 2); + + QTest::newRow("simpletable") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "\n<tr>\n<td></td>\n<td></td></tr>" + "\n<tr>\n<td></td>\n<td></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTable *table = cursor.insertTable(1, 4); + table->mergeCells(0, 0, 1, 2); + table->mergeCells(0, 2, 1, 2); + + QTest::newRow("tablespans") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "\n<tr>\n<td colspan=\"2\"></td>\n<td colspan=\"2\"></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTableFormat fmt; + fmt.setBorder(1); + fmt.setCellSpacing(3); + fmt.setCellPadding(3); + fmt.setBackground(QColor("#ff00ff")); + fmt.setWidth(QTextLength(QTextLength::PercentageLength, 50)); + fmt.setAlignment(Qt::AlignHCenter); + fmt.setPosition(QTextFrameFormat::FloatRight); + cursor.insertTable(2, 2, fmt); + + QTest::newRow("tableattrs") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" style=\" float: right;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" + "\n<tr>\n<td></td>\n<td></td></tr>" + "\n<tr>\n<td></td>\n<td></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTableFormat fmt; + fmt.setBorder(1); + fmt.setCellSpacing(3); + fmt.setCellPadding(3); + fmt.setBackground(QColor("#ff00ff")); + fmt.setWidth(QTextLength(QTextLength::PercentageLength, 50)); + fmt.setAlignment(Qt::AlignHCenter); + fmt.setPosition(QTextFrameFormat::FloatRight); + fmt.setLeftMargin(25); + fmt.setBottomMargin(35); + cursor.insertTable(2, 2, fmt); + + QTest::newRow("tableattrs2") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" style=\" float: right; margin-top:0px; margin-bottom:35px; margin-left:25px; margin-right:0px;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" + "\n<tr>\n<td></td>\n<td></td></tr>" + "\n<tr>\n<td></td>\n<td></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTableFormat fmt; + fmt.setHeaderRowCount(2); + cursor.insertTable(4, 2, fmt); + + QTest::newRow("tableheader") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "<thead>\n<tr>\n<td></td>\n<td></td></tr>" + "\n<tr>\n<td></td>\n<td></td></tr></thead>" + "\n<tr>\n<td></td>\n<td></td></tr>" + "\n<tr>\n<td></td>\n<td></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTable *table = cursor.insertTable(2, 2); + QTextTable *subTable = table->cellAt(0, 1).firstCursorPosition().insertTable(1, 1); + subTable->cellAt(0, 0).firstCursorPosition().insertText("Hey"); + + QTest::newRow("nestedtable") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "\n<tr>\n<td></td>\n<td>\n<table border=\"1\" cellspacing=\"2\">\n<tr>\n<td>\n<p DEFAULTBLOCKSTYLE>Hey</p></td></tr></table></td></tr>" + "\n<tr>\n<td></td>\n<td></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTableFormat fmt; + QVector<QTextLength> widths; + widths.append(QTextLength()); + widths.append(QTextLength(QTextLength::PercentageLength, 30)); + widths.append(QTextLength(QTextLength::FixedLength, 40)); + fmt.setColumnWidthConstraints(widths); + cursor.insertTable(1, 3, fmt); + + QTest::newRow("colwidths") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "\n<tr>\n<td></td>\n<td width=\"30%\"></td>\n<td width=\"40\"></td></tr>" + "</table>"); + } + + // ### rowspan/colspan tests, once texttable api for that is back again + // + { + CREATE_DOC_AND_CURSOR(); + + QTextTable *table = cursor.insertTable(1, 1); + QTextCursor cellCurs = table->cellAt(0, 0).firstCursorPosition(); + QTextCharFormat fmt; + fmt.setBackground(QColor("#ffffff")); + cellCurs.mergeBlockCharFormat(fmt); + + QTest::newRow("cellproperties") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "\n<tr>\n<td bgcolor=\"#ffffff\"></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + // ### fixme: use programmatic api as soon as we can create floats through it + const char html[] = "<html><body>Blah<img src=\"image.png\" width=\"10\" height=\"20\" style=\"float: right;\" />Blubb</body></html>"; + + QTest::newRow("image") << QTextDocumentFragment::fromHtml(QString::fromLatin1(html)) + << QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah<img src=\"image.png\" width=\"10\" height=\"20\" style=\"float: right;\" />Blubb</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextImageFormat fmt; + fmt.setName("foo"); + fmt.setVerticalAlignment(QTextCharFormat::AlignMiddle); + cursor.insertImage(fmt); + + QTest::newRow("image-malign") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><img src=\"foo\" style=\"vertical-align: middle;\" /></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextImageFormat fmt; + fmt.setName("foo"); + fmt.setVerticalAlignment(QTextCharFormat::AlignTop); + cursor.insertImage(fmt); + + QTest::newRow("image-malign") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><img src=\"foo\" style=\"vertical-align: top;\" /></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextImageFormat fmt; + fmt.setName("foo"); + cursor.insertImage(fmt); + cursor.insertImage(fmt); + + QTest::newRow("2images") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><img src=\"foo\" /><img src=\"foo\" /></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QString txt = QLatin1String("Blah"); + txt += QChar::LineSeparator; + txt += QLatin1String("Bar"); + cursor.insertText(txt); + + QTest::newRow("linebreaks") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE>Blah<br />Bar</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setTopMargin(10); + fmt.setBottomMargin(20); + fmt.setLeftMargin(30); + fmt.setRightMargin(40); + cursor.insertBlock(fmt); + cursor.insertText("Blah"); + + QTest::newRow("blockmargins") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<p style=\" margin-top:10px; margin-bottom:20px; margin-left:30px; margin-right:40px; -qt-block-indent:0; text-indent:0px;\">Blah</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextList *list = cursor.insertList(QTextListFormat::ListDisc); + cursor.insertText("Blubb"); + cursor.insertBlock(); + cursor.insertText("Blah"); + QCOMPARE(list->count(), 2); + + QTest::newRow("lists") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextList *list = cursor.insertList(QTextListFormat::ListDisc); + cursor.insertText("Blubb"); + + cursor.insertBlock(); + + QTextCharFormat blockCharFmt; + blockCharFmt.setForeground(QColor("#0000ff")); + cursor.mergeBlockCharFormat(blockCharFmt); + + QTextCharFormat fmt; + fmt.setForeground(QColor("#ff0000")); + cursor.insertText("Blah", fmt); + QCOMPARE(list->count(), 2); + + QTest::newRow("charfmt-for-list-item") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li style=\" color:#0000ff;\" DEFAULTBLOCKSTYLE><span style=\" color:#ff0000;\">Blah</span></li></ul>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setIndent(3); + fmt.setTextIndent(30); + cursor.insertBlock(fmt); + cursor.insertText("Test"); + + QTest::newRow("block-indent") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:3; text-indent:30px;\">Test</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListDisc); + fmt.setIndent(4); + cursor.insertList(fmt); + cursor.insertText("Blah"); + + QTest::newRow("list-indent") << QTextDocumentFragment(&doc) + << + QString("EMPTYBLOCK") + + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 4;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertBlock(); + + + QTest::newRow("emptyblock") << QTextDocumentFragment(&doc) + // after insertBlock() we /do/ have two blocks in the document, so also expect + // these in the html output + << QString("EMPTYBLOCK") + QString("EMPTYBLOCK"); + } + + { + CREATE_DOC_AND_CURSOR(); + + // if you press enter twice in an empty textedit and then insert 'Test' + // you actually get three visible paragraphs, two empty leading ones and + // a third with the actual text. the corresponding html representation + // therefore should also contain three paragraphs. + + cursor.insertBlock(); + QTextCharFormat fmt; + fmt.setForeground(QColor("#00ff00")); + fmt.setProperty(QTextFormat::FontSizeIncrement, 1); + cursor.mergeBlockCharFormat(fmt); + + fmt.setProperty(QTextFormat::FontSizeIncrement, 2); + cursor.insertText("Test", fmt); + + QTest::newRow("blockcharfmt") << QTextDocumentFragment(&doc) + << QString("EMPTYBLOCK<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:x-large; color:#00ff00;\">Test</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setForeground(QColor("#00ff00")); + cursor.setBlockCharFormat(fmt); + fmt.setForeground(QColor("#0000ff")); + cursor.insertText("Test", fmt); + + QTest::newRow("blockcharfmt2") << QTextDocumentFragment(&doc) + << QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" color:#0000ff;\">Test</span></p>"); + } + + { + QTest::newRow("horizontal-ruler") << QTextDocumentFragment::fromHtml("<hr />") + << + QString("EMPTYBLOCK") + + QString("<hr />"); + } + { + QTest::newRow("horizontal-ruler-with-width") << QTextDocumentFragment::fromHtml("<hr width=\"50%\"/>") + << + QString("EMPTYBLOCK") + + QString("<hr width=\"50%\"/>"); + } + { + CREATE_DOC_AND_CURSOR(); + + QTextFrame *mainFrame = cursor.currentFrame(); + + QTextFrameFormat ffmt; + ffmt.setBorder(1); + ffmt.setPosition(QTextFrameFormat::FloatRight); + ffmt.setMargin(2); + ffmt.setWidth(100); + ffmt.setHeight(50); + ffmt.setBackground(QColor("#00ff00")); + cursor.insertFrame(ffmt); + cursor.insertText("Hello World"); + cursor = mainFrame->lastCursorPosition(); + + QTest::newRow("frame") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" style=\"-qt-table-type: frame; float: right; margin-top:2px; margin-bottom:2px; margin-left:2px; margin-right:2px;\" width=\"100\" height=\"50\" bgcolor=\"#00ff00\">\n<tr>\n<td style=\"border: none;\">\n<p DEFAULTBLOCKSTYLE>Hello World</p></td></tr></table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + fmt.setForeground(QColor("#00ff00")); +// fmt.setBackground(QColor("#0000ff")); + cursor.setBlockCharFormat(fmt); + + fmt.setForeground(QBrush()); +// fmt.setBackground(QBrush()); + cursor.insertText("Test", fmt); + +// QTest::newRow("nostylebrush") << QTextDocumentFragment(&doc) << QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#00ff00; -qt-blockcharfmt-background-color:#0000ff;\">Test</p>"); + QTest::newRow("nostylebrush") << QTextDocumentFragment(&doc) << QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Test</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTable *table = cursor.insertTable(2, 2); + table->mergeCells(0, 0, 1, 2); + QTextTableFormat fmt = table->format(); + QVector<QTextLength> widths; + widths.append(QTextLength(QTextLength::FixedLength, 20)); + widths.append(QTextLength(QTextLength::FixedLength, 40)); + fmt.setColumnWidthConstraints(widths); + table->setFormat(fmt); + + QTest::newRow("mergedtablecolwidths") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "\n<tr>\n<td colspan=\"2\"></td></tr>" + "\n<tr>\n<td width=\"20\"></td>\n<td width=\"40\"></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextCharFormat fmt; + + cursor.insertText("Blah\nGreen yellow green"); + cursor.setPosition(0); + cursor.setPosition(23, QTextCursor::KeepAnchor); + fmt.setBackground(Qt::green); + cursor.mergeCharFormat(fmt); + cursor.clearSelection(); + cursor.setPosition(11); + cursor.setPosition(17, QTextCursor::KeepAnchor); + fmt.setBackground(Qt::yellow); + cursor.mergeCharFormat(fmt); + cursor.clearSelection(); + + QTest::newRow("multiparagraph-bgcolor") << QTextDocumentFragment(&doc) + << QString("<p DEFAULTBLOCKSTYLE><span style=\" background-color:#00ff00;\">Blah</span></p>\n" + "<p DEFAULTBLOCKSTYLE><span style=\" background-color:#00ff00;\">Green </span>" + "<span style=\" background-color:#ffff00;\">yellow</span>" + "<span style=\" background-color:#00ff00;\"> green</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat fmt; + fmt.setBackground(QColor("#0000ff")); + cursor.insertBlock(fmt); + + QTextCharFormat charfmt; + charfmt.setBackground(QColor("#0000ff")); + cursor.insertText("Blah", charfmt); + + QTest::newRow("nospan-bgcolor") << QTextDocumentFragment(&doc) + << QString("EMPTYBLOCK") + + QString("<p OPENDEFAULTBLOCKSTYLE background-color:#0000ff;\"><span style=\" background-color:#0000ff;\">Blah</span></p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTable *table = cursor.insertTable(2, 2); + QTextCharFormat fmt = table->cellAt(0, 0).format(); + fmt.setVerticalAlignment(QTextCharFormat::AlignMiddle); + table->cellAt(0, 0).setFormat(fmt); + fmt = table->cellAt(0, 1).format(); + fmt.setVerticalAlignment(QTextCharFormat::AlignTop); + table->cellAt(0, 1).setFormat(fmt); + fmt = table->cellAt(1, 0).format(); + fmt.setVerticalAlignment(QTextCharFormat::AlignBottom); + table->cellAt(1, 0).setFormat(fmt); + + table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); + + QTest::newRow("table-vertical-alignment") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "\n<tr>\n<td style=\" vertical-align:middle;\">\n" + "<p DEFAULTBLOCKSTYLE>Blah</p></td>" + "\n<td style=\" vertical-align:top;\"></td></tr>" + "\n<tr>\n<td style=\" vertical-align:bottom;\"></td>" + "\n<td></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTable *table = cursor.insertTable(2, 2); + QTextTableCellFormat fmt = table->cellAt(0, 0).format().toTableCellFormat(); + fmt.setLeftPadding(1); + table->cellAt(0, 0).setFormat(fmt); + fmt = table->cellAt(0, 1).format().toTableCellFormat(); + fmt.setRightPadding(1); + table->cellAt(0, 1).setFormat(fmt); + fmt = table->cellAt(1, 0).format().toTableCellFormat(); + fmt.setTopPadding(1); + table->cellAt(1, 0).setFormat(fmt); + fmt = table->cellAt(1, 1).format().toTableCellFormat(); + fmt.setBottomPadding(1); + table->cellAt(1, 1).setFormat(fmt); + + table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); + + QTest::newRow("table-cell-paddings") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" cellspacing=\"2\">" + "\n<tr>\n<td style=\" padding-left:1;\">\n" + "<p DEFAULTBLOCKSTYLE>Blah</p></td>" + "\n<td style=\" padding-right:1;\"></td></tr>" + "\n<tr>\n<td style=\" padding-top:1;\"></td>" + "\n<td style=\" padding-bottom:1;\"></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextTableFormat fmt; + fmt.setBorderBrush(QColor("#0000ff")); + fmt.setBorderStyle(QTextFrameFormat::BorderStyle_Solid); + cursor.insertTable(2, 2, fmt); + + QTest::newRow("tableborder") << QTextDocumentFragment(&doc) + << QString("<table border=\"1\" style=\" border-color:#0000ff; border-style:solid;\" cellspacing=\"2\">" + "\n<tr>\n<td></td>\n<td></td></tr>" + "\n<tr>\n<td></td>\n<td></td></tr>" + "</table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertBlock(); + cursor.insertText("Foo"); + + cursor.block().setUserState(42); + + QTest::newRow("userstate") << QTextDocumentFragment(&doc) + << QString("EMPTYBLOCK") + + QString("<p OPENDEFAULTBLOCKSTYLE -qt-user-state:42;\">Foo</p>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextBlockFormat blockFmt; + blockFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysBefore); + + cursor.insertBlock(blockFmt); + cursor.insertText("Foo"); + + blockFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysBefore | QTextFormat::PageBreak_AlwaysAfter); + + cursor.insertBlock(blockFmt); + cursor.insertText("Bar"); + + QTextTableFormat tableFmt; + tableFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysAfter); + + cursor.insertTable(1, 1, tableFmt); + + QTest::newRow("pagebreak") << QTextDocumentFragment(&doc) + << QString("EMPTYBLOCK") + + QString("<p OPENDEFAULTBLOCKSTYLE page-break-before:always;\">Foo</p>" + "\n<p OPENDEFAULTBLOCKSTYLE page-break-before:always; page-break-after:always;\">Bar</p>" + "\n<table border=\"1\" style=\" page-break-after:always;\" cellspacing=\"2\">\n<tr>\n<td></td></tr></table>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextListFormat listFmt; + listFmt.setStyle(QTextListFormat::ListDisc); + + cursor.insertList(listFmt); + cursor.insertText("Blah"); + + QTest::newRow("list-ul-margin") << QTextDocumentFragment(&doc) + << QString("EMPTYBLOCK") + + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + } +} + +void tst_QTextDocument::toHtml() +{ + QFETCH(QTextDocumentFragment, input); + QFETCH(QString, expectedOutput); + + cursor.insertFragment(input); + + expectedOutput.prepend(htmlHead); + + expectedOutput.replace("OPENDEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"); + expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\""); + expectedOutput.replace("EMPTYBLOCK", "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p>\n"); + if (expectedOutput.endsWith(QLatin1Char('\n'))) + expectedOutput.chop(1); + expectedOutput.append(htmlTail); + + QString output = doc->toHtml(); + + QCOMPARE(output, expectedOutput); + + QDomDocument document; + QVERIFY2(document.setContent(output), "Output was not valid XML"); +} + +void tst_QTextDocument::toHtml2() +{ + QTextDocument doc; + doc.setHtml("<p>text <img src=\"\"> text</p>"); // 4 spaces before the second 'text' + QTextBlock block = doc.firstBlock(); + QTextBlock::Iterator iter = block.begin(); + QTextFragment f = iter.fragment(); + QVERIFY(f.isValid()); + QCOMPARE(f.position(), 0); + QCOMPARE(f.length(), 5); + //qDebug() << block.text().mid(f.position(), f.length()); + + iter++; + f = iter.fragment(); + QVERIFY(f.isValid()); + QCOMPARE(f.position(), 5); + QCOMPARE(f.length(), 1); + //qDebug() << block.text().mid(f.position(), f.length()); + + iter++; + f = iter.fragment(); + //qDebug() << block.text().mid(f.position(), f.length()); + QVERIFY(f.isValid()); + QCOMPARE(f.position(), 6); + QCOMPARE(f.length(), 5); // 1 space should be preserved. + QCOMPARE(block.text().mid(f.position(), f.length()), QString(" text")); + + doc.setHtml("<table><tr><td> foo</td></tr></table> text"); // 4 spaces before the second 'text' + block = doc.firstBlock().next(); + //qDebug() << block.text(); + QCOMPARE(block.text(), QString("foo")); + + block = block.next(); + //qDebug() << block.text(); + QCOMPARE(block.text(), QString("text")); +} + +void tst_QTextDocument::setFragmentMarkersInHtmlExport() +{ + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertText("Leadin"); + const int startPos = cursor.position(); + + cursor.insertText("Test"); + QTextCharFormat fmt; + fmt.setForeground(QColor("#00ff00")); + cursor.insertText("Blah", fmt); + + const int endPos = cursor.position(); + cursor.insertText("Leadout", QTextCharFormat()); + + cursor.setPosition(startPos); + cursor.setPosition(endPos, QTextCursor::KeepAnchor); + QTextDocumentFragment fragment(cursor); + + QString expected = htmlHead; + expected.replace(QRegExp("<body.*>"), QString("<body>")); + expected += QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><!--StartFragment-->Test<span style=\" color:#00ff00;\">Blah</span><!--EndFragment--></p>") + htmlTail; + QCOMPARE(fragment.toHtml(), expected); + } + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertText("Leadin"); + const int startPos = cursor.position(); + + cursor.insertText("Test"); + + const int endPos = cursor.position(); + cursor.insertText("Leadout", QTextCharFormat()); + + cursor.setPosition(startPos); + cursor.setPosition(endPos, QTextCursor::KeepAnchor); + QTextDocumentFragment fragment(cursor); + + QString expected = htmlHead; + expected.replace(QRegExp("<body.*>"), QString("<body>")); + expected += QString("<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><!--StartFragment-->Test<!--EndFragment--></p>") + htmlTail; + QCOMPARE(fragment.toHtml(), expected); + } +} + +void tst_QTextDocument::toHtmlBodyBgColor() +{ + CREATE_DOC_AND_CURSOR(); + + cursor.insertText("Blah"); + + QTextFrameFormat fmt = doc.rootFrame()->frameFormat(); + fmt.setBackground(QColor("#0000ff")); + doc.rootFrame()->setFrameFormat(fmt); + + QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " + "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" + "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" + "p, li { white-space: pre-wrap; }\n" + "</style></head>" + "<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:%4;\"" + " bgcolor=\"#0000ff\">\n" + "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + "</body></html>"); + + expectedHtml = expectedHtml.arg(defaultFont.family()).arg(defaultFont.pointSizeF()).arg(defaultFont.weight() * 8).arg((defaultFont.italic() ? "italic" : "normal")); + + QCOMPARE(doc.toHtml(), expectedHtml); +} + +void tst_QTextDocument::toHtmlRootFrameProperties() +{ + CREATE_DOC_AND_CURSOR(); + + QTextFrameFormat fmt = doc.rootFrame()->frameFormat(); + fmt.setTopMargin(10); + fmt.setLeftMargin(10); + fmt.setBorder(2); + doc.rootFrame()->setFrameFormat(fmt); + + cursor.insertText("Blah"); + + QString expectedOutput("<table border=\"2\" style=\"-qt-table-type: root; margin-top:10px; " + "margin-bottom:4px; margin-left:10px; margin-right:4px;\">\n" + "<tr>\n<td style=\"border: none;\">\n" + "<p DEFAULTBLOCKSTYLE>Blah</p></td></tr></table>"); + + expectedOutput.prepend(htmlHead); + expectedOutput.replace("DEFAULTBLOCKSTYLE", "style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\""); + expectedOutput.append(htmlTail); + + QCOMPARE(doc.toHtml(), expectedOutput); +} + +void tst_QTextDocument::capitalizationHtmlInExport() +{ + doc->setPlainText("Test"); + + QRegExp re(".*span style=\"(.*)\">Test.*"); + QVERIFY(re.exactMatch(doc->toHtml()) == false); // no span + + QTextCursor cursor(doc); + cursor.setPosition(4, QTextCursor::KeepAnchor); + QTextCharFormat cf; + cf.setFontCapitalization(QFont::SmallCaps); + cursor.mergeCharFormat(cf); + + const QString smallcaps = doc->toHtml(); + QVERIFY(re.exactMatch(doc->toHtml())); + QCOMPARE(re.captureCount(), 1); + QCOMPARE(re.cap(1).trimmed(), QString("font-variant:small-caps;")); + + cf.setFontCapitalization(QFont::AllUppercase); + cursor.mergeCharFormat(cf); + const QString uppercase = doc->toHtml(); + QVERIFY(re.exactMatch(doc->toHtml())); + QCOMPARE(re.captureCount(), 1); + QCOMPARE(re.cap(1).trimmed(), QString("text-transform:uppercase;")); + + cf.setFontCapitalization(QFont::AllLowercase); + cursor.mergeCharFormat(cf); + const QString lowercase = doc->toHtml(); + QVERIFY(re.exactMatch(doc->toHtml())); + QCOMPARE(re.captureCount(), 1); + QCOMPARE(re.cap(1).trimmed(), QString("text-transform:lowercase;")); + + doc->setHtml(smallcaps); + cursor.setPosition(1); + QCOMPARE(cursor.charFormat().fontCapitalization(), QFont::SmallCaps); + doc->setHtml(uppercase); + QCOMPARE(cursor.charFormat().fontCapitalization(), QFont::AllUppercase); + doc->setHtml(lowercase); + QCOMPARE(cursor.charFormat().fontCapitalization(), QFont::AllLowercase); +} + +void tst_QTextDocument::wordspacingHtmlExport() +{ + doc->setPlainText("Test"); + + QRegExp re(".*span style=\"(.*)\">Test.*"); + QVERIFY(re.exactMatch(doc->toHtml()) == false); // no span + + QTextCursor cursor(doc); + cursor.setPosition(4, QTextCursor::KeepAnchor); + QTextCharFormat cf; + cf.setFontWordSpacing(4); + cursor.mergeCharFormat(cf); + + QVERIFY(re.exactMatch(doc->toHtml())); + QCOMPARE(re.captureCount(), 1); + QCOMPARE(re.cap(1).trimmed(), QString("word-spacing:4px;")); + + cf.setFontWordSpacing(-8.5); + cursor.mergeCharFormat(cf); + + QVERIFY(re.exactMatch(doc->toHtml())); + QCOMPARE(re.captureCount(), 1); + QCOMPARE(re.cap(1).trimmed(), QString("word-spacing:-8.5px;")); +} + +class CursorPosSignalSpy : public QObject +{ + Q_OBJECT +public: + CursorPosSignalSpy(QTextDocument *doc) + { + calls = 0; + connect(doc, SIGNAL(cursorPositionChanged(const QTextCursor &)), + this, SLOT(cursorPositionChanged(const QTextCursor &))); + } + + int calls; + +private slots: + void cursorPositionChanged(const QTextCursor &) + { + ++calls; + } +}; + +void tst_QTextDocument::cursorPositionChanged() +{ + CursorPosSignalSpy spy(doc); + + cursor.insertText("Test"); + QCOMPARE(spy.calls, 1); + + spy.calls = 0; + QTextCursor unrelatedCursor(doc); + unrelatedCursor.insertText("Blah"); + QCOMPARE(spy.calls, 2); + + spy.calls = 0; + cursor.insertText("Blah"); + QCOMPARE(spy.calls, 1); + + spy.calls = 0; + cursor.movePosition(QTextCursor::PreviousCharacter); + QCOMPARE(spy.calls, 0); +} + +void tst_QTextDocument::cursorPositionChangedOnSetText() +{ + CursorPosSignalSpy spy(doc); + + // doc has one QTextCursor stored in the + // cursor member variable, thus the signal + // gets emitted once. + + doc->setPlainText("Foo\nBar\nBaz\nBlub\nBlah"); + + QCOMPARE(spy.calls, 1); + + spy.calls = 0; + doc->setHtml("<p>Foo<p>Bar<p>Baz<p>Blah"); + + QCOMPARE(spy.calls, 1); +} + +void tst_QTextDocument::textFrameIterator() +{ + cursor.insertTable(1, 1); + + int blockCount = 0; + int frameCount = 0; + + for (QTextFrame::Iterator frameIt = doc->rootFrame()->begin(); + !frameIt.atEnd(); ++frameIt) { + if (frameIt.currentFrame()) + ++frameCount; + else if (frameIt.currentBlock().isValid()) + ++blockCount; + + } + + QEXPECT_FAIL("", "This is currently worked around in the html export but needs fixing!", Continue); + QCOMPARE(blockCount, 0); + QCOMPARE(frameCount, 1); +} + +void tst_QTextDocument::codecForHtml() +{ + const QByteArray header("<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;charset=utf-16\">"); + QTextCodec *c = Qt::codecForHtml(header); + QVERIFY(c); + QCOMPARE(c->name(), QByteArray("UTF-16")); +} + +class TestSyntaxHighlighter : public QObject +{ + Q_OBJECT +public: + inline TestSyntaxHighlighter(QTextDocument *doc) : QObject(doc), ok(false) {} + + bool ok; + +private slots: + inline void markBlockDirty(int from, int charsRemoved, int charsAdded) + { + Q_UNUSED(charsRemoved); + Q_UNUSED(charsAdded); + QTextDocument *doc = static_cast<QTextDocument *>(parent()); + QTextBlock block = doc->findBlock(from); + + QTestDocumentLayout *lout = qobject_cast<QTestDocumentLayout *>(doc->documentLayout()); + lout->called = false; + + doc->markContentsDirty(block.position(), block.length()); + + ok = (lout->called == false); + } + + inline void modifyBlockAgain(int from, int charsRemoved, int charsAdded) + { + Q_UNUSED(charsRemoved); + Q_UNUSED(charsAdded); + QTextDocument *doc = static_cast<QTextDocument *>(parent()); + QTextBlock block = doc->findBlock(from); + QTextCursor cursor(block); + + QTestDocumentLayout *lout = qobject_cast<QTestDocumentLayout *>(doc->documentLayout()); + lout->called = false; + + cursor.insertText("Foo"); + + ok = (lout->called == true); + } +}; + +void tst_QTextDocument::markContentsDirty() +{ + QTestDocumentLayout *lout = new QTestDocumentLayout(doc); + doc->setDocumentLayout(lout); + TestSyntaxHighlighter *highlighter = new TestSyntaxHighlighter(doc); + connect(doc, SIGNAL(contentsChange(int, int, int)), + highlighter, SLOT(markBlockDirty(int, int, int))); + + highlighter->ok = false; + cursor.insertText("Some dummy text blah blah"); + QVERIFY(highlighter->ok); + + disconnect(doc, SIGNAL(contentsChange(int, int, int)), + highlighter, SLOT(markBlockDirty(int, int, int))); + connect(doc, SIGNAL(contentsChange(int, int, int)), + highlighter, SLOT(modifyBlockAgain(int, int, int))); + highlighter->ok = false; + cursor.insertText("FooBar"); + QVERIFY(highlighter->ok); + + lout->called = false; + + doc->markContentsDirty(1, 4); + + QVERIFY(lout->called); +} + +void tst_QTextDocument::clonePreservesMetaInformation() +{ + const QString title("Foobar"); + const QString url("about:blank"); + doc->setHtml("<html><head><title>" + title + "</title></head><body>Hrm</body></html>"); + doc->setMetaInformation(QTextDocument::DocumentUrl, url); + QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), title); + QCOMPARE(doc->metaInformation(QTextDocument::DocumentUrl), url); + + QTextDocument *clone = doc->clone(); + QCOMPARE(clone->metaInformation(QTextDocument::DocumentTitle), title); + QCOMPARE(clone->metaInformation(QTextDocument::DocumentUrl), url); + delete clone; +} + +void tst_QTextDocument::clonePreservesPageSize() +{ + QSizeF sz(100., 100.); + doc->setPageSize(sz); + QTextDocument *clone = doc->clone(); + QCOMPARE(clone->pageSize(), sz); + delete clone; +} + +void tst_QTextDocument::clonePreservesPageBreakPolicies() +{ + QTextTableFormat tableFmt; + tableFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysAfter); + + QTextBlockFormat blockFmt; + blockFmt.setPageBreakPolicy(QTextFormat::PageBreak_AlwaysBefore); + + QTextCursor cursor(doc); + + cursor.setBlockFormat(blockFmt); + cursor.insertText("foo"); + cursor.insertTable(2, 2, tableFmt); + + QTextDocument *clone = doc->clone(); + QCOMPARE(clone->begin().blockFormat().pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore); + QVERIFY(!clone->rootFrame()->childFrames().isEmpty()); + QCOMPARE(clone->rootFrame()->childFrames().first()->frameFormat().pageBreakPolicy(), QTextFormat::PageBreak_AlwaysAfter); + delete clone; +} + +void tst_QTextDocument::clonePreservesDefaultFont() +{ + QFont f = doc->defaultFont(); + QVERIFY(f.pointSize() != 100); + f.setPointSize(100); + doc->setDefaultFont(f); + QTextDocument *clone = doc->clone(); + QCOMPARE(clone->defaultFont(), f); + delete clone; +} + +void tst_QTextDocument::clonePreservesResources() +{ + QUrl testUrl(":/foobar"); + QVariant testResource("hello world"); + + doc->addResource(QTextDocument::ImageResource, testUrl, testResource); + QTextDocument *clone = doc->clone(); + QVERIFY(clone->resource(QTextDocument::ImageResource, testUrl) == testResource); + delete clone; +} + +void tst_QTextDocument::clonePreservesUserStates() +{ + QTextCursor cursor(doc); + cursor.insertText("bla bla bla"); + cursor.block().setUserState(1); + cursor.insertBlock(); + cursor.insertText("foo bar"); + cursor.block().setUserState(2); + cursor.insertBlock(); + cursor.insertText("no user state"); + + QTextDocument *clone = doc->clone(); + QTextBlock b1 = doc->begin(), b2 = clone->begin(); + while (b1 != doc->end()) { + b1 = b1.next(); + b2 = b2.next(); + QCOMPARE(b1.userState(), b2.userState()); + } + QVERIFY(b2 == clone->end()); + delete clone; +} + +void tst_QTextDocument::clonePreservesRootFrameFormat() +{ + doc->setPlainText("Hello"); + QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); + fmt.setMargin(200); + doc->rootFrame()->setFrameFormat(fmt); + QCOMPARE(doc->rootFrame()->frameFormat().margin(), qreal(200)); + QTextDocument *copy = doc->clone(); + QCOMPARE(copy->rootFrame()->frameFormat().margin(), qreal(200)); + delete copy; +} + +void tst_QTextDocument::clonePreservesIndentWidth() +{ + doc->setIndentWidth(42); + QTextDocument *clone = doc->clone(); + QCOMPARE(clone->indentWidth(), qreal(42)); + delete clone; +} + +void tst_QTextDocument::blockCount() +{ + QCOMPARE(doc->blockCount(), 1); + cursor.insertBlock(); + QCOMPARE(doc->blockCount(), 2); + cursor.insertBlock(); + QCOMPARE(doc->blockCount(), 3); + cursor.insertText("blah blah"); + QCOMPARE(doc->blockCount(), 3); + doc->undo(); + doc->undo(); + QCOMPARE(doc->blockCount(), 2); + doc->undo(); + QCOMPARE(doc->blockCount(), 1); +} + +void tst_QTextDocument::resolvedFontInEmptyFormat() +{ + QFont font; + font.setPointSize(42); + doc->setDefaultFont(font); + QTextCharFormat fmt = doc->begin().charFormat(); + QVERIFY(fmt.properties().isEmpty()); + QVERIFY(fmt.font() == font); +} + +void tst_QTextDocument::defaultRootFrameMargin() +{ + QCOMPARE(doc->rootFrame()->frameFormat().margin(), 4.0); +} + +class TestDocument : public QTextDocument +{ +public: + inline TestDocument(const QUrl &testUrl, const QString &testString) + : url(testUrl), string(testString), resourceLoaded(false) {} + + bool hasResourceCached(); + +protected: + virtual QVariant loadResource(int type, const QUrl &name); + +private: + QUrl url; + QString string; + bool resourceLoaded; +}; + +bool TestDocument::hasResourceCached() +{ + resourceLoaded = false; + resource(QTextDocument::ImageResource, url); + return !resourceLoaded; +} + +QVariant TestDocument::loadResource(int type, const QUrl &name) +{ + if (type == QTextDocument::ImageResource + && name == url) { + resourceLoaded = true; + return string; + } + return QTextDocument::loadResource(type, name); +} + +void tst_QTextDocument::clearResources() +{ + // regular resource for QTextDocument + QUrl testUrl(":/foobar"); + QVariant testResource("hello world"); + + // implicitly cached resource, initially loaded through TestDocument::loadResource() + QUrl cacheUrl(":/blub"); + QString cacheResource("mah"); + + TestDocument doc(cacheUrl, cacheResource); + doc.addResource(QTextDocument::ImageResource, testUrl, testResource); + + QVERIFY(doc.resource(QTextDocument::ImageResource, testUrl) == testResource); + + doc.setPlainText("Hah"); + QVERIFY(doc.resource(QTextDocument::ImageResource, testUrl) == testResource); + + doc.setHtml("<b>Mooo</b><img src=\":/blub\"/>"); + QVERIFY(doc.resource(QTextDocument::ImageResource, testUrl) == testResource); + QVERIFY(doc.resource(QTextDocument::ImageResource, cacheUrl) == cacheResource); + + doc.clear(); + QVERIFY(!doc.resource(QTextDocument::ImageResource, testUrl).isValid()); + QVERIFY(!doc.hasResourceCached()); + doc.clear(); + + doc.setHtml("<b>Mooo</b><img src=\":/blub\"/>"); + QVERIFY(doc.resource(QTextDocument::ImageResource, cacheUrl) == cacheResource); + + doc.setPlainText("Foob"); + QVERIFY(!doc.hasResourceCached()); +} + +void tst_QTextDocument::setPlainText() +{ + doc->setPlainText("Hello World"); + QString s(""); + doc->setPlainText(s); + QCOMPARE(doc->toPlainText(), s); +} + +void tst_QTextDocument::toPlainText() +{ + doc->setHtml("Hello World"); + QCOMPARE(doc->toPlainText(), QLatin1String("Hello World")); +} + +void tst_QTextDocument::deleteTextObjectsOnClear() +{ + QPointer<QTextTable> table = cursor.insertTable(2, 2); + QVERIFY(!table.isNull()); + doc->clear(); + QVERIFY(table.isNull()); +} + +void tst_QTextDocument::defaultStyleSheet() +{ + const QString sheet("p { background-color: green; }"); + QVERIFY(doc->defaultStyleSheet().isEmpty()); + doc->setDefaultStyleSheet(sheet); + QCOMPARE(doc->defaultStyleSheet(), sheet); + + cursor.insertHtml("<p>test"); + QTextBlockFormat fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); + + doc->clear(); + cursor.insertHtml("<p>test"); + fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); + + QTextDocument *clone = doc->clone(); + QCOMPARE(clone->defaultStyleSheet(), sheet); + cursor = QTextCursor(clone); + cursor.insertHtml("<p>test"); + fmt = clone->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); + delete clone; + + cursor = QTextCursor(doc); + cursor.insertHtml("<p>test"); + fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); + + doc->clear(); + cursor.insertHtml("<style>p { background-color: red; }</style><p>test"); + fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("red")); + + doc->clear(); + doc->setDefaultStyleSheet("invalid style sheet...."); + cursor.insertHtml("<p>test"); + fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() != QColor("green")); +} + +void tst_QTextDocument::maximumBlockCount() +{ + QCOMPARE(doc->maximumBlockCount(), 0); + QVERIFY(doc->isUndoRedoEnabled()); + + cursor.insertBlock(); + cursor.insertText("Blah"); + cursor.insertBlock(); + cursor.insertText("Foo"); + QCOMPARE(doc->blockCount(), 3); + QCOMPARE(doc->toPlainText(), QString("\nBlah\nFoo")); + + doc->setMaximumBlockCount(1); + QVERIFY(!doc->isUndoRedoEnabled()); + + QCOMPARE(doc->blockCount(), 1); + QCOMPARE(doc->toPlainText(), QString("Foo")); + + cursor.insertBlock(); + cursor.insertText("Hello"); + doc->setMaximumBlockCount(1); + QCOMPARE(doc->blockCount(), 1); + QCOMPARE(doc->toPlainText(), QString("Hello")); + + doc->setMaximumBlockCount(100); + for (int i = 0; i < 1000; ++i) { + cursor.insertBlock(); + cursor.insertText("Blah)"); + QVERIFY(doc->blockCount() <= 100); + } + + cursor.movePosition(QTextCursor::End); + QCOMPARE(cursor.blockNumber(), 99); + QTextCharFormat fmt; + fmt.setFontItalic(true); + cursor.setBlockCharFormat(fmt); + cursor.movePosition(QTextCursor::Start); + QVERIFY(!cursor.blockCharFormat().fontItalic()); + + doc->setMaximumBlockCount(1); + QVERIFY(cursor.blockCharFormat().fontItalic()); + + cursor.insertTable(2, 2); + QCOMPARE(doc->blockCount(), 6); + cursor.insertBlock(); + QCOMPARE(doc->blockCount(), 1); +} + +void tst_QTextDocument::adjustSize() +{ + // avoid ugly tooltips like in task 125583 + QString text("Test Text"); + doc->setPlainText(text); + doc->rootFrame()->setFrameFormat(QTextFrameFormat()); + doc->adjustSize(); + QCOMPARE(doc->size().width(), doc->idealWidth()); +} + +void tst_QTextDocument::initialUserData() +{ + doc->setPlainText("Hello"); + QTextBlock block = doc->begin(); + block.setUserData(new QTextBlockUserData); + QVERIFY(block.userData()); + doc->documentLayout(); + QVERIFY(block.userData()); + doc->setDocumentLayout(new QTestDocumentLayout(doc)); + QVERIFY(!block.userData()); +} + +void tst_QTextDocument::html_defaultFont() +{ + QFont f; + f.setItalic(true); + f.setWeight(QFont::Bold); + doc->setDefaultFont(f); + doc->setPlainText("Test"); + + QString bodyPart = QString::fromLatin1("<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:italic;\">") + .arg(f.family()).arg(f.pointSizeF()).arg(f.weight() * 8); + + QString html = doc->toHtml(); + if (!html.contains(bodyPart)) { + qDebug() << "html:" << html; + qDebug() << "expected body:" << bodyPart; + QVERIFY(html.contains(bodyPart)); + } + + if (html.contains("span")) + qDebug() << "html:" << html; + QVERIFY(!html.contains("<span style")); +} + +void tst_QTextDocument::blockCountChanged() +{ + QSignalSpy spy(doc, SIGNAL(blockCountChanged(int))); + + doc->setPlainText("Foo"); + + QCOMPARE(doc->blockCount(), 1); + QCOMPARE(spy.count(), 0); + + spy.clear(); + + doc->setPlainText("Foo\nBar"); + QCOMPARE(doc->blockCount(), 2); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).value(0).toInt(), 2); + + spy.clear(); + + cursor.movePosition(QTextCursor::End); + cursor.insertText("Blahblah"); + + QCOMPARE(spy.count(), 0); + + cursor.insertBlock(); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).value(0).toInt(), 3); + + spy.clear(); + doc->undo(); + + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).value(0).toInt(), 2); +} + +void tst_QTextDocument::nonZeroDocumentLengthOnClear() +{ + QTestDocumentLayout *lout = new QTestDocumentLayout(doc); + doc->setDocumentLayout(lout); + + doc->clear(); + QVERIFY(lout->called); + QVERIFY(!lout->lastDocumentLengths.contains(0)); +} + +void tst_QTextDocument::setTextPreservesUndoRedoEnabled() +{ + QVERIFY(doc->isUndoRedoEnabled()); + + doc->setPlainText("Test"); + + QVERIFY(doc->isUndoRedoEnabled()); + + doc->setUndoRedoEnabled(false); + QVERIFY(!doc->isUndoRedoEnabled()); + doc->setPlainText("Test2"); + QVERIFY(!doc->isUndoRedoEnabled()); + + doc->setHtml("<p>hello"); + QVERIFY(!doc->isUndoRedoEnabled()); +} + +void tst_QTextDocument::firstLast() +{ + QCOMPARE(doc->blockCount(), 1); + QVERIFY(doc->firstBlock() == doc->lastBlock()); + + doc->setPlainText("Hello\nTest\nWorld"); + + QCOMPARE(doc->blockCount(), 3); + QVERIFY(doc->firstBlock() != doc->lastBlock()); + + QCOMPARE(doc->firstBlock().text(), QString("Hello")); + QCOMPARE(doc->lastBlock().text(), QString("World")); + + // manual forward loop + QTextBlock block = doc->firstBlock(); + + QVERIFY(block.isValid()); + QCOMPARE(block.text(), QString("Hello")); + + block = block.next(); + + QVERIFY(block.isValid()); + QCOMPARE(block.text(), QString("Test")); + + block = block.next(); + + QVERIFY(block.isValid()); + QCOMPARE(block.text(), QString("World")); + + block = block.next(); + QVERIFY(!block.isValid()); + + // manual backward loop + block = doc->lastBlock(); + + QVERIFY(block.isValid()); + QCOMPARE(block.text(), QString("World")); + + block = block.previous(); + + QVERIFY(block.isValid()); + QCOMPARE(block.text(), QString("Test")); + + block = block.previous(); + + QVERIFY(block.isValid()); + QCOMPARE(block.text(), QString("Hello")); + + block = block.previous(); + QVERIFY(!block.isValid()); +} + +const QString backgroundImage_html("<body><table><tr><td background=\"foo.png\">Blah</td></tr></table></body>"); + +void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &doc) +{ + QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " + "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" + "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" + "p, li { white-space: pre-wrap; }\n" + "</style></head>" + "<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:%4;\">\n" + "<table border=\"0\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;\" cellspacing=\"2\" cellpadding=\"0\">" + "\n<tr>\n<td background=\"foo.png\">" + "\n<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + "</td></tr></table></body></html>"); + + expectedHtml = expectedHtml.arg(defaultFont.family()).arg(defaultFont.pointSizeF()).arg(defaultFont.weight() * 8).arg((defaultFont.italic() ? "italic" : "normal")); + + QCOMPARE(doc.toHtml(), expectedHtml); +} + +void tst_QTextDocument::backgroundImage_toHtml() +{ + CREATE_DOC_AND_CURSOR(); + + doc.setHtml(backgroundImage_html); + backgroundImage_checkExpectedHtml(doc); +} + +void tst_QTextDocument::backgroundImage_toHtml2() +{ + CREATE_DOC_AND_CURSOR(); + + cursor.insertHtml(backgroundImage_html); + backgroundImage_checkExpectedHtml(doc); +} + +void tst_QTextDocument::backgroundImage_clone() +{ + CREATE_DOC_AND_CURSOR(); + + doc.setHtml(backgroundImage_html); + QTextDocument *clone = doc.clone(); + backgroundImage_checkExpectedHtml(*clone); + delete clone; +} + +void tst_QTextDocument::backgroundImage_copy() +{ + CREATE_DOC_AND_CURSOR(); + + doc.setHtml(backgroundImage_html); + QTextDocumentFragment fragment(&doc); + + { + CREATE_DOC_AND_CURSOR(); + + cursor.insertFragment(fragment); + backgroundImage_checkExpectedHtml(doc); + } +} + +void tst_QTextDocument::documentCleanup() +{ + QTextDocument doc; + QTextCursor cursor(&doc); + cursor.insertText("d\nfoo\nbar\n"); + doc.documentLayout(); // forces relayout + + // remove char 1 + cursor.setPosition(0); + QSizeF size = doc.documentLayout()->documentSize(); + cursor.deleteChar(); + // the size should be unchanged. + QCOMPARE(doc.documentLayout()->documentSize(), size); +} + +void tst_QTextDocument::characterAt() +{ + QTextDocument doc; + QTextCursor cursor(&doc); + QString text("12345\n67890"); + cursor.insertText(text); + int length = doc.characterCount(); + QCOMPARE(length, text.length() + 1); + QCOMPARE(doc.characterAt(length-1), QChar(QChar::ParagraphSeparator)); + QCOMPARE(doc.characterAt(-1), QChar()); + QCOMPARE(doc.characterAt(length), QChar()); + QCOMPARE(doc.characterAt(length + 1), QChar()); + for (int i = 0; i < text.length(); ++i) { + QChar c = text.at(i); + if (c == QLatin1Char('\n')) + c = QChar(QChar::ParagraphSeparator); + QCOMPARE(doc.characterAt(i), c); + } +} + +void tst_QTextDocument::revisions() +{ + QTextDocument doc; + QTextCursor cursor(&doc); + QString text("Hello World"); + QCOMPARE(doc.firstBlock().revision(), 0); + cursor.insertText(text); + QCOMPARE(doc.firstBlock().revision(), 1); + cursor.setPosition(6); + cursor.insertBlock(); + QCOMPARE(cursor.block().previous().revision(), 2); + QCOMPARE(cursor.block().revision(), 2); + cursor.insertText("candle"); + QCOMPARE(cursor.block().revision(), 3); + cursor.movePosition(QTextCursor::EndOfBlock); + cursor.insertBlock(); // we are at the block end + QCOMPARE(cursor.block().previous().revision(), 3); + QCOMPARE(cursor.block().revision(), 4); + cursor.insertText("lightbulb"); + QCOMPARE(cursor.block().revision(), 5); + cursor.movePosition(QTextCursor::StartOfBlock); + cursor.insertBlock(); // we are the block start + QCOMPARE(cursor.block().previous().revision(), 6); + QCOMPARE(cursor.block().revision(), 5); +} + +void tst_QTextDocument::revisionWithUndoCompressionAndUndo() +{ + QTextDocument doc; + QTextCursor cursor(&doc); + cursor.insertText("This is the beginning of it all."); + QCOMPARE(doc.firstBlock().revision(), 1); + QCOMPARE(doc.revision(), 1); + cursor.insertBlock(); + QCOMPARE(doc.revision(), 2); + cursor.insertText("this"); + QCOMPARE(doc.revision(), 3); + cursor.insertText("is"); + QCOMPARE(doc.revision(), 4); + cursor.insertText("compressed"); + QCOMPARE(doc.revision(), 5); + doc.undo(); + QCOMPARE(doc.revision(), 6); + QCOMPARE(doc.toPlainText(), QString("This is the beginning of it all.\n")) ; + cursor.setPosition(0); + QCOMPARE(doc.firstBlock().revision(), 1); + cursor.insertText("Very beginnig"); + QCOMPARE(doc.firstBlock().revision(), 7); + doc.undo(); + QCOMPARE(doc.revision(), 8); + QCOMPARE(doc.firstBlock().revision(), 1); + + cursor.beginEditBlock(); + cursor.insertText("Hello"); + cursor.insertBlock(); + cursor.insertText("world"); + cursor.endEditBlock(); + QCOMPARE(doc.revision(), 9); + doc.undo(); + QCOMPARE(doc.revision(), 10); + + +} + +void tst_QTextDocument::testUndoCommandAdded() +{ + QVERIFY(doc); + QSignalSpy spy(doc, SIGNAL(undoCommandAdded())); + QVERIFY(spy.isValid()); + QVERIFY(spy.isEmpty()); + + cursor.insertText("a"); + QCOMPARE(spy.count(), 1); + cursor.insertText("b"); // should be merged + QCOMPARE(spy.count(), 1); + cursor.insertText("c"); // should be merged + QCOMPARE(spy.count(), 1); + QCOMPARE(doc->toPlainText(), QString("abc")); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("")); + + doc->clear(); + spy.clear(); + cursor.insertText("aaa"); + QCOMPARE(spy.count(), 1); + + spy.clear(); + cursor.insertText("aaaa\nbcd"); + QCOMPARE(spy.count(), 1); + + spy.clear(); + cursor.beginEditBlock(); + cursor.insertText("aa"); + cursor.insertText("bbb\n"); + cursor.setCharFormat(QTextCharFormat()); + cursor.insertText("\nccc"); + QVERIFY(spy.isEmpty()); + cursor.endEditBlock(); + QCOMPARE(spy.count(), 1); + + spy.clear(); + cursor.insertBlock(); + QCOMPARE(spy.count(), 1); + + spy.clear(); + cursor.setPosition(5); + QVERIFY(spy.isEmpty()); + cursor.setCharFormat(QTextCharFormat()); + QVERIFY(spy.isEmpty()); + cursor.setPosition(10, QTextCursor::KeepAnchor); + QVERIFY(spy.isEmpty()); + QTextCharFormat cf; + cf.setFontItalic(true); + cursor.mergeCharFormat(cf); + QCOMPARE(spy.count(), 1); + + spy.clear(); + doc->undo(); + QCOMPARE(spy.count(), 0); + doc->undo(); + QCOMPARE(spy.count(), 0); + spy.clear(); + doc->redo(); + QCOMPARE(spy.count(), 0); + doc->redo(); + QCOMPARE(spy.count(), 0); +} + +void tst_QTextDocument::testUndoBlocks() +{ + QVERIFY(doc); + cursor.insertText("Hello World"); + cursor.insertText("period"); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("")); + cursor.insertText("Hello World"); + cursor.insertText("One\nTwo\nThree"); + QCOMPARE(doc->toPlainText(), QString("Hello WorldOne\nTwo\nThree")); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("Hello World")); + cursor.insertText("One\nTwo\nThree"); + cursor.insertText("Trailing text"); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("Hello WorldOne\nTwo\nThree")); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("Hello World")); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("")); + + cursor.insertText("quod"); + cursor.beginEditBlock(); + cursor.insertText(" erat"); + cursor.endEditBlock(); + cursor.insertText(" demonstrandum"); + QCOMPARE(doc->toPlainText(), QString("quod erat demonstrandum")); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("quod erat")); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("quod")); + doc->undo(); + QCOMPARE(doc->toPlainText(), QString("")); +} + +class Receiver : public QObject +{ + Q_OBJECT + public: + QString first; + public slots: + void cursorPositionChanged() { + if (first.isEmpty()) + first = QLatin1String("cursorPositionChanged"); + } + + void contentsChange() { + if (first.isEmpty()) + first = QLatin1String("contentsChanged"); + } +}; + +void tst_QTextDocument::receiveCursorPositionChangedAfterContentsChange() +{ + QVERIFY(doc); + doc->setDocumentLayout(new MyAbstractTextDocumentLayout(doc)); + Receiver rec; + connect(doc, SIGNAL(cursorPositionChanged(QTextCursor)), + &rec, SLOT(cursorPositionChanged())); + connect(doc, SIGNAL(contentsChange(int,int,int)), + &rec, SLOT(contentsChange())); + cursor.insertText("Hello World"); + QCOMPARE(rec.first, QString("contentsChanged")); +} + +void tst_QTextDocument::escape_data() +{ + QTest::addColumn<QString>("original"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("1") << "Hello World\n" << "Hello World\n"; + QTest::newRow("2") << "#include <QtCore>" << "#include <QtCore>"; + QTest::newRow("3") << "<p class=\"cool\"><a href=\"http://example.com/?foo=bar&bar=foo\">plop --> </a></p>" + << "<p class="cool"><a href="http://example.com/?foo=bar&amp;bar=foo">plop --&gt; </a></p>"; + QTest::newRow("4") << QString::fromUtf8("<\320\222\321\201>") << QString::fromUtf8("<\320\222\321\201>"); +} + +void tst_QTextDocument::escape() +{ + QFETCH(QString, original); + QFETCH(QString, expected); + + QCOMPARE(Qt::escape(original), expected); +} + +void tst_QTextDocument::copiedFontSize() +{ + QTextDocument documentInput; + QTextDocument documentOutput; + + QFont fontInput; + fontInput.setPixelSize(24); + + QTextCursor cursorInput(&documentInput); + QTextCharFormat formatInput = cursorInput.charFormat(); + formatInput.setFont(fontInput); + cursorInput.insertText("Should be the same font", formatInput); + cursorInput.select(QTextCursor::Document); + + QTextDocumentFragment fragmentInput(cursorInput); + QString html = fragmentInput.toHtml(); + + QTextCursor cursorOutput(&documentOutput); + QTextDocumentFragment fragmentOutput = QTextDocumentFragment::fromHtml(html); + cursorOutput.insertFragment(fragmentOutput); + + QCOMPARE(cursorOutput.charFormat().font().pixelSize(), 24); +} + +void tst_QTextDocument::htmlExportImportBlockCount() +{ + QTextDocument document; + { + QTextCursor cursor(&document); + cursor.insertText("Foo"); + cursor.insertBlock(); + cursor.insertBlock(); + cursor.insertBlock(); + cursor.insertBlock(); + cursor.insertText("Bar"); + } + + QCOMPARE(document.blockCount(), 5); + QString html = document.toHtml(); + + document.clear(); + document.setHtml(html); + + QCOMPARE(document.blockCount(), 5); +} + +QTEST_MAIN(tst_QTextDocument) +#include "tst_qtextdocument.moc" diff --git a/tests/auto/gui/text/qtextdocumentfragment/.gitignore b/tests/auto/gui/text/qtextdocumentfragment/.gitignore new file mode 100644 index 0000000000..5c569834d3 --- /dev/null +++ b/tests/auto/gui/text/qtextdocumentfragment/.gitignore @@ -0,0 +1 @@ +tst_qtextdocumentfragment diff --git a/tests/auto/gui/text/qtextdocumentfragment/qtextdocumentfragment.pro b/tests/auto/gui/text/qtextdocumentfragment/qtextdocumentfragment.pro new file mode 100644 index 0000000000..e6ddd45f85 --- /dev/null +++ b/tests/auto/gui/text/qtextdocumentfragment/qtextdocumentfragment.pro @@ -0,0 +1,8 @@ +load(qttest_p4) + +QT += core-private gui-private + +SOURCES += tst_qtextdocumentfragment.cpp + + + diff --git a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp new file mode 100644 index 0000000000..68c7a285ef --- /dev/null +++ b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp @@ -0,0 +1,4030 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <qtextdocument.h> +#include <qtextdocumentfragment.h> +#include <qtexttable.h> +#include <qtextlist.h> +#include <qdebug.h> +#include <private/qtextdocument_p.h> + + +#include <qtextcursor.h> + +QT_FORWARD_DECLARE_CLASS(QTextDocument) + +//TESTED_CLASS= +//TESTED_FILES=gui/text/qtextdocumentfragment.h gui/text/qtextdocumentfragment.cpp gui/text/qtexthtmlparser.cpp gui/text/qtexthtmlparser_p.h + +class tst_QTextDocumentFragment : public QObject +{ + Q_OBJECT + +public: + tst_QTextDocumentFragment(); + ~tst_QTextDocumentFragment(); + +public slots: + void init(); + void cleanup(); +private slots: + void listCopying(); + void listZeroCopying(); + void listCopying2(); + void tableCopying(); + void tableCopyingWithColSpans(); + void tableColSpanAndWidth(); + void tableImport(); + void tableImport2(); + void tableImport3(); + void tableImport4(); + void tableImport5(); + void textCopy(); + void copyWholeDocument(); + void title(); + void html_listIndents1(); + void html_listIndents2(); + void html_listIndents3(); + void html_listIndents4(); + void html_listIndents5(); + void html_listIndents6(); + void blockCharFormat(); + void blockCharFormatCopied(); + void initialBlock(); + void clone(); + void dontRemoveInitialBlockIfItHoldsObjectIndexedCharFormat(); + void dosLineFeed(); + void unorderedListEnumeration(); + void resetHasBlockAfterClosedBlockTags(); + void ignoreStyleTags(); + void hrefAnchor(); + void namedAnchorFragments(); + void namedAnchorFragments2(); + void namedAnchorFragments3(); + void dontInheritAlignmentInTables(); + void cellBlockCount(); + void cellBlockCount2(); + void emptyTable(); + void emptyTable2(); + void emptyTable3(); + void doubleRowClose(); + void mayNotHaveChildren(); + void inheritAlignment(); + void dontEmitEmptyNodeWhenEmptyTagIsFollowedByCloseTag(); + void toPlainText(); + void copyTableRow(); + void copyTableColumn(); + void copySubTable(); + void html_textDecoration(); + void html_infiniteLoop(); + void html_blockIndent(); + void html_listIndent(); + void html_whitespace(); + void html_whitespace_data(); + void html_qt3Whitespace(); + void html_qt3WhitespaceWithFragments(); + void html_qt3WhitespaceAfterTags(); + void html_listStart1(); + void html_listStart2(); + void html_cssMargin(); + void html_hexEntities(); + void html_decEntities(); + void html_thCentered(); + void orderedListNumbering(); + void html_blockAfterList(); + void html_subAndSuperScript(); + void html_cssColors(); + void obeyFragmentMarkersInImport(); + void whitespaceWithFragmentMarkers(); + void html_emptyParapgraphs1(); + void html_emptyParapgraphs2(); + void html_emptyParagraphs3(); + void html_emptyParagraphs4(); + void html_font(); + void html_fontSize(); + void html_fontSizeAdjustment(); + void html_cssFontSize(); + void html_cssShorthandFont(); + void html_bodyBgColor(); + void html_qtBgColor(); + void html_blockLevelDiv(); + void html_spanNesting(); + void html_nestedLists(); + void noSpecialCharactersInPlainText(); + void html_doNotInheritBackground(); + void html_inheritBackgroundToInlineElements(); + void html_doNotInheritBackgroundFromBlockElements(); + void html_nobr(); + void fromPlainText(); + void fromPlainText2(); + void html_closingImageTag(); + void html_emptyDocument(); + void html_closingTag(); + void html_anchorAroundImage(); + void html_floatBorder(); + void html_frameImport(); + void html_frameImport2(); + void html_dontAddMarginsAcrossTableCells(); + void html_dontMergeCenterBlocks(); + void html_tableCellBgColor(); + void html_tableCellBgColor2(); + void html_cellSkip(); + void nonZeroMarginOnImport(); + void html_charFormatPropertiesUnset(); + void html_headings(); + void html_quotedFontFamily(); + void html_spanBackgroundColor(); + void defaultFont(); + void html_brokenTitle_data(); + void html_brokenTitle(); + void html_blockVsInline(); + void html_tbody(); + void html_nestedTables(); + void html_rowSpans(); + void html_rowSpans2(); + void html_implicitParagraphs(); + void html_missingCloseTag(); + void html_anchorColor(); + void html_lastParagraphClosing(); + void html_tableHeaderBodyFootParent(); + void html_columnWidths(); + void html_bodyBackground(); + void html_tableCellBackground(); + void css_bodyBackground(); + void css_tableCellBackground(); + void css_fontWeight(); + void css_float(); + void css_textIndent(); + void css_inline(); + void css_external(); + void css_import(); + void css_selectors_data(); + void css_selectors(); + void css_nodeNameCaseInsensitivity(); + void css_textUnderlineStyle_data(); + void css_textUnderlineStyle(); + void css_textUnderlineStyleAndDecoration(); + void css_listStyleType(); + void css_linkPseudo(); + void css_pageBreaks(); + void css_cellPaddings(); + void universalSelectors_data(); + void universalSelectors(); + void screenMedia(); + void htmlResourceLoading(); + void someCaseInsensitiveAttributeValues(); + void backgroundImage(); + void dontMergePreAndNonPre(); + void leftMarginInsideHtml(); + void html_margins(); + void newlineInsidePreShouldBecomeNewParagraph(); + void invalidColspan(); + void html_brokenTableWithJustTr(); + void html_brokenTableWithJustTd(); + void html_preNewlineHandling_data(); + void html_preNewlineHandling(); + void html_br(); + void html_dl(); + void html_tableStrangeNewline(); + void html_tableStrangeNewline2(); + void html_tableStrangeNewline3(); + void html_caption(); + void html_windowsEntities(); + void html_eatenText(); + void html_hr(); + void html_hrMargins(); + void html_blockQuoteMargins(); + void html_definitionListMargins(); + void html_listMargins(); + void html_titleAttribute(); + void html_compressDivs(); + void completeToPlainText(); + void copyContents(); + void html_textAfterHr(); + void blockTagClosing(); + void isEmpty(); + void html_alignmentInheritance(); + void html_ignoreEmptyDivs(); + void html_dontInheritAlignmentForFloatingImages(); + void html_verticalImageAlignment(); + void html_verticalCellAlignment(); + void html_borderColor(); + void html_borderStyle(); + void html_borderWidth(); + void html_userState(); + void html_rootFrameProperties(); + void html_alignmentPropertySet(); + void html_appendList(); + void html_appendList2(); + void html_qt3RichtextWhitespaceMode(); + void html_brAfterHr(); + void html_unclosedHead(); + void html_entities(); + void html_entities_data(); + void html_ignore_script(); + void html_directionWithHtml(); + void html_directionWithRichText(); + void html_metaInBody(); + void html_importImageWithoutAspectRatio(); + void html_fromFirefox(); + +private: + inline void setHtml(const QString &html) + // don't take the shortcut in QTextDocument::setHtml + { doc->clear(); QTextCursor(doc).insertFragment(QTextDocumentFragment::fromHtml(html)); } + + inline void appendHtml(const QString &html) + { + QTextCursor cursor(doc); + cursor.movePosition(QTextCursor::End); + cursor.insertHtml(html); + } + + QTextDocument *doc; + QTextCursor cursor; +}; + +tst_QTextDocumentFragment::tst_QTextDocumentFragment() +{ + QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); + img.save("foo.png"); +} + +tst_QTextDocumentFragment::~tst_QTextDocumentFragment() +{ + QFile::remove(QLatin1String("foo.png")); +} + +void tst_QTextDocumentFragment::init() +{ + doc = new QTextDocument; + cursor = QTextCursor(doc); +} + +void tst_QTextDocumentFragment::cleanup() +{ + cursor = QTextCursor(); + delete doc; + doc = 0; +} + +#include <private/qtextdocument_p.h> +#include <qdebug.h> +static void dumpTable(const QTextDocumentPrivate *pt) +{ + qDebug() << "---dump----"; + qDebug() << "all text:" << pt->buffer(); + for (QTextDocumentPrivate::FragmentIterator it = pt->begin(); + !it.atEnd(); ++it) { + qDebug() << "Fragment at text position" << it.position() << "; stringPosition" << it.value()->stringPosition << "; size" << it.value()->size_array[0] << "format :" << it.value()->format << "frag: " << it.n; + qDebug() << " text:" << pt->buffer().mid(it.value()->stringPosition, it.value()->size_array[0]); + } + qDebug() << "----begin block dump----"; + for (QTextBlock it = pt->blocksBegin(); it.isValid(); it = it.next()) + qDebug() << "block at" << it.position() << "with length" << it.length() << "block alignment" << it.blockFormat().alignment(); + qDebug() << "---dump----"; +} +static void dumpTable(QTextDocument *doc) { dumpTable(doc->docHandle()); } + +void tst_QTextDocumentFragment::listCopying() +{ + cursor.insertList(QTextListFormat::ListDecimal); + + QTextFormat originalBlockFormat = cursor.blockFormat(); + QVERIFY(originalBlockFormat.objectIndex() != -1); + int originalListItemIdx = cursor.blockFormat().objectIndex(); + + cursor.insertText("Hello World"); + + QTextDocumentFragment fragment(doc); + + cursor.insertFragment(fragment); + + QVERIFY(cursor.currentList()); + QVERIFY(cursor.blockFormat() != originalBlockFormat); + QVERIFY(cursor.blockFormat().objectIndex() != originalListItemIdx); +} + +void tst_QTextDocumentFragment::listZeroCopying() +{ + // same testcase as above but using the zero-copying + + cursor.insertList(QTextListFormat::ListDecimal); + + QTextFormat originalBlockFormat = cursor.blockFormat(); + int originalListItemIdx = cursor.blockFormat().objectIndex(); + + cursor.insertText("Hello World"); + + QTextDocumentFragment fragment(doc); + cursor.insertFragment(fragment); + + QVERIFY(cursor.currentList()); + QVERIFY(cursor.blockFormat() != originalBlockFormat); + QVERIFY(cursor.blockFormat().objectIndex() != originalListItemIdx); +} + +void tst_QTextDocumentFragment::listCopying2() +{ + cursor.insertList(QTextListFormat::ListDecimal); + cursor.insertText("Hello World"); + + cursor.insertList(QTextListFormat::ListDisc); + cursor.insertText("Hello World"); + + QTextDocumentFragment fragment(doc); + + cursor.insertFragment(fragment); + + cursor.movePosition(QTextCursor::Start); + int listItemCount = 0; + do { + if (cursor.currentList()) + listItemCount++; + } while (cursor.movePosition(QTextCursor::NextBlock)); + + QCOMPARE(listItemCount, 4); + + // we call this here because it used to cause a failing assertion in the + // list manager. + doc->undo(); +} + +void tst_QTextDocumentFragment::tableCopying() +{ + // this tests both, the fragment to use the direction insertion instead of using the + // cursor, which might adjuts its position when inserting a table step by step, as well + // as the pasiveness of the tablemanager. + QTextDocumentFragment fragment; + { + QTextDocument doc; + QTextCursor cursor(&doc); + + QTextTableFormat fmt; + QTextTable *table = cursor.insertTable(2, 2, fmt); + + table->cellAt(0, 0).firstCursorPosition().insertText("First Cell"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second Cell"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third Cell"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth Cell"); + + fragment = QTextDocumentFragment(&doc); + } + { + QTextDocument doc; + QTextCursor cursor(&doc); + + cursor.insertText("FooBar"); + cursor.insertBlock(); + cursor.movePosition(QTextCursor::Left); + + cursor.insertFragment(fragment); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); + } +} + +void tst_QTextDocumentFragment::tableCopyingWithColSpans() +{ + const char html[] = "" +"<table border>" +" <tr>" +" <td>First Cell" +" <td>Second Cell" +" </tr>" +" <tr>" +" <td colspan=\"2\">Third Cell" +" </tr>" +" <tr>" +" <td>Fourth Cell" +" <td>Fifth Cell" +" </tr>" +"</table>"; + setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QVERIFY(table->columns() == 2 && table->rows() == 3); + + cursor = table->cellAt(2, 0).lastCursorPosition(); + cursor.setPosition(table->cellAt(0, 0).firstPosition(), QTextCursor::KeepAnchor); + QVERIFY(cursor.hasComplexSelection()); + + int firstRow = 0, numRows = 0, firstCol = 0, numCols = 0; + cursor.selectedTableCells(&firstRow, &numRows, &firstCol, &numCols); + QCOMPARE(firstRow, 0); + QCOMPARE(numRows, 3); + QCOMPARE(firstCol, 0); + QCOMPARE(numCols, 1); + + QTextDocumentFragment frag = cursor.selection(); + cleanup(); + init(); + cursor.insertFragment(frag); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + table = cursor.currentTable(); + QVERIFY(table); + QVERIFY(table->columns() == 1 && table->rows() == 3); +} + +void tst_QTextDocumentFragment::tableColSpanAndWidth() +{ + const char html[] = "" +"<table border=\"0\">" +" <tr>" +" <td colspan=\"4\" width=\"400\">First Cell</td>" +" </tr>" +"</table>"; + setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QVERIFY(table->columns() == 4 && table->rows() == 1); + // make sure its approx 400 and not a multiple due to the colspan + QVERIFY(doc->size().width()> 398.); + QVERIFY(doc->size().width() < 420.); +} + +void tst_QTextDocumentFragment::tableImport() +{ + // used to cause a failing assertion, as HTMLImporter::closeTag was + // called twice with the last node. + QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(QString::fromLatin1("<table><tr><td>Hey</td><td>Blah")); + QVERIFY(!fragment.isEmpty()); +} + +void tst_QTextDocumentFragment::tableImport2() +{ + { + const char html[] = "" + "<table>" + "<tr><td>First Cell</td><td>Second Cell</td></tr>" + "<tr><td>Third Cell</td><td>Fourth Cell</td></tr>" + "</table>"; + + QTextDocument doc; + QTextCursor cursor(&doc); + cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0])))); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 2); + } + { + const char html[] = "" + "<table>" + "<tr><td>First Cell</td><td>Second Cell</td></tr>" + "<tr><td>Third Cell</td><td>" + " <table>" + " <tr><td>First Nested Cell</td><td>Second Nested Cell</td></tr>" + " <tr><td>Third Nested Cell</td><td>Fourth Nested Cell</td></tr>" + " <tr><td>Fifth Nested Cell</td><td>Sixth Nested Cell</td></tr>" + " </table></td></tr>" + "</table>"; + + QTextDocument doc; + QTextCursor cursor(&doc); + cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0])))); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 2); + + /* + QTextCursor fourthCell = table->cellAt(1, 1).firstCursorPosition(); + fourthCell.movePosition(QTextCursor::NextBlock); + table = fourthCell.currentTable(); + QVERIFY(table); + QVERIFY(table != cursor.currentTable()); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 3); + */ + } + { + const char buggyHtml[] = "" + "<table>" + "<tr><td>First Cell<td>Second Cell" + "<tr><td>Third Cell<td>Fourth Cell" + "</table>"; + + QTextDocument doc; + QTextCursor cursor(&doc); + cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(buggyHtml, sizeof(buggyHtml) / sizeof(buggyHtml[0])))); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 2); + } + { + const char buggyHtml[] = "" + "<table>" + "<tr><th>First Cell<th>Second Cell" + "<tr><td>Third Cell<td>Fourth Cell" + "</table>"; + + QTextDocument doc; + QTextCursor cursor(&doc); + cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(buggyHtml, sizeof(buggyHtml) / sizeof(buggyHtml[0])))); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 2); + } + +} + +void tst_QTextDocumentFragment::tableImport3() +{ + // ### would be better to have tree tests for QTextHtmlParser + // make sure the p is a child of the td. If not the following td + // ends up outside the table, causing an assertion + const char html[] = "<table><tr><td><p></p></td><td></td></tr></table>"; + QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(QString::fromLatin1(html)); + QVERIFY(!fragment.isEmpty()); +} + +void tst_QTextDocumentFragment::tableImport4() +{ + const char html[] = "<table>" + "<tr><td>blah</td></tr>" + "<tr><td>blah</td><td>blah</td></tr>" + "</table>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + QCOMPARE(cursor.currentTable()->columns(), 2); +} + +void tst_QTextDocumentFragment::tableImport5() +{ + const char html[] = "<table>" + "<tr>" + " <td>Foo</td>" + " <td>Bar</td>" + " <td>Bleh</td>" + " <td>Blub</td>" + "</tr>" + "<tr>" + " <td>Ahh</td>" + " <td colspan=5>Gah</td>" + "</tr>" + "</table>"; + + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + QCOMPARE(cursor.currentTable()->rows(), 2); + QCOMPARE(cursor.currentTable()->columns(), 6); +} + +void tst_QTextDocumentFragment::textCopy() +{ + /* this test used to cause failing assertions in QTextDocumentFragment */ + /* copy&paste 'lo\bwor' */ + cursor.insertText("Hello"); + cursor.insertBlock(); + cursor.insertText("World"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, 3); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 3); + + QTextDocumentFragment fragment(cursor); + QVERIFY(!fragment.isEmpty()); + cursor.insertFragment(fragment); +} + +void tst_QTextDocumentFragment::copyWholeDocument() +{ + // used to cause the famous currentBlock.position() == pos + 1 failing assertion + cursor.insertText("\nHey\nBlah\n"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + + QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); + fmt.setBackground(Qt::blue); + doc->rootFrame()->setFrameFormat(fmt); + + QTextDocumentFragment fragment(cursor); + QVERIFY(true); // good if we reach this point :) + + cleanup(); + init(); + + fmt.setBackground(Qt::red); + doc->rootFrame()->setFrameFormat(fmt); + + cursor.insertFragment(fragment); + + QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::red); +} + +void tst_QTextDocumentFragment::title() +{ + doc->setHtml(QString::fromLatin1("<html><head><title>Test</title></head><body>Blah</body></html>")); + QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), QString::fromLatin1("Test")); +} + +void tst_QTextDocumentFragment::html_listIndents1() +{ + const char html[] = "<ul><li>Hey</li><li>Hah</li></ul>"; + setHtml(QString::fromLatin1(html)); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextList *list = cursor.currentList(); + QVERIFY(list); + QCOMPARE(list->format().indent(), 1); + QCOMPARE(cursor.block().blockFormat().indent(), 0); +} + +void tst_QTextDocumentFragment::html_listIndents2() +{ + const char html[] = "<ul><li>Hey<p>Hah</ul>"; + setHtml(QString::fromLatin1(html)); + cursor.movePosition(QTextCursor::Start); + QTextList *list = cursor.currentList(); + QVERIFY(list); + QCOMPARE(list->format().indent(), 1); + QCOMPARE(cursor.block().blockFormat().indent(), 0); + + cursor.movePosition(QTextCursor::NextBlock); + QCOMPARE(cursor.block().blockFormat().indent(), 1); +} + +void tst_QTextDocumentFragment::html_listIndents3() +{ + const char html[] = "<ul><li><p>Hah</ul>"; + setHtml(QString::fromLatin1(html)); + cursor.movePosition(QTextCursor::Start); + QTextList *list = cursor.currentList(); + QVERIFY(list); + QCOMPARE(list->format().indent(), 1); + QCOMPARE(cursor.block().blockFormat().indent(), 0); +} + +void tst_QTextDocumentFragment::html_listIndents4() +{ + const char html[] = "<ul><li>Foo</ul><p>This should not have the same indent as Foo"; + setHtml(QString::fromLatin1(html)); + cursor.movePosition(QTextCursor::Start); + QTextList *list = cursor.currentList(); + QVERIFY(list); + QCOMPARE(list->format().indent(), 1); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(!cursor.currentList()); + QCOMPARE(cursor.blockFormat().indent(), 0); +} + +void tst_QTextDocumentFragment::html_listIndents5() +{ + const char html[] = "<ul><li>Foo<p><li>Bar</li></ul>"; + setHtml(QString::fromLatin1(html)); + cursor.movePosition(QTextCursor::Start); + QTextList *list = cursor.currentList(); + QVERIFY(list); + QCOMPARE(list->format().indent(), 1); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentList() == list); + QCOMPARE(cursor.blockFormat().indent(), 0); +} + +void tst_QTextDocumentFragment::html_listIndents6() +{ + const char html[] = "<ul><li>Outer List<div class=\"testclass\"><ul><li>Nested Item 1</li></ul></div></li></ul>"; + setHtml(QString::fromLatin1(html)); + cursor.movePosition(QTextCursor::Start); + QTextList *list = cursor.currentList(); + QVERIFY(list); + QCOMPARE(list->format().indent(), 1); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentList() != list); + list = cursor.currentList(); + QVERIFY(list); + QCOMPARE(list->format().indent(), 2); + + QCOMPARE(cursor.blockFormat().indent(), 0); +} + +void tst_QTextDocumentFragment::blockCharFormat() +{ + const char html[] = "<p style=\"font-style:italic\"><span style=\"font-style:normal\">Test</span></p>"; + setHtml(QString::fromLatin1(html)); + QVERIFY(doc->begin().charFormat().fontItalic()); +} + +void tst_QTextDocumentFragment::blockCharFormatCopied() +{ + QTextCharFormat fmt; + fmt.setForeground(Qt::green); + cursor.setBlockCharFormat(fmt); + cursor.insertText("Test", QTextCharFormat()); + QTextDocumentFragment frag(doc); + cleanup(); + init(); + cursor.insertFragment(frag); + QVERIFY(cursor.blockCharFormat() == fmt); +} + +void tst_QTextDocumentFragment::initialBlock() +{ + const char html[] = "<p>Test</p>"; + setHtml(QString::fromLatin1(html)); + QCOMPARE(doc->blockCount(), 1); +} + +void tst_QTextDocumentFragment::clone() +{ + QTextBlockFormat mod; + mod.setAlignment(Qt::AlignCenter); + cursor.mergeBlockFormat(mod); + cursor.insertText("Blah"); + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignCenter); + QTextDocumentFragment frag(doc); + cleanup(); + init(); + cursor.insertFragment(frag); + cursor.movePosition(QTextCursor::Start); + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignCenter); +} + +void tst_QTextDocumentFragment::dontRemoveInitialBlockIfItHoldsObjectIndexedCharFormat() +{ + const char html[] = "<table><tr><td>cell one<td>cell two</tr><tr><td>cell three<td>cell four</tr></table>"; + QVERIFY(doc->begin().charFormat().objectIndex() == -1); + setHtml(QString::fromLatin1(html)); + int cnt = 0; + + int objectIndexOfLast = -1; + for (QTextBlock blk = doc->begin(); blk.isValid(); blk = blk.next()) { + ++cnt; + objectIndexOfLast = blk.charFormat().objectIndex(); + } + // beginning of frame for first cell + // + beginning of frame for second cell + // + beginning of frame for third cell + // + beginning of frame for fourth cell + // + end of frame + // + initial block + // ==> 6 + QCOMPARE(cnt, 6); + QVERIFY(objectIndexOfLast != -1); + QVERIFY(doc->begin().next().charFormat().objectIndex() != -1); +} + +void tst_QTextDocumentFragment::dosLineFeed() +{ + const char html[] = "<pre>Test\r\n</pre>Bar"; + setHtml(QString::fromLatin1(html)); + QVERIFY(!doc->toPlainText().contains('\r')); + QCOMPARE(doc->toPlainText(), QString("Test\nBar")); +} + +void tst_QTextDocumentFragment::unorderedListEnumeration() +{ + const char html[] = "<ul><ul><ul><li>Blah</li></ul></ul>"; + setHtml(QString::fromLatin1(html)); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListCircle); + + const char html2[] = "<ul><ul><ul type=disc><li>Blah</li></ul></ul>"; + setHtml(QString::fromLatin1(html2)); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListDisc); + +} + +void tst_QTextDocumentFragment::resetHasBlockAfterClosedBlockTags() +{ + // when closing tags we have to make sure hasBlock in import() gets resetted + const char html[] = "<body><table><tr><td><td><p></table><p></body>"; + setHtml(QString::fromLatin1(html)); + QVERIFY(!doc->isEmpty()); +} + +void tst_QTextDocumentFragment::ignoreStyleTags() +{ + const char html[] = "<body><style>Blah</style>Hello</body>"; + setHtml(QString::fromLatin1(html)); + QCOMPARE(doc->toPlainText(), QString("Hello")); +} + +void tst_QTextDocumentFragment::hrefAnchor() +{ + { + const char html[] = "<a href=\"test\">blah</a>"; + setHtml(QString::fromLatin1(html)); + QVERIFY(doc->begin().begin().fragment().charFormat().isAnchor()); + QCOMPARE(doc->begin().begin().fragment().charFormat().anchorHref(), QString::fromAscii("test")); + QVERIFY(doc->begin().begin().fragment().charFormat().fontUnderline() == true); + } + + { + // only hyperlinks should have special formatting + const char html[] = "<a>blah</a>"; + setHtml(QString::fromLatin1(html)); + QVERIFY(doc->begin().begin().fragment().charFormat().isAnchor()); + QVERIFY(doc->begin().begin().fragment().charFormat().fontUnderline() == false); + } +} + +void tst_QTextDocumentFragment::namedAnchorFragments() +{ + // named anchors should be 'invisible', but the fragment right after it should + // hold the attribute + const char html[] = "a<a name=\"test\" />blah"; + setHtml(QString::fromLatin1(html)); + + QTextBlock firstBlock = doc->begin(); + QVERIFY(firstBlock.isValid()); + + QTextBlock::Iterator it = firstBlock.begin(); + QVERIFY(!it.atEnd()); + + // the 'a' + QVERIFY(it.fragment().isValid()); + QCOMPARE(it.fragment().text(), QString::fromAscii("a")); + QVERIFY(it.fragment().charFormat().isAnchor() == false); + + // the 'b' of 'blah' as separate fragment with the anchor attribute + ++it; + QVERIFY(it.fragment().isValid()); + QCOMPARE(it.fragment().text(), QString::fromAscii("b")); + QVERIFY(it.fragment().charFormat().isAnchor()); + + // the 'lah' of 'blah' as remainder + ++it; + QVERIFY(it.fragment().isValid()); + QVERIFY(it.fragment().text().startsWith("lah")); + QVERIFY(it.fragment().charFormat().isAnchor() == false); +} + +void tst_QTextDocumentFragment::namedAnchorFragments2() +{ + const char html[] = "<p> <a name=\"foo\"> Hello"; + setHtml(QString::fromLatin1(html)); + + QCOMPARE(doc->toPlainText(), QString("Hello")); + + QTextBlock::Iterator it = doc->begin().begin(); + QVERIFY(!it.atEnd()); + + QCOMPARE(it.fragment().text(), QString::fromAscii("H")); + QVERIFY(it.fragment().charFormat().isAnchor()); + + ++it; + + QCOMPARE(it.fragment().text(), QString::fromAscii("ello")); + QVERIFY(!it.fragment().charFormat().isAnchor()); +} + +void tst_QTextDocumentFragment::namedAnchorFragments3() +{ + setHtml("<a name=\"target\" /><a name=\"target2\"/><span>Text</span>"); + + QCOMPARE(doc->toPlainText(), QString("Text")); + + QTextBlock::Iterator it = doc->begin().begin(); + QVERIFY(!it.atEnd()); + + QCOMPARE(it.fragment().text(), QString::fromAscii("T")); + QVERIFY(it.fragment().charFormat().isAnchor()); + QCOMPARE(it.fragment().charFormat().anchorName(), QString("target")); + QStringList targets; targets << "target" << "target2"; + QCOMPARE(it.fragment().charFormat().anchorNames(), targets); + + ++it; + + QCOMPARE(it.fragment().text(), QString::fromAscii("ext")); + QVERIFY(!it.fragment().charFormat().isAnchor()); +} + +void tst_QTextDocumentFragment::dontInheritAlignmentInTables() +{ + const char html[] = "<table align=center><tr><td>Hey</td></tr></table>"; + setHtml(QString::fromLatin1(html)); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + QVERIFY(cursor.currentTable()->cellAt(0, 0).isValid()); + QVERIFY(cursor.currentTable()->cellAt(0, 0).firstCursorPosition().block().next().blockFormat().alignment() != Qt::AlignHCenter); +} + +void tst_QTextDocumentFragment::cellBlockCount() +{ + const char html[] = "<table><tr><td>Hey</td></tr></table>"; + setHtml(QString::fromLatin1(html)); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + + QTextTableCell cell = cursor.currentTable()->cellAt(0, 0); + QVERIFY(cell.isValid()); + + int blockCount = 0; + for (QTextFrame::iterator it = cell.begin(); !it.atEnd(); ++it) { + QVERIFY(it.currentFrame() == 0); + QVERIFY(it.currentBlock().isValid()); + ++blockCount; + } + QCOMPARE(blockCount, 1); +} + +void tst_QTextDocumentFragment::cellBlockCount2() +{ + const char html[] = "<table><tr><td><p>Hey</p></td></tr></table>"; + setHtml(QString::fromLatin1(html)); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + + QTextTableCell cell = cursor.currentTable()->cellAt(0, 0); + QVERIFY(cell.isValid()); + + int blockCount = 0; + for (QTextFrame::iterator it = cell.begin(); !it.atEnd(); ++it) { + QVERIFY(it.currentFrame() == 0); + QVERIFY(it.currentBlock().isValid()); + ++blockCount; + } + QCOMPARE(blockCount, 1); +} + +void tst_QTextDocumentFragment::emptyTable() +{ + const char html[] = "<table></table>"; + setHtml(QString::fromLatin1(html)); + QVERIFY(true); // don't crash with a failing assertion +} + +void tst_QTextDocumentFragment::emptyTable2() +{ + const char html[] = "<table></td></tr></table><p>blah</p>"; + setHtml(QString::fromLatin1(html)); + QVERIFY(true); // don't crash with a failing assertion +} + +void tst_QTextDocumentFragment::emptyTable3() +{ + const char html[] = "<table><tr><td><table></table></td><td>Foobar</td></tr></table>"; + setHtml(QString::fromLatin1(html)); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 2); + QTextTableCell cell = table->cellAt(0, 0); + QVERIFY(cell.isValid()); + QVERIFY(cell.firstPosition() == cell.lastPosition()); + cell = table->cellAt(0, 1); + QTextCursor cursor = cell.firstCursorPosition(); + cursor.setPosition(cell.lastPosition(), QTextCursor::KeepAnchor); + QCOMPARE(cursor.selectedText(), QString("Foobar")); +} + +void tst_QTextDocumentFragment::doubleRowClose() +{ + const char html[] = "<table><tr><td>Blah</td></tr></tr><tr><td>Hm</td></tr></table>"; + setHtml(QString::fromLatin1(html)); + QVERIFY(true); // don't crash with a failing assertion +} + +void tst_QTextDocumentFragment::mayNotHaveChildren() +{ + // make sure the Hey does not end up as tag text for the img tag + const char html[] = "<img />Hey"; + setHtml(QString::fromLatin1(html)); + QCOMPARE(doc->toPlainText().mid(1), QString::fromAscii("Hey")); +} + +void tst_QTextDocumentFragment::inheritAlignment() +{ + // make sure attributes from the body tag get inherited + const char html[] = "<body align=right><p>Hey"; + setHtml(QString::fromLatin1(html)); + // html alignment is absolute + QVERIFY(doc->begin().blockFormat().alignment() == Qt::Alignment(Qt::AlignRight|Qt::AlignAbsolute)); +} + +void tst_QTextDocumentFragment::dontEmitEmptyNodeWhenEmptyTagIsFollowedByCloseTag() +{ + // make sure the Hey does not end up as tag text for the img tag + const char html[] = "<body align=right><p align=left>Blah<img></img><p>Hey"; + setHtml(QString::fromLatin1(html)); + QVERIFY(doc->begin().blockFormat().alignment() == Qt::Alignment(Qt::AlignLeft|Qt::AlignAbsolute)); + QVERIFY(doc->begin().next().blockFormat().alignment() == Qt::Alignment(Qt::AlignRight|Qt::AlignAbsolute)); +} + +void tst_QTextDocumentFragment::toPlainText() +{ + QString input = "Hello\nWorld"; + input += QChar::ParagraphSeparator; + input += "Blah"; + doc->setPlainText(input); + QCOMPARE(doc->blockCount(), 3); +} + +void tst_QTextDocumentFragment::copyTableRow() +{ + QTextDocumentFragment frag; + { + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); + table->cellAt(0, 1).firstCursorPosition().insertText("Foo"); + table->cellAt(1, 0).firstCursorPosition().insertText("Bar"); + table->cellAt(1, 1).firstCursorPosition().insertText("Hah"); + + // select second row + cursor = table->cellAt(1, 1).firstCursorPosition(); + cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::KeepAnchor); + + QCOMPARE(table->cellAt(cursor.position()).row(), 1); + QCOMPARE(table->cellAt(cursor.position()).column(), 0); + QCOMPARE(table->cellAt(cursor.anchor()).row(), 1); + QCOMPARE(table->cellAt(cursor.anchor()).column(), 1); + + frag = QTextDocumentFragment(cursor); + } + { + QTextDocument doc2; + cursor = QTextCursor(&doc2); + cursor.insertFragment(frag); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + + QVERIFY(table); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 1); + + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Bar")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Hah")); + } +} + +void tst_QTextDocumentFragment::copyTableColumn() +{ + QTextDocumentFragment frag; + { + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); + table->cellAt(0, 1).firstCursorPosition().insertText("Foo"); + table->cellAt(1, 0).firstCursorPosition().insertText("Bar"); + table->cellAt(1, 1).firstCursorPosition().insertText("Hah"); + + // select second column + cursor = table->cellAt(0, 1).firstCursorPosition(); + cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor); + + QCOMPARE(table->cellAt(cursor.anchor()).row(), 0); + QCOMPARE(table->cellAt(cursor.anchor()).column(), 1); + QCOMPARE(table->cellAt(cursor.position()).row(), 1); + QCOMPARE(table->cellAt(cursor.position()).column(), 1); + + frag = QTextDocumentFragment(cursor); + } + { + QTextDocument doc2; + cursor = QTextCursor(&doc2); + cursor.insertFragment(frag); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + + QVERIFY(table); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->rows(), 2); + + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Foo")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Hah")); + } +} + +void tst_QTextDocumentFragment::copySubTable() +{ + QTextDocumentFragment frag; + { + QTextTableFormat fmt; + QVector<QTextLength> constraints; + constraints << QTextLength(QTextLength::PercentageLength, 16); + constraints << QTextLength(QTextLength::PercentageLength, 28); + constraints << QTextLength(QTextLength::PercentageLength, 28); + constraints << QTextLength(QTextLength::PercentageLength, 28); + fmt.setColumnWidthConstraints(constraints); + + QTextTable *table = cursor.insertTable(4, 4, fmt); + for (int row = 0; row < 4; ++row) + for (int col = 0; col < 4; ++col) + table->cellAt(row, col).firstCursorPosition().insertText(QString("%1/%2").arg(row).arg(col)); + + QCOMPARE(table->format().columnWidthConstraints().count(), table->columns()); + + // select 2x2 subtable + cursor = table->cellAt(1, 1).firstCursorPosition(); + cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + + QCOMPARE(table->cellAt(cursor.anchor()).row(), 1); + QCOMPARE(table->cellAt(cursor.anchor()).column(), 1); + QCOMPARE(table->cellAt(cursor.position()).row(), 2); + QCOMPARE(table->cellAt(cursor.position()).column(), 2); + + frag = QTextDocumentFragment(cursor); + } + { + QTextDocument doc2; + cursor = QTextCursor(&doc2); + cursor.insertFragment(frag); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + + QVERIFY(table); + QVERIFY(table->format().columnWidthConstraints().isEmpty()); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 2); + + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("1/1")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("1/2")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("2/1")); + QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("2/2")); + } +} + +void tst_QTextDocumentFragment::html_textDecoration() +{ + const char html[] = "<span style='text-decoration: overline line-through underline'>Blah</span>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0])))); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().fontUnderline()); + QVERIFY(cursor.charFormat().fontOverline()); + QVERIFY(cursor.charFormat().fontStrikeOut()); +} + +void tst_QTextDocumentFragment::html_infiniteLoop() +{ + { + // used to cause an infinite loop due to the lack of a space after the + // tag name + const char html[] = "<ahref=\"argl\">Link</a>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + QVERIFY(true); + } + + { + const char html[] = "<a href=\"\"a<"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + QVERIFY(true); + } +} + +void tst_QTextDocumentFragment::html_blockIndent() +{ + const char html[] = "<p style=\"-qt-block-indent:3;\">Test</p>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + QCOMPARE(cursor.blockFormat().indent(), 3); +} + +void tst_QTextDocumentFragment::html_listIndent() +{ + const char html[] = "<ul style=\"-qt-list-indent:4;\"><li>Blah</ul>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + QVERIFY(cursor.currentList()); + QCOMPARE(cursor.currentList()->format().indent(), 4); +} + +void tst_QTextDocumentFragment::html_whitespace_data() +{ + QTest::addColumn<QString>("html"); + QTest::addColumn<QString>("expectedPlainText"); + + QTest::newRow("1") << QString("<span>This is some test</span><span> with spaces between words</span>") + << QString("This is some test with spaces between words"); + + QTest::newRow("2") << QString("<span> </span><span>nowhitespacehereplease</span>") + << QString::fromLatin1("nowhitespacehereplease"); + + QTest::newRow("3") << QString("<span style=\"white-space: pre;\"> white space here </span>") + << QString::fromLatin1(" white space here "); + + QTest::newRow("4") << QString("<span style=\"white-space: pre-wrap;\"> white space here </span>") + << QString::fromLatin1(" white space here "); + + QTest::newRow("5") << QString("<a href=\"One.html\">One</a> <a href=\"Two.html\">Two</a> <b>Three</b>\n" + "<b>Four</b>") + << QString::fromLatin1("One Two Three Four"); + + QTest::newRow("6") << QString("<p>Testing: <b><i><u>BoldItalic</u></i></b> <i>Italic</i></p>") + << QString("Testing: BoldItalic Italic"); + + QTest::newRow("7") << QString("<table><tr><td>Blah</td></tr></table> <table border><tr><td>Foo</td></tr></table>") + << QString("\nBlah\n\nFoo\n"); + + QTest::newRow("8") << QString("<table><tr><td><i>Blah</i></td></tr></table> <i>Blub</i>") + << QString("\nBlah\nBlub"); + + QTest::newRow("task116492") << QString("<p>a<font=\"Times\"> b </font>c</p>") + << QString("a b c"); + + QTest::newRow("task121653") << QString("abc<b> def</b>") + << QString("abc def"); + + QTest::newRow("task122650") << QString("<p>Foo</p> Bar") + << QString("Foo\nBar"); + + QTest::newRow("task122650-2") << QString("<p>Foo</p> <p> Bar") + << QString("Foo \nBar"); + + QTest::newRow("task122650-3") << QString("<html>Before<pre>\nTest</pre>") + << QString("Before\nTest"); + + QTest::newRow("br-with-whitespace") << QString("Foo<br>\nBlah") + << QString("Foo\nBlah"); + + QTest::newRow("collapse-p-with-newline") << QString("Foo<p>\n<p>\n<p>\n<p>\n<p>\n<p>\nBar") + << QString("Foo\nBar"); + + QTest::newRow("table") << QString("<table><tr><td>Blah</td></tr></table>\nTest") + << QString("\nBlah\nTest"); + + QTest::newRow("table2") << QString("<table><tr><td><pre>\nTest\n</pre></td>\n </tr></table>") + << QString("\nTest\n"); + + QTest::newRow("table3") << QString("<table><tr><td><pre>\nTest\n</pre> \n \n </td></tr></table>") + << QString("\nTest \n"); +} + +void tst_QTextDocumentFragment::html_whitespace() +{ + QFETCH(QString, html); + QFETCH(QString, expectedPlainText); + + setHtml(html); + + QCOMPARE(doc->toPlainText(), expectedPlainText); +} + +void tst_QTextDocumentFragment::html_qt3Whitespace() +{ + QString text = "This text has some whitespace" + "\n and \nnewlines that \n should be ignored\n\n"; + const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body>") + + text + + QString("</body></html>"); + + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + + text.remove(QChar::fromLatin1('\n')); + + QCOMPARE(doc->toPlainText(), text); +} + +void tst_QTextDocumentFragment::html_qt3WhitespaceWithFragments() +{ + QString text = "This text has some whitespace" + "\n and \nnewlines that \n should be ignored\n\n"; + const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body>" + "blah blah<!--StartFragment--><span>") + + text + + QString("</span><!--EndFragment--></body></html>"); + + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + + text.remove(QChar::fromLatin1('\n')); + + QCOMPARE(doc->toPlainText(), text); +} + +void tst_QTextDocumentFragment::html_qt3WhitespaceAfterTags() +{ + QString text = " This text has some whitespace "; + const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body><span>") + + text + + QString("</span></body></html>"); + + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + + QCOMPARE(doc->toPlainText(), text); +} + +void tst_QTextDocumentFragment::html_listStart1() +{ + // don't create a block for the <ul> element, even if there's some whitespace between + // it and the <li> + const char html[] = "<ul> <li>list item</li><ul>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0])))); + + QCOMPARE(doc->blockCount(), 1); +} + +void tst_QTextDocumentFragment::html_listStart2() +{ + // unlike with html_listStart1 we want a block showing the 'buggy' text here + const char html[] = "<ul>buggy, but text should appear<li>list item</li><ul>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QByteArray::fromRawData(html, sizeof(html) / sizeof(html[0])))); + + QCOMPARE(doc->blockCount(), 2); +} + +void tst_QTextDocumentFragment::html_cssMargin() +{ + const char html[] = "<p style=\"margin-top: 1px; margin-bottom: 2px; margin-left: 3px; margin-right: 4px\">Test</p>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + const QTextBlockFormat fmt = cursor.blockFormat(); + QCOMPARE(fmt.topMargin(), qreal(1)); + QCOMPARE(fmt.bottomMargin(), qreal(2)); + QCOMPARE(fmt.leftMargin(), qreal(3)); + QCOMPARE(fmt.rightMargin(), qreal(4)); +} + +void tst_QTextDocumentFragment::html_hexEntities() +{ + const char html[] = "@"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + QCOMPARE(doc->begin().begin().fragment().text(), QString("@")); +} + +void tst_QTextDocumentFragment::html_decEntities() +{ + const char html[] = "@"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + QCOMPARE(doc->begin().begin().fragment().text(), QString("@")); +} + +void tst_QTextDocumentFragment::html_thCentered() +{ + const char html[] = "<table><tr><th>This should be centered</th></tr></table>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + + cursor.movePosition(QTextCursor::PreviousBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QVERIFY(table->cellAt(0, 0).begin().currentBlock().blockFormat().alignment() == Qt::AlignCenter); +} + +void tst_QTextDocumentFragment::orderedListNumbering() +{ + // Supporter issue 45941 - make sure _two_ separate lists + // are imported, which have their own numbering + const char html[] = "<html><body>" + "<ol><li>elem 1</li></ol>" + "<ol><li>elem 1</li></ol>" + "</body></html>"; + + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + + int numberOfLists = 0; + + cursor.movePosition(QTextCursor::Start); + QTextList *lastList = 0; + do { + QTextList *list = cursor.currentList(); + if (list && list != lastList) { + lastList = list; + ++numberOfLists; + } + } while (cursor.movePosition(QTextCursor::NextBlock)); + + QCOMPARE(numberOfLists, 2); +} + +void tst_QTextDocumentFragment::html_blockAfterList() +{ + const char html[] = "<ul><li>Foo</ul>This should be a separate paragraph and not be indented at the same level as Foo"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + + cursor.movePosition(QTextCursor::Start); + + QVERIFY(cursor.currentList()); + QCOMPARE(cursor.currentList()->format().indent(), 1); + + QVERIFY(cursor.movePosition(QTextCursor::NextBlock)); + QVERIFY(!cursor.currentList()); + QCOMPARE(cursor.blockFormat().indent(), 0); +} + +void tst_QTextDocumentFragment::html_subAndSuperScript() +{ + const char subHtml[] = "<sub>Subby</sub>"; + const char superHtml[] = "<sup>Super</sup>"; + const char subHtmlCss[] = "<span style=\"vertical-align: sub\">Subby</span>"; + const char superHtmlCss[] = "<span style=\"vertical-align: super\">Super</span>"; + const char alignmentInherited[] = "<sub><font face=\"Verdana\">Subby</font></sub>"; + + setHtml(subHtml); + QVERIFY(cursor.charFormat().verticalAlignment() == QTextCharFormat::AlignSubScript); + + setHtml(subHtmlCss); + QVERIFY(cursor.charFormat().verticalAlignment() == QTextCharFormat::AlignSubScript); + + setHtml(superHtml); + QVERIFY(cursor.charFormat().verticalAlignment() == QTextCharFormat::AlignSuperScript); + + setHtml(superHtmlCss); + QVERIFY(cursor.charFormat().verticalAlignment() == QTextCharFormat::AlignSuperScript); + + setHtml(alignmentInherited); + QVERIFY(cursor.charFormat().verticalAlignment() == QTextCharFormat::AlignSubScript); +} + +void tst_QTextDocumentFragment::html_cssColors() +{ + const char color[] = "<span style=\"color:red\"><span style=\"color:blue\">Blue</span></span>"; + setHtml(color); + QVERIFY(cursor.charFormat().foreground().color() == Qt::blue); + + const char rgbColor[] = "<span style=\"color:red\"><span style=\"color:rgb(0, 0, 255)\">Blue</span></span>"; + setHtml(rgbColor); + QVERIFY(cursor.charFormat().foreground().color() == Qt::blue); +} + +void tst_QTextDocumentFragment::obeyFragmentMarkersInImport() +{ + const char html[] = "This leading text should not appear<!--StartFragment--><span>Text</span><!--EndFragment-->This text at the end should not appear"; + setHtml(html); + + QCOMPARE(doc->toPlainText(), QString("Text")); +} + +void tst_QTextDocumentFragment::whitespaceWithFragmentMarkers() +{ + QString text(" text with leading and trailing whitespace "); + const char html[] = "This leading text should not appear<!--StartFragment-->%1<!--EndFragment-->This text at the end should not appear"; + setHtml(QString::fromLatin1(html).arg(text)); + + QString expected("text with leading and trailing whitespace "); + QCOMPARE(doc->toPlainText(), expected); +} + +void tst_QTextDocumentFragment::html_emptyParapgraphs1() +{ + const char html[] = "<p style=\"-qt-paragraph-type:empty;\"> </p><p>Two paragraphs</p>"; + setHtml(html); + + QCOMPARE(doc->blockCount(), 2); + QVERIFY(doc->begin().text().isEmpty()); + QCOMPARE(doc->begin().next().text(), QString("Two paragraphs")); +} + +void tst_QTextDocumentFragment::html_emptyParapgraphs2() +{ + const char html[] = "<p style=\"margin-left:80px\"></p><p>One paragraph</p>"; + setHtml(html); + + QCOMPARE(doc->blockCount(), 1); + QCOMPARE(cursor.blockFormat().leftMargin(), qreal(0)); + + const char html2[] = "<p style=\"margin-left:80px\"></p>One paragraph"; + setHtml(html2); + QCOMPARE(doc->blockCount(), 1); + QCOMPARE(cursor.blockFormat().leftMargin(), qreal(0)); + + const char html3[] = "<p style=\"margin-left:80px\">Foo</p><p></p>Two paragraphs"; + setHtml(html3); + QCOMPARE(doc->blockCount(), 2); + cursor = QTextCursor(doc); + QCOMPARE(cursor.blockFormat().leftMargin(), qreal(80)); + QCOMPARE(cursor.block().next().blockFormat().leftMargin(), qreal(0)); +} + +void tst_QTextDocumentFragment::html_emptyParagraphs3() +{ + const char html[] = "<ul><p>Foo</p><p></p></ul><h4>Bar</h4>"; + + setHtml(html); + + QCOMPARE(doc->blockCount(), 2); + + cursor = QTextCursor(doc); + QCOMPARE(cursor.block().next().blockFormat().indent(), 0); +} + +void tst_QTextDocumentFragment::html_emptyParagraphs4() +{ + const char html[] = "<p>foo</p><p style=\"page-break-before: always\"></p><p>bar</p>"; + setHtml(html); + + QTextBlock block = doc->begin(); + QVERIFY(block.isValid()); + QCOMPARE(block.text(), QString("foo")); + block = block.next(); + QVERIFY(block.isValid()); + QTextBlockFormat bf = block.blockFormat(); + QVERIFY(bf.hasProperty(QTextFormat::PageBreakPolicy)); + QCOMPARE(bf.pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore); + QCOMPARE(block.text(), QString("bar")); + + const char html2[] = "<p>foo</p><p style=\"page-break-after: always\"></p><p>bar</p>"; + setHtml(html2); + + block = doc->begin(); + QVERIFY(block.isValid()); + QCOMPARE(block.text(), QString("foo")); + block = block.next(); + QVERIFY(block.isValid()); + bf = block.blockFormat(); + QVERIFY(bf.hasProperty(QTextFormat::PageBreakPolicy)); + QCOMPARE(bf.pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore); // after the empty line means it should appear for 'bar' + QCOMPARE(block.text(), QString("bar")); +} + +void tst_QTextDocumentFragment::html_font() +{ + const char html[] = "<font color=\"blue\"><p>Hah</p></font>"; + setHtml(html); + + QVERIFY(cursor.charFormat().foreground().color() == Qt::blue); + QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::blue); +} + +void tst_QTextDocumentFragment::html_fontSize() +{ + const char html[] = "<font size=\"2\">Hah</font>"; + setHtml(html); + + QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), -1); +} + +void tst_QTextDocumentFragment::html_fontSizeAdjustment() +{ + const char html[] = "<font size=\"7\"><b>Hah</b></font>"; + setHtml(html); + + QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), 4); + QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); +} + +void tst_QTextDocumentFragment::html_cssFontSize() +{ + const char html[] = "<span style=\"font-size: 50pt\">Foo</span>"; + setHtml(html); + + QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 50); + + const char html2[] = "<span style=\"font-size: 50px\">Foo</span>"; + setHtml(html2); + + QCOMPARE(cursor.charFormat().property(QTextFormat::FontPixelSize).toInt(), 50); + + const char html3[] = "<span style=\"font-size: large\">Foo</span>"; + setHtml(html3); + + QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), 1); +} + +void tst_QTextDocumentFragment::html_cssShorthandFont() +{ + { + const char html[] = "<span style=\"font: 50px sans-serif\">Foo</span>"; + setHtml(html); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontPixelSize).toInt(), 50); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("sans-serif")); + } + { + const char html[] = "<span style=\"font: 50pt sans-serif\">Foo</span>"; + setHtml(html); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 50); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("sans-serif")); + } + { + const char html[] = "<span style='font:7.0pt \"Times New Roman\"'>Foo</span>"; + setHtml(html); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 7); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("Times New Roman")); + } + { + const char html[] = "<span style='font:bold 7.0pt'>Foo</span>"; + setHtml(html); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontWeight).toInt(), int(QFont::Bold)); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 7); + } + { + const char html[] = "<span style='font:bold italic 7.0pt'>Foo</span>"; + setHtml(html); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontWeight).toInt(), int(QFont::Bold)); + QCOMPARE(cursor.charFormat().property(QTextFormat::FontItalic).toBool(), true); + } +} + +void tst_QTextDocumentFragment::html_bodyBgColor() +{ + const char html[] = "<body bgcolor=\"blue\">Foo</body>"; + doc->setHtml(html); + + QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue); +} + +void tst_QTextDocumentFragment::html_qtBgColor() +{ + const char html[] = "<qt bgcolor=\"blue\">Foo</qt>"; + doc->setHtml(html); + + QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue); +} + +void tst_QTextDocumentFragment::html_bodyBackground() +{ + const char html[] = "<body background=\"foo.png\">Foo</body>"; + doc->setHtml(html); + + QVERIFY(doc->rootFrame()->frameFormat().background().style() == Qt::TexturePattern); +} + +void tst_QTextDocumentFragment::html_tableCellBackground() +{ + const char html[] = "<body><table><tr><td background=\"foo.png\">Foo</td></tr></table></body>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QVERIFY(cell.format().background().style() == Qt::TexturePattern); +} + +void tst_QTextDocumentFragment::css_bodyBackground() +{ + const char html[] = "<body style=\"background-image:url('foo.png')\">Foo</body>"; + doc->setHtml(html); + + QVERIFY(doc->rootFrame()->frameFormat().background().style() == Qt::TexturePattern); +} + +void tst_QTextDocumentFragment::css_tableCellBackground() +{ + const char html[] = "<body><table><tr><td style=\"background-image:url('foo.png')\">Foo</td></tr></table></body>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QVERIFY(cell.format().background().style() == Qt::TexturePattern); +} + +void tst_QTextDocumentFragment::css_cellPaddings() +{ + const char html[] = "<body><table><tr><td style=\"padding-left:1\">Foo</td>" + "<td style=\"padding-right:1\"></td><td style=\"padding-top:10\"></td>" + "<td style=\"padding-bottom:5\"></td><td style=\"padding:15\"></td></tr></table></body>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QCOMPARE(cell.format().toTableCellFormat().leftPadding(), qreal(1)); + cell = table->cellAt(0, 1); + QCOMPARE(cell.format().toTableCellFormat().rightPadding(), qreal(1)); + cell = table->cellAt(0, 2); + QCOMPARE(cell.format().toTableCellFormat().topPadding(), qreal(10)); + cell = table->cellAt(0, 3); + QCOMPARE(cell.format().toTableCellFormat().bottomPadding(), qreal(5)); + cell = table->cellAt(0, 4); + QCOMPARE(cell.format().toTableCellFormat().leftPadding(), qreal(15)); + QCOMPARE(cell.format().toTableCellFormat().rightPadding(), qreal(15)); + QCOMPARE(cell.format().toTableCellFormat().topPadding(), qreal(15)); + QCOMPARE(cell.format().toTableCellFormat().bottomPadding(), qreal(15)); +} + +void tst_QTextDocumentFragment::html_blockLevelDiv() +{ + const char html[] = "<div align=right><b>Hello World"; + setHtml(html); + + QCOMPARE(doc->begin().blockFormat().alignment(), Qt::AlignRight|Qt::AlignAbsolute); + QVERIFY(doc->begin().next() == doc->end()); +} + +void tst_QTextDocumentFragment::html_spanNesting() +{ + const char html[] = "<span style=\"color:black\">a<span style=\"color:red\">b<span style=\"color:black\">c</span></span>d</span>"; + setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground() == Qt::black); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground() == Qt::red); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground() == Qt::black); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground() == Qt::black); +} + +void tst_QTextDocumentFragment::html_nestedLists() +{ + const char html[] = "<p><ul><li>Foo<ul><li>In nested list</li></ul></li><li>Last item</li></ul></p>"; + setHtml(html); + + cursor.movePosition(QTextCursor::Start); + QTextList *firstList = cursor.currentList(); + QVERIFY(firstList); + QCOMPARE(firstList->format().indent(), 1); + + cursor.movePosition(QTextCursor::NextBlock); + QTextList *secondList = cursor.currentList(); + QVERIFY(secondList); + QVERIFY(secondList != firstList); + QCOMPARE(cursor.currentList()->format().indent(), 2); + + cursor.movePosition(QTextCursor::NextBlock); + QTextList *thirdList = cursor.currentList(); + QVERIFY(thirdList); + QVERIFY(thirdList == firstList); +} + +void tst_QTextDocumentFragment::noSpecialCharactersInPlainText() +{ + cursor.insertTable(2, 2); + cursor.insertBlock(); + cursor.insertText(QString(QChar::LineSeparator)); + cursor.insertText(QString(QChar::Nbsp)); + + QString plain = doc->toPlainText(); + QVERIFY(!plain.contains(QChar::ParagraphSeparator)); + QVERIFY(!plain.contains(QChar::Nbsp)); + QVERIFY(!plain.contains(QTextBeginningOfFrame)); + QVERIFY(!plain.contains(QTextEndOfFrame)); + QVERIFY(!plain.contains(QChar::LineSeparator)); + + plain = QTextDocumentFragment(doc).toPlainText(); + QVERIFY(!plain.contains(QChar::ParagraphSeparator)); + QVERIFY(!plain.contains(QChar::Nbsp)); + QVERIFY(!plain.contains(QTextBeginningOfFrame)); + QVERIFY(!plain.contains(QTextEndOfFrame)); + QVERIFY(!plain.contains(QChar::LineSeparator)); +} + +void tst_QTextDocumentFragment::html_doNotInheritBackground() +{ + const char html[] = "<html><body bgcolor=\"blue\"><p>Blah</p></body></html>"; + doc->setHtml(html); + + for (QTextBlock block = doc->begin(); + block.isValid(); block = block.next()) { + QVERIFY(block.blockFormat().hasProperty(QTextFormat::BackgroundBrush) == false); + } + + QVERIFY(doc->rootFrame()->frameFormat().hasProperty(QTextFormat::BackgroundBrush)); + QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue); +} + +void tst_QTextDocumentFragment::html_inheritBackgroundToInlineElements() +{ + const char html[] = "<span style=\"background: blue\">Foo<span>Bar</span></span>"; + doc->setHtml(html); + + int fragmentCount = 0; + + QTextBlock block = doc->begin(); + for (QTextBlock::Iterator it = block.begin(); + !it.atEnd(); ++it, ++fragmentCount) { + + const QTextFragment fragment = it.fragment(); + if (fragmentCount == 0) { + QCOMPARE(fragment.text(), QString("FooBar")); + QVERIFY(fragment.charFormat().background().color() == Qt::blue); + } + } + + QCOMPARE(fragmentCount, 1); +} + +void tst_QTextDocumentFragment::html_doNotInheritBackgroundFromBlockElements() +{ + const char html[] = "<p style=\"background: blue\"><span>Foo</span></span>"; + doc->setHtml(html); + + int fragmentCount = 0; + + QTextBlock block = doc->begin(); + for (QTextBlock::Iterator it = block.begin(); + !it.atEnd(); ++it, ++fragmentCount) { + + const QTextFragment fragment = it.fragment(); + if (fragmentCount == 0) { + QCOMPARE(fragment.text(), QString("Foo")); + QVERIFY(!fragment.charFormat().hasProperty(QTextFormat::BackgroundBrush)); + } + } + + QCOMPARE(fragmentCount, 1); +} +void tst_QTextDocumentFragment::html_nobr() +{ + const QString input = "Blah Foo Bar"; + const QString html = QString::fromLatin1("<html><body><p><nobr>") + input + QString::fromLatin1("</nobr></p></body></html>"); + setHtml(html); + + QString text = doc->begin().begin().fragment().text(); + QString expectedText = input; + expectedText.replace(QRegExp("\\s+"), QString(QChar::Nbsp)); + QCOMPARE(text, expectedText); +} + +void tst_QTextDocumentFragment::fromPlainText() +{ + QString plainText; + plainText = "Hello\nWorld\r\nBlub"; + plainText += QChar::ParagraphSeparator; + // TextEdit on OS 10 gives us OS 9 style linefeeds + // when copy & pasteing multi-line plaintext. + plainText += "OS9IsOldSchool\r"; + plainText += "Last Parag"; + + doc->setPlainText(plainText); + + int blockCount = 0; + for (QTextBlock block = doc->begin(); block.isValid(); block = block.next()) { + QVERIFY(!block.text().contains(QLatin1Char('\n'))); + QVERIFY(!block.text().contains(QLatin1Char('\r'))); + QVERIFY(!block.text().contains(QChar::ParagraphSeparator)); + + if (blockCount == 0) + QCOMPARE(block.text(), QString("Hello")); + else if (blockCount == 1) + QCOMPARE(block.text(), QString("World")); + else if (blockCount == 2) + QCOMPARE(block.text(), QString("Blub")); + else if (blockCount == 3) + QCOMPARE(block.text(), QString("OS9IsOldSchool")); + else if (blockCount == 4) + QCOMPARE(block.text(), QString("Last Parag")); + + + ++blockCount; + } + + QCOMPARE(blockCount, 5); +} + +void tst_QTextDocumentFragment::fromPlainText2() +{ + doc->setPlainText("Hello World"); + QCOMPARE(QTextDocumentFragment(doc).toPlainText(), doc->toPlainText()); +} + +void tst_QTextDocumentFragment::html_closingImageTag() +{ + const char html[] = "<span style=\"font-size: 10pt\"><span style=\"font-size: 40pt\">Blah<img src=\"blah\"></img>Foo</span></span>"; + setHtml(html); + + int fragmentCount = 0; + + QTextBlock block = doc->begin(); + for (QTextBlock::Iterator it = block.begin(); + !it.atEnd(); ++it, ++fragmentCount) { + + const QTextFragment fragment = it.fragment(); + if (fragmentCount == 0) { + QCOMPARE(fragment.text(), QString("Blah")); + QCOMPARE(fragment.charFormat().fontPointSize(), qreal(40)); + } else if (fragmentCount == 1) { + QCOMPARE(fragment.text(), QString(QChar::ObjectReplacementCharacter)); + } else if (fragmentCount == 2) { + QCOMPARE(fragment.text(), QString("Foo")); + QCOMPARE(fragment.charFormat().fontPointSize(), qreal(40)); + } + } + + QCOMPARE(fragmentCount, 3); +} + +void tst_QTextDocumentFragment::html_emptyDocument() +{ + const char html[] = "<html><body><p style=\"-qt-paragraph-type:empty;\"></p></body></html>"; + setHtml(html); + QCOMPARE(doc->blockCount(), 1); +} + +void tst_QTextDocumentFragment::html_closingTag() +{ + const char html[] = "<i />text"; + setHtml(html); + + QVERIFY(!cursor.charFormat().fontItalic()); +} + +void tst_QTextDocumentFragment::html_anchorAroundImage() +{ + const char html[] = "<a href=\"http://www.troll.no\"><img src=test.png></a>"; + setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QTextImageFormat fmt = cursor.charFormat().toImageFormat(); + QCOMPARE(fmt.name(), QString("test.png")); + QVERIFY(fmt.isAnchor()); + QCOMPARE(fmt.anchorHref(), QString("http://www.troll.no")); +} + +void tst_QTextDocumentFragment::html_floatBorder() +{ + const char html[] = "<table border=1.2><tr><td>Foo"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + QCOMPARE(cursor.currentTable()->format().border(), qreal(1.2)); +} + +void tst_QTextDocumentFragment::html_frameImport() +{ + QTextFrameFormat ffmt; + ffmt.setBorder(1); + ffmt.setPosition(QTextFrameFormat::FloatRight); + ffmt.setMargin(2); + ffmt.setWidth(100); + ffmt.setHeight(50); + ffmt.setBackground(QColor("#00ff00")); + cursor.insertFrame(ffmt); + cursor.insertText("Hello World"); + + QTextDocumentFragment frag(doc); + cleanup(); + init(); + frag = QTextDocumentFragment::fromHtml(frag.toHtml()); + cursor.insertFragment(frag); + + QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); + QVERIFY(childFrames.count() == 1); + QTextFrame *frame = childFrames.first(); + QCOMPARE(frame->frameFormat().margin(), ffmt.margin()); + QCOMPARE(frame->frameFormat().border(), ffmt.border()); +} + +void tst_QTextDocumentFragment::html_frameImport2() +{ + QTextFrameFormat ffmt; + ffmt.setBorder(1); + ffmt.setPosition(QTextFrameFormat::FloatRight); + ffmt.setLeftMargin(200); + ffmt.setTopMargin(100); + ffmt.setBottomMargin(50); + ffmt.setRightMargin(250); + ffmt.setWidth(100); + ffmt.setHeight(50); + ffmt.setBackground(QColor("#00ff00")); + cursor.insertFrame(ffmt); + cursor.insertText("Hello World"); + + QTextDocumentFragment frag(doc); + cleanup(); + init(); + frag = QTextDocumentFragment::fromHtml(frag.toHtml()); + cursor.insertFragment(frag); + + QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); + QVERIFY(childFrames.count() == 1); + QTextFrame *frame = childFrames.first(); + QCOMPARE(frame->frameFormat().topMargin(), ffmt.topMargin()); + QCOMPARE(frame->frameFormat().bottomMargin(), ffmt.bottomMargin()); + QCOMPARE(frame->frameFormat().leftMargin(), ffmt.leftMargin()); + QCOMPARE(frame->frameFormat().rightMargin(), ffmt.rightMargin()); + QCOMPARE(frame->frameFormat().border(), ffmt.border()); +} + +void tst_QTextDocumentFragment::html_dontAddMarginsAcrossTableCells() +{ + const char html[] = "<table style=\"margin-left: 100px;\"><tr><td><p style=\"margin-left:50px;\">Foo</p></td></tr></table>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + + QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); + QVERIFY(childFrames.count() == 1); + QTextFrame *frame = childFrames.first(); + cursor = frame->firstCursorPosition(); + QCOMPARE(cursor.blockFormat().leftMargin(), qreal(50.0)); +} + +void tst_QTextDocumentFragment::html_dontMergeCenterBlocks() +{ + const char html[] = "<center>This should be centered</center>And this should not be centered anymore"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + + QCOMPARE(doc->blockCount(), 2); + QTextBlock blk = doc->begin(); + QVERIFY(blk.blockFormat().alignment() == Qt::AlignCenter); + blk = blk.next(); + QVERIFY(blk.blockFormat().alignment() != Qt::AlignCenter); +} + +void tst_QTextDocumentFragment::html_tableCellBgColor() +{ + const char html[] = "<table><tr><td bgcolor=\"blue\">Test<p>Second Parag</p></td></tr></table>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QVERIFY(cell.format().background().color() == Qt::blue); +} + +void tst_QTextDocumentFragment::html_tableCellBgColor2() +{ + const char html[] = "<table><tr><td bgcolor=\"blue\"><table><tr><td>Blah</td></tr></table></td></tr></table>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QVERIFY(cell.format().background().color() == Qt::blue); + + QTextFrame::Iterator it = cell.begin(); + QVERIFY(!it.atEnd()); + QVERIFY(it.currentFrame() == 0); + QVERIFY(it.currentBlock().isValid()); + + ++it; + QVERIFY(!it.atEnd()); + QVERIFY(it.currentFrame() != 0); + QVERIFY(!it.currentBlock().isValid()); + + ++it; + QVERIFY(!it.atEnd()); + QVERIFY(it.currentFrame() == 0); + QVERIFY(it.currentBlock().isValid()); + QVERIFY(it.currentBlock().blockFormat().background() == QBrush(Qt::NoBrush)); + + ++it; + QVERIFY(it.atEnd()); +} + +void tst_QTextDocumentFragment::html_cellSkip() +{ + const char html[] = "" +"<table border>" +" <tr>" +" <td>First Cell</td>" +" </tr>" +" <tr>" +" <td>Second Cell</td>" +" <td>Third Cell</td>" +" </tr>" +"</table>"; + + setHtml(html); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QVERIFY(table->columns() == 2 && table->rows() == 2); + + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell")); + QVERIFY(table->cellAt(0, 1).firstCursorPosition().block().text().isEmpty()); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell")); + QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Third Cell")); +} + +void tst_QTextDocumentFragment::nonZeroMarginOnImport() +{ + // specify bgcolor so that the html import creates a root frame format + setHtml("<html><body bgcolor=\"#00ff00\"><b>Hello World</b></body></html>"); + QVERIFY(doc->rootFrame()->frameFormat().margin() > 0.0); +} + +void tst_QTextDocumentFragment::html_charFormatPropertiesUnset() +{ + setHtml("Hello World"); + QVERIFY(doc->begin().begin().fragment().charFormat().properties().isEmpty()); +} + +void tst_QTextDocumentFragment::html_headings() +{ + setHtml("<h1>foo</h1>bar"); + QCOMPARE(doc->blockCount(), 2); +} + +void tst_QTextDocumentFragment::html_quotedFontFamily() +{ + setHtml("<div style=\"font-family: 'Foo Bar';\">Test</div>"); + QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar")); + + setHtml("<div style='font-family: \"Foo Bar\";'>Test</div>"); + QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar")); + + setHtml("<div style='font-family: \"Foo Bar\";'>Test</div>"); + QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar")); + + setHtml("<div style='font-family: Foo\n Bar;'>Test</div>"); + QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar")); + + setHtml("<div style='font-family: Foo\n Bar, serif, \"bar foo\";'>Test</div>"); + QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), QString("Foo Bar,serif,bar foo")); + +} + +void tst_QTextDocumentFragment::defaultFont() +{ + QFont f; + f.setFamily("Courier New"); + f.setBold(true); + f.setItalic(true); + f.setStrikeOut(true); // set here but deliberately ignored for the html export + f.setPointSize(100); + doc->setDefaultFont(f); + doc->setPlainText("Hello World"); + const QString html = doc->toHtml(); + QLatin1String str("<body style=\" font-family:'Courier New'; font-size:100pt; font-weight:600; font-style:italic;\">"); + QVERIFY(html.contains(str)); +} + +void tst_QTextDocumentFragment::html_spanBackgroundColor() +{ + setHtml("<span style=\"background-color: blue\">Foo</span>"); + QVERIFY(doc->begin().begin().fragment().charFormat().background().color() == QColor(Qt::blue)); +} + +void tst_QTextDocumentFragment::html_brokenTitle_data() +{ + QTest::addColumn<QString>("html"); + QTest::addColumn<QString>("expectedBody"); + QTest::addColumn<QString>("expectedTitle"); + + QTest::newRow("brokentitle") << QString("<html><head><title>Foo<b>bar</b></title></head><body>Blah</body></html>") + << QString("Blah") << QString("Foo"); + QTest::newRow("brokentitle2") << QString("<html><head><title>Foo<font color=red>i</font>t<font color=red>i</font>Blub</title></head><body>Blah</body></html>") + << QString("Blah") << QString("Foo"); + QTest::newRow("entities") << QString("<html><head><title>Foo<bar</title></head><body>Blah</body></html>") + << QString("Blah") << QString("Foo<bar"); + QTest::newRow("unclosedtitle") << QString("<html><head><title>Foo</head><body>Blah</body></html>") + << QString("Blah") << QString("Foo"); +} + +void tst_QTextDocumentFragment::html_brokenTitle() +{ + QFETCH(QString, html); + QFETCH(QString, expectedBody); + QFETCH(QString, expectedTitle); + doc->setHtml(html); + QCOMPARE(doc->toPlainText(), expectedBody); + QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), expectedTitle); +} + +void tst_QTextDocumentFragment::html_blockVsInline() +{ + { + setHtml("<html><body><div><b>Foo<div>Bar"); + QVERIFY(cursor.charFormat().fontWeight() == QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() == QFont::Bold); + } + { + setHtml("<html><body><p><b>Foo<p>Bar"); + QVERIFY(cursor.charFormat().fontWeight() != QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() != QFont::Bold); + } + { + setHtml("<html><body><b><center>Foo</center></b>"); + QVERIFY(cursor.charFormat().fontWeight() == QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() == QFont::Bold); + } + { + setHtml("<html><body><b><p>Foo"); + QVERIFY(cursor.charFormat().fontWeight() == QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() == QFont::Bold); + } + { + setHtml("<html><body><b><p>Foo<p>Bar"); + QVERIFY(cursor.charFormat().fontWeight() == QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() == QFont::Bold); + } + { + setHtml("<div><b>Foo<div>Bar"); + QVERIFY(cursor.charFormat().fontWeight() == QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() == QFont::Bold); + } + { + setHtml("<p><b>Foo<p>Bar"); + QVERIFY(cursor.charFormat().fontWeight() != QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() != QFont::Bold); + } + { + setHtml("<b><center>Foo</center></b>"); + QVERIFY(cursor.charFormat().fontWeight() == QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() == QFont::Bold); + } + { + setHtml("<b><p>Foo"); + QVERIFY(cursor.charFormat().fontWeight() == QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() == QFont::Bold); + } + { + setHtml("<b><p>Foo<p>Bar"); + QVERIFY(cursor.charFormat().fontWeight() == QFont::Bold); + QVERIFY(cursor.blockCharFormat().fontWeight() == QFont::Bold); + } +} + +void tst_QTextDocumentFragment::html_tbody() +{ + setHtml("<table><thead><tr><td>First Cell</td></tr></thead><tbody><tr><td>Second Cell</td></tr></tbody></table>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->format().headerRowCount(), 1); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell")); +} + +void tst_QTextDocumentFragment::html_nestedTables() +{ + setHtml("<table>" + " <tr><td>" + "" + " <table>" + " <tr><td>Hello</td></tr>" + " </table>" + "" + " <table>" + " <tr><td>World</td></tr>" + " </table>" + "" + " </td></tr>" + "</table>" + ); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 1); + + cursor = table->cellAt(0, 0).firstCursorPosition(); + cursor.movePosition(QTextCursor::NextBlock); + + QTextTable *firstNestedTable = cursor.currentTable(); + QVERIFY(firstNestedTable); + QVERIFY(firstNestedTable->parentFrame() == table); + QCOMPARE(firstNestedTable->rows(), 1); + QCOMPARE(firstNestedTable->columns(), 1); + QCOMPARE(firstNestedTable->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hello")); + + while (cursor.currentTable() == firstNestedTable + && cursor.movePosition(QTextCursor::NextBlock)) + ; + + QVERIFY(!cursor.isNull()); + QVERIFY(cursor.currentTable() == table); + + cursor.movePosition(QTextCursor::NextBlock); + + QTextTable *secondNestedTable = cursor.currentTable(); + QVERIFY(secondNestedTable); + QVERIFY(secondNestedTable->parentFrame() == table); + QCOMPARE(secondNestedTable->rows(), 1); + QCOMPARE(secondNestedTable->columns(), 1); + QCOMPARE(secondNestedTable->cellAt(0, 0).firstCursorPosition().block().text(), QString("World")); +} + +void tst_QTextDocumentFragment::html_rowSpans() +{ + setHtml("" + "<table border=\"1\" width=\"100%\">" + " <tr>" + " <td rowspan=\"2\">blah</td>" + " <td rowspan=\"2\">foo</td>" + " </tr>" + " <tr></tr>" + " <tr>" + " <td rowspan=\"2\">blubb</td>" + " <td rowspan=\"2\">baz</td>" + " </tr>" + " <tr></tr>" + "</table>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 4); + QCOMPARE(table->columns(), 2); + + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("blah")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("foo")); + + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("blah")); + QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("foo")); + + QCOMPARE(table->cellAt(2, 0).firstCursorPosition().block().text(), QString("blubb")); + QCOMPARE(table->cellAt(2, 1).firstCursorPosition().block().text(), QString("baz")); + + QCOMPARE(table->cellAt(3, 0).firstCursorPosition().block().text(), QString("blubb")); + QCOMPARE(table->cellAt(3, 1).firstCursorPosition().block().text(), QString("baz")); +} + +void tst_QTextDocumentFragment::html_rowSpans2() +{ + setHtml("" + "<html><body>" + "<table border=\"1\">" + "<tr>" + "<td>Row 1 col 1</td>" + "</tr>" + "<tr>" + "<td rowspan=\"3\">Row 2 col 1, rowspan 3</td>" + "<td>Row 2 col 2</td>" + "</tr>" + "<tr>" + "<td rowspan=\"2\">Row 3 col 2, rowspan 2</td>" + "</tr>" + "<tr>" + "</tr>" + "</table>" + "</body></html>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 4); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 1).rowSpan(), 1); + QCOMPARE(table->cellAt(1, 0).rowSpan(), 3); + QCOMPARE(table->cellAt(2, 1).rowSpan(), 2); +} + +void tst_QTextDocumentFragment::html_implicitParagraphs() +{ + setHtml("<p>foo</p>bar"); + QCOMPARE(doc->blockCount(), 2); +} + +void tst_QTextDocumentFragment::html_missingCloseTag() +{ + setHtml("<font color=\"red\"><span style=\"color:blue\">blue</span></span> red</font>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground().color() == Qt::blue); + cursor.movePosition(QTextCursor::NextWord); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground().color() == Qt::red); +} + +void tst_QTextDocumentFragment::html_anchorColor() +{ + setHtml("<span style=\"color: red;\">Red</span>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground().color() == Qt::red); + + setHtml("<span style=\"color: red;\"><a href=\"http://www.kde.org/\">Blue</a></span>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground().color() == QApplication::palette().link().color()); + + setHtml("<span style=\"color: red;\"><a href=\"http://www.kde.org/\" style=\"color: yellow;\">Green</a></span>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().foreground().color() == Qt::yellow); +} + +void tst_QTextDocumentFragment::html_lastParagraphClosing() +{ + setHtml("<p>Foo<b>Bar</b>Baz"); + QCOMPARE(doc->blockCount(), 1); +} + +void tst_QTextDocumentFragment::html_tableHeaderBodyFootParent() +{ + // don't get confused by strange tags, keep tbody/thead/tfoot children of + // the table tag + setHtml("<table><col><col><col><tbody><tr><td>Hey</td></tr></tbody></table>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey")); + + setHtml("<table><col><col><col><thead><tr><td>Hey</td></tr></thead></table>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey")); + + setHtml("<table><col><col><col><tfoot><tr><td>Hey</td></tr></tfoot></table>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey")); +} + +void tst_QTextDocumentFragment::html_columnWidths() +{ + setHtml("<table>" + " <tr>" + " <td colspan=\"2\">Foo</td>" + " </tr>" + " <tr>" + " <td>Bar</td>" + " <td width=\"1%\">Baz</td>" + " </tr>" + "</table>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 2); + QTextTableFormat fmt = table->format(); + + const QVector<QTextLength> columnWidths = fmt.columnWidthConstraints(); + QCOMPARE(columnWidths.count(), 2); + QVERIFY(columnWidths.at(0).type() == QTextLength::VariableLength); + QVERIFY(columnWidths.at(1).type() == QTextLength::PercentageLength); + QVERIFY(columnWidths.at(1).rawValue() == 1); +} + +void tst_QTextDocumentFragment::css_fontWeight() +{ + setHtml("<p style=\"font-weight:bold\">blah</p>"); + QVERIFY(doc->begin().charFormat().fontWeight() == QFont::Bold); + setHtml("<p style=\"font-weight:600\">blah</p>"); + QVERIFY(doc->begin().charFormat().fontWeight() == QFont::Bold); + +} + +void tst_QTextDocumentFragment::css_float() +{ + setHtml("<img src=\"foo\" style=\"float: right\">"); + QTextCharFormat fmt = doc->begin().begin().fragment().charFormat(); + QVERIFY(fmt.isImageFormat()); + QTextObject *o = doc->objectForFormat(fmt); + QVERIFY(o); + QTextFormat f = o->format(); + QVERIFY(f.isFrameFormat()); + QVERIFY(f.toFrameFormat().position() == QTextFrameFormat::FloatRight); + + setHtml("<img src=\"foo\" align=right>"); + fmt = doc->begin().begin().fragment().charFormat(); + QVERIFY(fmt.isImageFormat()); + o = doc->objectForFormat(fmt); + QVERIFY(o); + f = o->format(); + QVERIFY(f.isFrameFormat()); + QVERIFY(f.toFrameFormat().position() == QTextFrameFormat::FloatRight); + + setHtml("<img src=\"foo\" align=left>"); + fmt = doc->begin().begin().fragment().charFormat(); + QVERIFY(fmt.isImageFormat()); + o = doc->objectForFormat(fmt); + QVERIFY(o); + f = o->format(); + QVERIFY(f.isFrameFormat()); + QVERIFY(f.toFrameFormat().position() == QTextFrameFormat::FloatLeft); +} + +void tst_QTextDocumentFragment::css_textIndent() +{ + setHtml("<p style=\"text-indent: 42px\">foo</p>"); + QTextBlockFormat fmt = doc->begin().blockFormat(); + QCOMPARE(fmt.textIndent(), qreal(42)); +} + +void tst_QTextDocumentFragment::css_inline() +{ + setHtml("" + "<style>" + " p { background-color: green;}" + "</style>" + "<p>test</p>" + ); + QTextBlockFormat fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); +} + +void tst_QTextDocumentFragment::css_external() +{ + doc->addResource(QTextDocument::StyleSheetResource, QUrl("test.css"), QString("p { background-color: green; }")); + doc->setHtml("" + "<link href=\"test.css\" type=\"text/css\" />" + "<p>test</p>" + ); + QTextBlockFormat fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); +} + +void tst_QTextDocumentFragment::css_import() +{ + doc->addResource(QTextDocument::StyleSheetResource, QUrl("test.css"), QString("@import \"other.css\";")); + doc->addResource(QTextDocument::StyleSheetResource, QUrl("other.css"), QString("@import url(\"other2.css\");")); + doc->addResource(QTextDocument::StyleSheetResource, QUrl("other2.css"), QString("p { background-color: green; }")); + doc->setHtml("" + "<link href=\"test.css\" type=\"text/css\" />" + "<p>test</p>" + ); + QTextBlockFormat fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); + + doc->setHtml("" + "<style>@import \"test.css\" screen;</style>" + "<p>test</p>" + ); + fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); +} + +void tst_QTextDocumentFragment::css_selectors_data() +{ + QTest::addColumn<bool>("match"); + QTest::addColumn<QString>("selector"); + QTest::addColumn<QString>("attributes"); + + QTest::newRow("plain") << true << QString() << QString(); + + QTest::newRow("class") << true << QString(".foo") << QString("class=foo"); + QTest::newRow("notclass") << false << QString(".foo") << QString("class=bar"); + + QTest::newRow("attrset") << true << QString("[justset]") << QString("justset"); + QTest::newRow("notattrset") << false << QString("[justset]") << QString("otherattribute"); + + QTest::newRow("attrmatch") << true << QString("[foo=bar]") << QString("foo=bar"); + QTest::newRow("noattrmatch") << false << QString("[foo=bar]") << QString("foo=xyz"); + + QTest::newRow("contains") << true << QString("[foo~=bar]") << QString("foo=\"baz bleh bar\""); + QTest::newRow("notcontains") << false << QString("[foo~=bar]") << QString("foo=\"test\""); + + QTest::newRow("beingswith") << true << QString("[foo|=bar]") << QString("foo=\"bar-bleh\""); + QTest::newRow("notbeingswith") << false << QString("[foo|=bar]") << QString("foo=\"bleh-bar\""); + + QTest::newRow("attr2") << true << QString("[bar=foo]") << QString("bleh=bar bar=foo"); +} + +void tst_QTextDocumentFragment::css_selectors() +{ + QFETCH(bool, match); + QFETCH(QString, selector); + QFETCH(QString, attributes); + + QString html = QString("" + "<style>" + " p { background-color: green }" + " p%1 { background-color: red }" + "</style>" + "<p %2>test</p>" + ).arg(selector).arg(attributes); + setHtml(html); + + QTextBlockFormat fmt = doc->begin().blockFormat(); + if (match) + QVERIFY(fmt.background().color() == QColor("red")); + else + QVERIFY(fmt.background().color() == QColor("green")); +} + +void tst_QTextDocumentFragment::css_nodeNameCaseInsensitivity() +{ + setHtml("<style>" + "P { background-color: green }" + "</style>" + "<p>test</p>"); + QTextBlockFormat fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); +} + +void tst_QTextDocumentFragment::css_textUnderlineStyle_data() +{ + QTest::addColumn<QString>("styleName"); + QTest::addColumn<int>("expectedStyle"); + + QTest::newRow("none") << QString("none") << int(QTextCharFormat::NoUnderline); + QTest::newRow("solid") << QString("solid") << int(QTextCharFormat::SingleUnderline); + QTest::newRow("dash") << QString("dashed") << int(QTextCharFormat::DashUnderline); + QTest::newRow("dot") << QString("dotted") << int(QTextCharFormat::DotLine); + QTest::newRow("dashdot") << QString("dot-dash") << int(QTextCharFormat::DashDotLine); + QTest::newRow("dashdotdot") << QString("dot-dot-dash") << int(QTextCharFormat::DashDotDotLine); + QTest::newRow("wave") << QString("wave") << int(QTextCharFormat::WaveUnderline); +} + +void tst_QTextDocumentFragment::css_textUnderlineStyle() +{ + QFETCH(QString, styleName); + QFETCH(int, expectedStyle); + + QString html = QString::fromLatin1("<span style=\"text-underline-style: %1\">Blah</span>").arg(styleName); + doc->setHtml(html); + + QTextFragment fragment = doc->begin().begin().fragment(); + QVERIFY(fragment.isValid()); + QCOMPARE(int(fragment.charFormat().underlineStyle()), expectedStyle); +} + +void tst_QTextDocumentFragment::css_textUnderlineStyleAndDecoration() +{ + doc->setHtml("<span style=\"text-decoration: overline; text-underline-style: solid\">Test</span>"); + + QTextFragment fragment = doc->begin().begin().fragment(); + QVERIFY(fragment.isValid()); + QVERIFY(fragment.charFormat().underlineStyle() == QTextCharFormat::SingleUnderline); + QVERIFY(fragment.charFormat().fontOverline()); + + doc->setHtml("<span style=\"text-underline-style: solid; text-decoration: overline\">Test</span>"); + + fragment = doc->begin().begin().fragment(); + QVERIFY(fragment.isValid()); + QVERIFY(fragment.charFormat().underlineStyle() == QTextCharFormat::SingleUnderline); + QVERIFY(fragment.charFormat().fontOverline()); +} + +void tst_QTextDocumentFragment::css_listStyleType() +{ + doc->setHtml("<ol style=\"list-style-type: disc\"><li>Blah</li></ol>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListDisc); + + doc->setHtml("<ul style=\"list-style-type: square\"><li>Blah</li></ul>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListSquare); + + doc->setHtml("<ul style=\"list-style-type: circle\"><li>Blah</li></ul>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListCircle); + + doc->setHtml("<ul style=\"list-style-type: decimal\"><li>Blah</li></ul>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListDecimal); + + doc->setHtml("<ul style=\"list-style-type: lower-alpha\"><li>Blah</li></ul>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListLowerAlpha); + + doc->setHtml("<ul style=\"list-style-type: upper-alpha\"><li>Blah</li></ul>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListUpperAlpha); + + doc->setHtml("<ul style=\"list-style-type: upper-roman\"><li>Blah</li></ul>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListUpperRoman); + + doc->setHtml("<ul style=\"list-style-type: lower-roman\"><li>Blah</li></ul>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListLowerRoman); + + // ignore the unsupported list-style-position inside the list-style shorthand property + doc->setHtml("<ul style=\"list-style: outside decimal\"><li>Blah</li></ul>"); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListDecimal); +} + +void tst_QTextDocumentFragment::css_linkPseudo() +{ + doc->setHtml("<a href=\"foobar\">Blah</a>"); + QVERIFY(doc->begin().begin().fragment().charFormat().fontUnderline()); + + doc->setHtml("<style>a { text-decoration: none; }</style><a href=\"foobar\">Blah</a>"); + QVERIFY(!doc->begin().begin().fragment().charFormat().fontUnderline()); + + doc->setHtml("<style>a:link { text-decoration: none; }</style><a href=\"foobar\">Blah</a>"); + QVERIFY(!doc->begin().begin().fragment().charFormat().fontUnderline()); +} + +void tst_QTextDocumentFragment::css_pageBreaks() +{ + doc->setHtml("<p>Foo</p>"); + QVERIFY(doc->begin().blockFormat().pageBreakPolicy() == QTextFormat::PageBreak_Auto); + + doc->setHtml("<p style=\" page-break-before:always;\">Foo</p>"); + QVERIFY(doc->begin().blockFormat().pageBreakPolicy() == QTextFormat::PageBreak_AlwaysBefore); + + doc->setHtml("<p style=\" page-break-after:always;\">Foo</p>"); + QVERIFY(doc->begin().blockFormat().pageBreakPolicy() == QTextFormat::PageBreak_AlwaysAfter); + + doc->setHtml("<p style=\" page-break-before:always; page-break-after:always;\">Foo</p>"); + QVERIFY(doc->begin().blockFormat().pageBreakPolicy() == (QTextFormat::PageBreak_AlwaysAfter | QTextFormat::PageBreak_AlwaysBefore)); +} + +void tst_QTextDocumentFragment::universalSelectors_data() +{ + QTest::addColumn<bool>("match"); + QTest::addColumn<QString>("selector"); + QTest::addColumn<QString>("attributes"); + + QTest::newRow("1") << true << QString("*") << QString(); + QTest::newRow("2") << false << QString() << QString(); // invalid totally empty selector + + QTest::newRow("3") << false << QString("*[foo=bar]") << QString("foo=bleh"); + QTest::newRow("4") << true << QString("*[foo=bar]") << QString("foo=bar"); + + QTest::newRow("5") << false << QString("[foo=bar]") << QString("foo=bleh"); + QTest::newRow("6") << true << QString("[foo=bar]") << QString("foo=bar"); + + QTest::newRow("7") << true << QString(".charfmt1") << QString("class=charfmt1"); +} + +void tst_QTextDocumentFragment::universalSelectors() +{ + QFETCH(bool, match); + QFETCH(QString, selector); + QFETCH(QString, attributes); + + QString html = QString("" + "<style>" + "%1 { background-color: green }" + "</style>" + "<p %2>test</p>" + ).arg(selector).arg(attributes); + + setHtml(html); + + QTextBlockFormat fmt = doc->begin().blockFormat(); + if (match) + QVERIFY(fmt.background().color() == QColor("green")); + else + QVERIFY(!fmt.hasProperty(QTextFormat::BackgroundBrush)); +} + +void tst_QTextDocumentFragment::screenMedia() +{ + setHtml("<style>" + "@media screen {" + "p { background-color: green }" + "}" + "</style>" + "<p>test</p>" + ""); + QTextBlockFormat fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); + + setHtml("<style>" + "@media foobar {" + "p { background-color: green }" + "}" + "</style>" + "<p>test</p>" + ""); + fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() != QColor("green")); + + setHtml("<style>" + "@media sCrEeN {" + "p { background-color: green }" + "}" + "</style>" + "<p>test</p>" + ""); + fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); +} + +void tst_QTextDocumentFragment::htmlResourceLoading() +{ + const QString html("<link href=\"test.css\" type=\"text/css\" />" + "<p>test</p>"); + + QTextDocument tmp; + tmp.addResource(QTextDocument::StyleSheetResource, QUrl("test.css"), QString("p { background-color: green; }")); + QTextDocumentFragment frag = QTextDocumentFragment::fromHtml(html, &tmp); + doc->clear(); + QTextCursor(doc).insertFragment(frag); + QTextBlockFormat fmt = doc->begin().blockFormat(); + QVERIFY(fmt.background().color() == QColor("green")); +} + +void tst_QTextDocumentFragment::someCaseInsensitiveAttributeValues() +{ + const char html1[] = "<ul type=sQUarE><li>Blah</li></ul>"; + setHtml(QString::fromLatin1(html1)); + cursor.movePosition(QTextCursor::End); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->format().style() == QTextListFormat::ListSquare); + + const char html2[] = "<div align=ceNTeR><b>Hello World"; + setHtml(html2); + + QCOMPARE(doc->begin().blockFormat().alignment(), Qt::AlignHCenter); + + const char html3[] = "<p dir=rTL><b>Hello World"; + setHtml(html3); + + QCOMPARE(doc->begin().blockFormat().layoutDirection(), Qt::RightToLeft); +} + +class TestDocument : public QTextDocument +{ +public: + inline TestDocument() {} + + QPixmap testPixmap; + + virtual QVariant loadResource(int type, const QUrl &name) { + if (name.toString() == QLatin1String("testPixmap")) { + return testPixmap; + } + return QTextDocument::loadResource(type, name); + } +}; + +void tst_QTextDocumentFragment::backgroundImage() +{ + TestDocument doc; + doc.testPixmap = QPixmap(100, 100); + doc.testPixmap.fill(Qt::blue); + doc.setHtml("<p style=\"background-image: url(testPixmap)\">Hello</p>"); + QBrush bg = doc.begin().blockFormat().background(); + QVERIFY(bg.style() == Qt::TexturePattern); + QVERIFY(bg.texture().serialNumber() == doc.testPixmap.serialNumber()); +} + +void tst_QTextDocumentFragment::dontMergePreAndNonPre() +{ + doc->setHtml("<pre>Pre text</pre>Text that should be wrapped"); + QCOMPARE(doc->blockCount(), 2); + QCOMPARE(doc->begin().text(), QString("Pre text")); + QCOMPARE(doc->begin().next().text(), QString("Text that should be wrapped")); +} + +void tst_QTextDocumentFragment::leftMarginInsideHtml() +{ + doc->setHtml("<html><dl><dd>Blah"); + QCOMPARE(doc->blockCount(), 1); + QVERIFY(doc->begin().blockFormat().leftMargin() > 0); +} + +void tst_QTextDocumentFragment::html_margins() +{ + doc->setHtml("<p style=\"margin-left: 42px\">Test"); + QCOMPARE(doc->blockCount(), 1); + QCOMPARE(doc->begin().blockFormat().topMargin(), 12.); + QCOMPARE(doc->begin().blockFormat().bottomMargin(), 12.); + QCOMPARE(doc->begin().blockFormat().leftMargin(), 42.); +} + +void tst_QTextDocumentFragment::newlineInsidePreShouldBecomeNewParagraph() +{ + // rationale: we used to map newlines inside <pre> to QChar::LineSeparator, but + // if you display a lot of text inside pre it all ended up inside one single paragraph, + // which doesn't scale very well with our text engine. Paragraphs spanning thousands of + // lines are not a common use-case otherwise. + + doc->setHtml("<pre>Foo\nBar</pre>"); + QCOMPARE(doc->blockCount(), 2); + QTextBlock block = doc->begin(); + QCOMPARE(block.blockFormat().topMargin(), qreal(12)); + QVERIFY(qIsNull(block.blockFormat().bottomMargin())); + + block = block.next(); + + QVERIFY(qIsNull(block.blockFormat().topMargin())); + QCOMPARE(block.blockFormat().bottomMargin(), qreal(12)); + + doc->setHtml("<pre style=\"margin-top: 32px; margin-bottom: 45px; margin-left: 50px\">Foo\nBar</pre>"); + QCOMPARE(doc->blockCount(), 2); + block = doc->begin(); + QCOMPARE(block.blockFormat().topMargin(), qreal(32)); + QVERIFY(qIsNull(block.blockFormat().bottomMargin())); + QCOMPARE(block.blockFormat().leftMargin(), qreal(50)); + + block = block.next(); + + QVERIFY(qIsNull(block.blockFormat().topMargin())); + QCOMPARE(block.blockFormat().bottomMargin(), qreal(45)); + QCOMPARE(block.blockFormat().leftMargin(), qreal(50)); + +} + +void tst_QTextDocumentFragment::invalidColspan() +{ + doc->setHtml("<table><tr rowspan=-1><td colspan=-1>Blah</td></tr></table>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->rows(), 1); +} + +void tst_QTextDocumentFragment::html_brokenTableWithJustTr() +{ + doc->setHtml("<tr><td>First Cell</td><tr><td>Second Cell"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell")); + + doc->setHtml("" + "<col width=286 style='mso-width-source:userset;mso-width-alt:10459;width:215pt'>" + "<col width=64 span=3 style='width:48pt'>" + "<tr height=17 style='height:12.75pt'>" + "<td height=17 width=286 style='height:12.75pt;width:215pt'>1a</td>" + "<td width=64 style='width:48pt'>1b</td>" + "<td width=64 style='width:48pt'>1c</td>" + "<td width=64 style='width:48pt'>1d</td>" + "</tr>" + "<tr height=17 style='height:12.75pt'>" + "<td height=17 style='height:12.75pt'>|2a</td>" + "<td>2b</td>" + "<td>2c</td>" + "<td>2d</td>" + "</tr>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 4); +} + +void tst_QTextDocumentFragment::html_brokenTableWithJustTd() +{ + doc->setHtml("<td>First Cell</td><td>Second Cell"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second Cell")); + + doc->setHtml("<td height=17 width=286 style='height:12.75pt;width:215pt'>1a</td>" + "<td width=64 style='width:48pt'>1b</td>" + "<td width=64 style='width:48pt'>1c</td>" + "<td width=64 style='width:48pt'>1d</td>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 4); +} + +void tst_QTextDocumentFragment::html_preNewlineHandling_data() +{ + QTest::addColumn<QString>("html"); + QTest::addColumn<QString>("expectedPlainText"); + + QTest::newRow("pre1") << QString("Foo<pre>Bar") + << QString("Foo\nBar"); + QTest::newRow("pre2") << QString("Foo<pre>\nBar") + << QString("Foo\nBar"); + QTest::newRow("pre2") << QString("Foo<pre>\n\nBar") + << QString("Foo\n\nBar"); + QTest::newRow("pre4") << QString("<html>Foo<pre>\nBar") + << QString("Foo\nBar"); + QTest::newRow("pre5") << QString("<pre>Foo\n</pre>\nBar") + << QString("Foo\nBar"); + QTest::newRow("pre6") << QString("<pre>Foo<b>Bar</b>Blah\n</pre>\nMooh") + << QString("FooBarBlah\nMooh"); + QTest::newRow("pre7") << QString("<pre>\nPara1\n</pre>\n<pre>\nPara2\n</pre>") + << QString("Para1\nPara2"); +} + +void tst_QTextDocumentFragment::html_preNewlineHandling() +{ + QFETCH(QString, html); + + doc->setHtml(html); + QTEST(doc->toPlainText(), "expectedPlainText"); +} + +void tst_QTextDocumentFragment::html_br() +{ + doc->setHtml("Foo<br><br><br>Blah"); + QCOMPARE(doc->toPlainText(), QString("Foo\n\n\nBlah")); +} + +void tst_QTextDocumentFragment::html_dl() +{ + doc->setHtml("<dl><dt>term<dd>data</dl>Text afterwards"); + QCOMPARE(doc->toPlainText(), QString("term\ndata\nText afterwards")); +} + +void tst_QTextDocumentFragment::html_tableStrangeNewline() +{ + doc->setHtml("<table><tr><td>Foo</td></tr>\n</table>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 1); + const QTextTableCell cell = table->cellAt(0, 0); + QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo")); + QVERIFY(cell.firstCursorPosition().block() == cell.lastCursorPosition().block()); +} + +void tst_QTextDocumentFragment::html_tableStrangeNewline2() +{ + doc->setHtml("<table><tr><td>Foo</td></tr><tr>\n<td/></tr></table>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 1); + const QTextTableCell cell = table->cellAt(0, 0); + QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo")); + QVERIFY(cell.firstCursorPosition().block() == cell.lastCursorPosition().block()); +} + +void tst_QTextDocumentFragment::html_tableStrangeNewline3() +{ + doc->setHtml("<table border>" + "<tr>" + "<td>" + "<ul>" + "<li>Meh</li>" + "</ul>" + "</td>" + "<td>\n" + "<ul>" + "<li>Foo</li>" + "</ul>" + "</td>" + "</tr>" + "</table>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 2); + + QTextTableCell cell = table->cellAt(0, 0); + QCOMPARE(cell.firstCursorPosition().block().text(), QString("Meh")); + QVERIFY(cell.firstCursorPosition().block() == cell.lastCursorPosition().block()); + + cell = table->cellAt(0, 1); + QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo")); + QVERIFY(cell.firstCursorPosition().block() == cell.lastCursorPosition().block()); +} + +void tst_QTextDocumentFragment::html_caption() +{ + doc->setHtml("<table border align=center>" + "<caption>This <b> is a</b> Caption!</caption>" + "<tr><td>Blah</td></tr>" + "</table>"); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + + QCOMPARE(cursor.block().text(), QString("This is a Caption!")); + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); + + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 1); + + QTextTableCell cell = table->cellAt(0, 0); + QCOMPARE(cell.firstCursorPosition().block().text(), QString("Blah")); +} + +static const uint windowsLatin1ExtendedCharacters[0xA0 - 0x80] = { + 0x20ac, // 0x80 + 0x0081, // 0x81 direct mapping + 0x201a, // 0x82 + 0x0192, // 0x83 + 0x201e, // 0x84 + 0x2026, // 0x85 + 0x2020, // 0x86 + 0x2021, // 0x87 + 0x02C6, // 0x88 + 0x2030, // 0x89 + 0x0160, // 0x8A + 0x2039, // 0x8B + 0x0152, // 0x8C + 0x008D, // 0x8D direct mapping + 0x017D, // 0x8E + 0x008F, // 0x8F directmapping + 0x0090, // 0x90 directmapping + 0x2018, // 0x91 + 0x2019, // 0x92 + 0x201C, // 0x93 + 0X201D, // 0x94 + 0x2022, // 0x95 + 0x2013, // 0x96 + 0x2014, // 0x97 + 0x02DC, // 0x98 + 0x2122, // 0x99 + 0x0161, // 0x9A + 0x203A, // 0x9B + 0x0153, // 0x9C + 0x009D, // 0x9D direct mapping + 0x017E, // 0x9E + 0x0178 // 0x9F +}; + +void tst_QTextDocumentFragment::html_windowsEntities() +{ + for (uint i = 0; i < sizeof(windowsLatin1ExtendedCharacters)/sizeof(windowsLatin1ExtendedCharacters[0]); ++i) { + QString html = QString::number(i + 0x80); + html.prepend("<p>&#"); + html.append(";"); + doc->setHtml(html); + QCOMPARE(doc->toPlainText(), QString(QChar(windowsLatin1ExtendedCharacters[i]))); + } +} + +void tst_QTextDocumentFragment::html_eatenText() +{ + doc->setHtml("<h1>Test1</h1>\nTest2<h1>Test3</h1>"); + cursor.movePosition(QTextCursor::Start); + QCOMPARE(cursor.block().text(), QString("Test1")); + cursor.movePosition(QTextCursor::NextBlock); + QCOMPARE(cursor.block().text(), QString("Test2")); + cursor.movePosition(QTextCursor::NextBlock); + QCOMPARE(cursor.block().text(), QString("Test3")); +} + +void tst_QTextDocumentFragment::html_hr() +{ + doc->setHtml("<hr />"); + QCOMPARE(doc->blockCount(), 1); + QVERIFY(doc->begin().blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)); +} + +void tst_QTextDocumentFragment::html_hrMargins() +{ + doc->setHtml("<p>Test<hr/>Blah"); + QCOMPARE(doc->blockCount(), 3); + + cursor.movePosition(QTextCursor::Start); + QTextBlock block = cursor.block(); + QCOMPARE(block.text(), QString("Test")); + QVERIFY(block.blockFormat().bottomMargin() <= qreal(12.)); + QTextBlock first = block; + + cursor.movePosition(QTextCursor::NextBlock); + block = cursor.block(); + QTextBlock hr = block; + QVERIFY(qMax(first.blockFormat().bottomMargin(), block.blockFormat().topMargin()) > 0); + + cursor.movePosition(QTextCursor::NextBlock); + block = cursor.block(); + + QCOMPARE(block.text(), QString("Blah")); +} + +void tst_QTextDocumentFragment::html_blockQuoteMargins() +{ + doc->setHtml("<blockquote>Bar</blockquote>"); + QCOMPARE(doc->blockCount(), 1); + cursor.movePosition(QTextCursor::Start); + QTextBlock block = cursor.block(); + QCOMPARE(block.text(), QString("Bar")); + QCOMPARE(block.blockFormat().leftMargin(), qreal(40.)); + QCOMPARE(block.blockFormat().rightMargin(), qreal(40.)); + QCOMPARE(block.blockFormat().topMargin(), qreal(12.)); + QCOMPARE(block.blockFormat().bottomMargin(), qreal(12.)); +} + +void tst_QTextDocumentFragment::html_definitionListMargins() +{ + doc->setHtml("Foo<dl><dt>tag<dd>data</dl>Bar"); + QCOMPARE(doc->blockCount(), 4); + + cursor.movePosition(QTextCursor::Start); + QTextBlock block = cursor.block(); + QCOMPARE(block.text(), QString("Foo")); + + block = block.next(); + QCOMPARE(block.text(), QString("tag")); + QCOMPARE(block.blockFormat().topMargin(), qreal(8.)); + + block = block.next(); + QCOMPARE(block.text(), QString("data")); + QCOMPARE(block.blockFormat().bottomMargin(), qreal(8.)); + + block = block.next(); + QCOMPARE(block.text(), QString("Bar")); +} + +void tst_QTextDocumentFragment::html_listMargins() +{ + doc->setHtml("Foo<ol><li>First<li>Second</ol>Bar"); + QCOMPARE(doc->blockCount(), 4); + + cursor.movePosition(QTextCursor::Start); + QTextBlock block = cursor.block(); + QCOMPARE(block.text(), QString("Foo")); + + block = block.next(); + QCOMPARE(block.text(), QString("First")); + QCOMPARE(block.blockFormat().topMargin(), qreal(12.)); + + block = block.next(); + QCOMPARE(block.text(), QString("Second")); + QCOMPARE(block.blockFormat().bottomMargin(), qreal(12.)); + + block = block.next(); + QCOMPARE(block.text(), QString("Bar")); +} + +void tst_QTextDocumentFragment::html_titleAttribute() +{ + doc->setHtml("<span title=\"this is my title\">Test</span>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QCOMPARE(cursor.charFormat().toolTip(), QString("this is my title")); +} + +void tst_QTextDocumentFragment::html_compressDivs() +{ + doc->setHtml("<p/><div/><div/><div/><div/>Test"); + QCOMPARE(doc->blockCount(), 1); + QCOMPARE(doc->begin().text(), QString("Test")); +} + +void tst_QTextDocumentFragment::completeToPlainText() +{ + doc->setPlainText("Hello\nWorld"); + QCOMPARE(doc->toPlainText(), QString("Hello\nWorld")); + QTextDocumentFragment fragment(doc); + QCOMPARE(fragment.toPlainText(), QString("Hello\nWorld")); +} + +void tst_QTextDocumentFragment::copyContents() +{ + doc->setPlainText("Hello"); + QFont f; + doc->setDefaultFont(f); + QTextFragment fragment = doc->begin().begin().fragment(); + QCOMPARE(fragment.text(), QString("Hello")); + QCOMPARE(fragment.charFormat().font().pointSize(), f.pointSize()); + + QTextDocumentFragment frag(doc); + doc->clear(); + f.setPointSize(48); + doc->setDefaultFont(f); + QTextCursor(doc).insertFragment(QTextDocumentFragment::fromHtml(frag.toHtml())); + fragment = doc->begin().begin().fragment(); + QCOMPARE(fragment.text(), QString("Hello")); + QCOMPARE(fragment.charFormat().font().pointSize(), f.pointSize()); +} + +void tst_QTextDocumentFragment::html_textAfterHr() +{ + doc->setHtml("<hr><nobr><b>After the centered text</b></nobr>"); + QCOMPARE(doc->blockCount(), 2); + QTextBlock block = doc->begin(); + QVERIFY(block.text().isEmpty()); + QVERIFY(block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)); + block = block.next(); + + QString txt("After the centered text"); + txt.replace(QLatin1Char(' '), QChar::Nbsp); + QCOMPARE(block.text(), txt); + QVERIFY(!block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)); +} + +void tst_QTextDocumentFragment::blockTagClosing() +{ + doc->setHtml("<p>foo<p>bar<span>baz</span>"); + QCOMPARE(doc->blockCount(), 2); + QTextBlock block = doc->begin(); + QCOMPARE(block.text(), QString("foo")); + block = block.next(); + QCOMPARE(block.text(), QString("barbaz")); +} + +void tst_QTextDocumentFragment::isEmpty() +{ + QTextDocumentFragment frag; + QVERIFY(frag.isEmpty()); + frag = QTextDocumentFragment::fromHtml("test"); + QVERIFY(!frag.isEmpty()); + frag = QTextDocumentFragment::fromHtml("<hr />"); + QVERIFY(!frag.isEmpty()); +} + +void tst_QTextDocumentFragment::html_alignmentInheritance() +{ + doc->setHtml("<center>Centered text<hr></center><b>After the centered text</b>"); + QCOMPARE(doc->blockCount(), 3); + QTextBlock block = doc->begin(); + QVERIFY(block.blockFormat().alignment() & Qt::AlignHCenter); + block = block.next(); + QVERIFY(block.blockFormat().alignment() & Qt::AlignHCenter); + block = block.next(); + QVERIFY(!(block.blockFormat().alignment() & Qt::AlignHCenter)); +} + +void tst_QTextDocumentFragment::html_ignoreEmptyDivs() +{ + doc->setHtml("<p><div/><b>Foo</b>"); + QCOMPARE(doc->blockCount(), 1); + QCOMPARE(doc->begin().text(), QString("Foo")); +} + +void tst_QTextDocumentFragment::html_dontInheritAlignmentForFloatingImages() +{ + doc->setHtml("<p align=right><img align=unknownignored src=\"foo\" /></p>"); + QTextCharFormat fmt = doc->begin().begin().fragment().charFormat(); + QVERIFY(fmt.isImageFormat()); + QTextObject *o = doc->objectForFormat(fmt); + QVERIFY(o); + QTextFormat f = o->format(); + QVERIFY(f.isFrameFormat()); + QVERIFY(f.toFrameFormat().position() == QTextFrameFormat::InFlow); +} + +void tst_QTextDocumentFragment::html_verticalImageAlignment() +{ + doc->setHtml("<img src=\"foo\"/>"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().isImageFormat()); + QTextImageFormat fmt = cursor.charFormat().toImageFormat(); + QVERIFY(fmt.verticalAlignment() == QTextCharFormat::AlignNormal); + + doc->setHtml("<img src=\"foo\" align=middle />"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().isImageFormat()); + fmt = cursor.charFormat().toImageFormat(); + QVERIFY(fmt.verticalAlignment() == QTextCharFormat::AlignMiddle); + + doc->setHtml("<img src=\"foo\" style=\"vertical-align: middle\" />"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().isImageFormat()); + fmt = cursor.charFormat().toImageFormat(); + QVERIFY(fmt.verticalAlignment() == QTextCharFormat::AlignMiddle); + + doc->setHtml("<img src=\"foo\" align=top />"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().isImageFormat()); + fmt = cursor.charFormat().toImageFormat(); + QVERIFY(fmt.verticalAlignment() == QTextCharFormat::AlignTop); + + doc->setHtml("<img src=\"foo\" style=\"vertical-align: top\" />"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().isImageFormat()); + fmt = cursor.charFormat().toImageFormat(); + QVERIFY(fmt.verticalAlignment() == QTextCharFormat::AlignTop); +} + +void tst_QTextDocumentFragment::html_verticalCellAlignment() +{ + const char *alt[] = + { + // vertical-align property + "<table>" + "<tr>" + "<td style=\"vertical-align: middle\"></td>" + "<td style=\"vertical-align: top\"></td>" + "<td style=\"vertical-align: bottom\"></td>" + "</tr>" + "</table>", + // valign property + "<table>" + "<tr>" + "<td valign=\"middle\"></td>" + "<td valign=\"top\"></td>" + "<td valign=\"bottom\"></td>" + "</tr>" + "</table>", + // test td override of tr property + "<table>" + "<tr valign=\"bottom\">" + "<td valign=\"middle\"></td>" + "<td valign=\"top\"></td>" + "<td></td>" + "</tr>" + "</table>" + }; + + const int numTestCases = sizeof(alt) / sizeof(*alt); + for (int i = 0; i < numTestCases; ++i) { + doc->setHtml(alt[i]); + + QTextTable *table = qobject_cast<QTextTable *>(doc->rootFrame()->childFrames().at(0)); + QVERIFY(table); + + QCOMPARE(table->cellAt(0, 0).format().verticalAlignment(), QTextCharFormat::AlignMiddle); + QCOMPARE(table->cellAt(0, 1).format().verticalAlignment(), QTextCharFormat::AlignTop); + QCOMPARE(table->cellAt(0, 2).format().verticalAlignment(), QTextCharFormat::AlignBottom); + } +} + +void tst_QTextDocumentFragment::html_borderColor() +{ + const char html[] = "<table border=1 style=\"border-color:#0000ff;\"><tr><td>Foo</td></tr></table>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + QCOMPARE(cursor.currentTable()->format().borderStyle(), QTextFrameFormat::BorderStyle_Outset); + QCOMPARE(cursor.currentTable()->format().borderBrush(), QBrush(QColor("#0000ff"))); +} + +void tst_QTextDocumentFragment::html_borderStyle() +{ + const char html[] = "<table border=1 style=\"border-style:solid;\"><tr><td>Foo</td></tr></table>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + QCOMPARE(cursor.currentTable()->format().borderStyle(), QTextFrameFormat::BorderStyle_Solid); + QCOMPARE(cursor.currentTable()->format().borderBrush(), QBrush(Qt::darkGray)); +} + +void tst_QTextDocumentFragment::html_borderWidth() +{ + const char *html[2] = { "<table style=\"border-width:2;\"><tr><td>Foo</td></tr></table>", + "<table style=\"border-width:2px;\"><tr><td>Foo</td></tr></table>" }; + + for (int i = 0; i < 2; ++i) { + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html[i]))); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentTable()); + QCOMPARE(cursor.currentTable()->format().border(), qreal(2)); + } +} + +void tst_QTextDocumentFragment::html_userState() +{ + const char html[] = "<p style=\"-qt-user-state:42;\">A</p><p style=\"-qt-user-state:0;\">B</p><p>C</p>"; + cursor.insertFragment(QTextDocumentFragment::fromHtml(QString::fromLatin1(html))); + QTextBlock block = doc->begin(); + QCOMPARE(block.userState(), 42); + QCOMPARE(block.next().userState(), 0); + QCOMPARE(block.next().next().userState(), -1); +} + +void tst_QTextDocumentFragment::html_rootFrameProperties() +{ + const char html[] = "<table border=1 style=\"-qt-table-type:root; margin-top:10px;\"><tr><td>Foo</tr></td>"; + doc->setHtml(html); + + QCOMPARE(doc->rootFrame()->childFrames().size(), 0); + + QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); + QCOMPARE(fmt.topMargin(), qreal(10)); + QCOMPARE(fmt.bottomMargin(), qreal(0)); + QCOMPARE(fmt.leftMargin(), qreal(0)); + QCOMPARE(fmt.rightMargin(), qreal(0)); + QCOMPARE(fmt.border(), qreal(1)); + + QString normalFrameHtml = QLatin1String(html); + normalFrameHtml.replace(QLatin1String("root"), QLatin1String("frame")); + + doc->setHtml(normalFrameHtml); + QCOMPARE(doc->rootFrame()->childFrames().size(), 1); +} + +void tst_QTextDocumentFragment::html_appendList() +{ + appendHtml("<p>foo</p>"); + appendHtml("<ul><li>Line 1</li><li>Line 2</li></ul>"); + + QCOMPARE(doc->blockCount(), 3); + QVERIFY(doc->begin().next().textList() != 0); +} + +void tst_QTextDocumentFragment::html_appendList2() +{ + appendHtml("1"); + appendHtml("<ul><li><img src=\"/foo/bar\" /></li></ul>"); + + QCOMPARE(doc->blockCount(), 2); + QVERIFY(doc->begin().next().textList() != 0); +} + +void tst_QTextDocumentFragment::html_alignmentPropertySet() +{ + const char html[] = "<p>Test</p>"; + setHtml(QString::fromLatin1(html)); + QVERIFY(!doc->begin().blockFormat().hasProperty(QTextFormat::BlockAlignment)); +} + +void tst_QTextDocumentFragment::html_qt3RichtextWhitespaceMode() +{ + setHtml(QString::fromLatin1("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><p> line with whitespace</p><p> another line with whitespace</p></body></html>")); + QCOMPARE(doc->blockCount(), 2); + + QTextBlock block = doc->begin(); + QVERIFY(block.text().startsWith(" ")); + + block = block.next(); + QVERIFY(block.text().startsWith(" ")); +} + +void tst_QTextDocumentFragment::html_brAfterHr() +{ + setHtml(QString::fromLatin1("Text A<br><hr><br>Text B<hr>")); + + QCOMPARE(doc->blockCount(), 4); + + QTextBlock block = doc->begin(); + QCOMPARE(block.text(), QString("Text A") + QChar(QChar::LineSeparator)); + + block = block.next(); + QVERIFY(block.text().isEmpty()); + + block = block.next(); + QCOMPARE(block.text(), QChar(QChar::LineSeparator) + QString("Text B")); + + block = block.next(); + QVERIFY(block.text().isEmpty()); +} + +void tst_QTextDocumentFragment::html_unclosedHead() +{ + doc->setHtml(QString::fromLatin1("<html><head><title>Test</title><body>Blah</body></html>")); + QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), QString::fromLatin1("Test")); + QCOMPARE(doc->toPlainText(), QString::fromLatin1("Blah")); +} + +// duplicated from qtexthtmlparser.cpp +#define MAX_ENTITY 258 +static const struct { const char *name; quint16 code; } entities[MAX_ENTITY]= { + { "AElig", 0x00c6 }, + { "Aacute", 0x00c1 }, + { "Acirc", 0x00c2 }, + { "Agrave", 0x00c0 }, + { "Alpha", 0x0391 }, + { "AMP", 38 }, + { "Aring", 0x00c5 }, + { "Atilde", 0x00c3 }, + { "Auml", 0x00c4 }, + { "Beta", 0x0392 }, + { "Ccedil", 0x00c7 }, + { "Chi", 0x03a7 }, + { "Dagger", 0x2021 }, + { "Delta", 0x0394 }, + { "ETH", 0x00d0 }, + { "Eacute", 0x00c9 }, + { "Ecirc", 0x00ca }, + { "Egrave", 0x00c8 }, + { "Epsilon", 0x0395 }, + { "Eta", 0x0397 }, + { "Euml", 0x00cb }, + { "Gamma", 0x0393 }, + { "GT", 62 }, + { "Iacute", 0x00cd }, + { "Icirc", 0x00ce }, + { "Igrave", 0x00cc }, + { "Iota", 0x0399 }, + { "Iuml", 0x00cf }, + { "Kappa", 0x039a }, + { "Lambda", 0x039b }, + { "LT", 60 }, + { "Mu", 0x039c }, + { "Ntilde", 0x00d1 }, + { "Nu", 0x039d }, + { "OElig", 0x0152 }, + { "Oacute", 0x00d3 }, + { "Ocirc", 0x00d4 }, + { "Ograve", 0x00d2 }, + { "Omega", 0x03a9 }, + { "Omicron", 0x039f }, + { "Oslash", 0x00d8 }, + { "Otilde", 0x00d5 }, + { "Ouml", 0x00d6 }, + { "Phi", 0x03a6 }, + { "Pi", 0x03a0 }, + { "Prime", 0x2033 }, + { "Psi", 0x03a8 }, + { "QUOT", 34 }, + { "Rho", 0x03a1 }, + { "Scaron", 0x0160 }, + { "Sigma", 0x03a3 }, + { "THORN", 0x00de }, + { "Tau", 0x03a4 }, + { "Theta", 0x0398 }, + { "Uacute", 0x00da }, + { "Ucirc", 0x00db }, + { "Ugrave", 0x00d9 }, + { "Upsilon", 0x03a5 }, + { "Uuml", 0x00dc }, + { "Xi", 0x039e }, + { "Yacute", 0x00dd }, + { "Yuml", 0x0178 }, + { "Zeta", 0x0396 }, + { "aacute", 0x00e1 }, + { "acirc", 0x00e2 }, + { "acute", 0x00b4 }, + { "aelig", 0x00e6 }, + { "agrave", 0x00e0 }, + { "alefsym", 0x2135 }, + { "alpha", 0x03b1 }, + { "amp", 38 }, + { "and", 0x22a5 }, + { "ang", 0x2220 }, + { "apos", 0x0027 }, + { "aring", 0x00e5 }, + { "asymp", 0x2248 }, + { "atilde", 0x00e3 }, + { "auml", 0x00e4 }, + { "bdquo", 0x201e }, + { "beta", 0x03b2 }, + { "brvbar", 0x00a6 }, + { "bull", 0x2022 }, + { "cap", 0x2229 }, + { "ccedil", 0x00e7 }, + { "cedil", 0x00b8 }, + { "cent", 0x00a2 }, + { "chi", 0x03c7 }, + { "circ", 0x02c6 }, + { "clubs", 0x2663 }, + { "cong", 0x2245 }, + { "copy", 0x00a9 }, + { "crarr", 0x21b5 }, + { "cup", 0x222a }, + { "curren", 0x00a4 }, + { "dArr", 0x21d3 }, + { "dagger", 0x2020 }, + { "darr", 0x2193 }, + { "deg", 0x00b0 }, + { "delta", 0x03b4 }, + { "diams", 0x2666 }, + { "divide", 0x00f7 }, + { "eacute", 0x00e9 }, + { "ecirc", 0x00ea }, + { "egrave", 0x00e8 }, + { "empty", 0x2205 }, + { "emsp", 0x2003 }, + { "ensp", 0x2002 }, + { "epsilon", 0x03b5 }, + { "equiv", 0x2261 }, + { "eta", 0x03b7 }, + { "eth", 0x00f0 }, + { "euml", 0x00eb }, + { "euro", 0x20ac }, + { "exist", 0x2203 }, + { "fnof", 0x0192 }, + { "forall", 0x2200 }, + { "frac12", 0x00bd }, + { "frac14", 0x00bc }, + { "frac34", 0x00be }, + { "frasl", 0x2044 }, + { "gamma", 0x03b3 }, + { "ge", 0x2265 }, + { "gt", 62 }, + { "hArr", 0x21d4 }, + { "harr", 0x2194 }, + { "hearts", 0x2665 }, + { "hellip", 0x2026 }, + { "iacute", 0x00ed }, + { "icirc", 0x00ee }, + { "iexcl", 0x00a1 }, + { "igrave", 0x00ec }, + { "image", 0x2111 }, + { "infin", 0x221e }, + { "int", 0x222b }, + { "iota", 0x03b9 }, + { "iquest", 0x00bf }, + { "isin", 0x2208 }, + { "iuml", 0x00ef }, + { "kappa", 0x03ba }, + { "lArr", 0x21d0 }, + { "lambda", 0x03bb }, + { "lang", 0x2329 }, + { "laquo", 0x00ab }, + { "larr", 0x2190 }, + { "lceil", 0x2308 }, + { "ldquo", 0x201c }, + { "le", 0x2264 }, + { "lfloor", 0x230a }, + { "lowast", 0x2217 }, + { "loz", 0x25ca }, + { "lrm", 0x200e }, + { "lsaquo", 0x2039 }, + { "lsquo", 0x2018 }, + { "lt", 60 }, + { "macr", 0x00af }, + { "mdash", 0x2014 }, + { "micro", 0x00b5 }, + { "middot", 0x00b7 }, + { "minus", 0x2212 }, + { "mu", 0x03bc }, + { "nabla", 0x2207 }, + { "nbsp", 0x00a0 }, + { "ndash", 0x2013 }, + { "ne", 0x2260 }, + { "ni", 0x220b }, + { "not", 0x00ac }, + { "notin", 0x2209 }, + { "nsub", 0x2284 }, + { "ntilde", 0x00f1 }, + { "nu", 0x03bd }, + { "oacute", 0x00f3 }, + { "ocirc", 0x00f4 }, + { "oelig", 0x0153 }, + { "ograve", 0x00f2 }, + { "oline", 0x203e }, + { "omega", 0x03c9 }, + { "omicron", 0x03bf }, + { "oplus", 0x2295 }, + { "or", 0x22a6 }, + { "ordf", 0x00aa }, + { "ordm", 0x00ba }, + { "oslash", 0x00f8 }, + { "otilde", 0x00f5 }, + { "otimes", 0x2297 }, + { "ouml", 0x00f6 }, + { "para", 0x00b6 }, + { "part", 0x2202 }, + { "percnt", 0x0025 }, + { "permil", 0x2030 }, + { "perp", 0x22a5 }, + { "phi", 0x03c6 }, + { "pi", 0x03c0 }, + { "piv", 0x03d6 }, + { "plusmn", 0x00b1 }, + { "pound", 0x00a3 }, + { "prime", 0x2032 }, + { "prod", 0x220f }, + { "prop", 0x221d }, + { "psi", 0x03c8 }, + { "quot", 34 }, + { "rArr", 0x21d2 }, + { "radic", 0x221a }, + { "rang", 0x232a }, + { "raquo", 0x00bb }, + { "rarr", 0x2192 }, + { "rceil", 0x2309 }, + { "rdquo", 0x201d }, + { "real", 0x211c }, + { "reg", 0x00ae }, + { "rfloor", 0x230b }, + { "rho", 0x03c1 }, + { "rlm", 0x200f }, + { "rsaquo", 0x203a }, + { "rsquo", 0x2019 }, + { "sbquo", 0x201a }, + { "scaron", 0x0161 }, + { "sdot", 0x22c5 }, + { "sect", 0x00a7 }, + { "shy", 0x00ad }, + { "sigma", 0x03c3 }, + { "sigmaf", 0x03c2 }, + { "sim", 0x223c }, + { "spades", 0x2660 }, + { "sub", 0x2282 }, + { "sube", 0x2286 }, + { "sum", 0x2211 }, + { "sup1", 0x00b9 }, + { "sup2", 0x00b2 }, + { "sup3", 0x00b3 }, + { "sup", 0x2283 }, + { "supe", 0x2287 }, + { "szlig", 0x00df }, + { "tau", 0x03c4 }, + { "there4", 0x2234 }, + { "theta", 0x03b8 }, + { "thetasym", 0x03d1 }, + { "thinsp", 0x2009 }, + { "thorn", 0x00fe }, + { "tilde", 0x02dc }, + { "times", 0x00d7 }, + { "trade", 0x2122 }, + { "uArr", 0x21d1 }, + { "uacute", 0x00fa }, + { "uarr", 0x2191 }, + { "ucirc", 0x00fb }, + { "ugrave", 0x00f9 }, + { "uml", 0x00a8 }, + { "upsih", 0x03d2 }, + { "upsilon", 0x03c5 }, + { "uuml", 0x00fc }, + { "weierp", 0x2118 }, + { "xi", 0x03be }, + { "yacute", 0x00fd }, + { "yen", 0x00a5 }, + { "yuml", 0x00ff }, + { "zeta", 0x03b6 }, + { "zwj", 0x200d }, + { "zwnj", 0x200c } +}; + +void tst_QTextDocumentFragment::html_entities_data() +{ + QTest::addColumn<QString>("html"); + QTest::addColumn<quint16>("code"); + + for (int i = 0; i < MAX_ENTITY; ++i) { + QTest::newRow(entities[i].name) << QString("<pre>&") + QString::fromLatin1(entities[i].name) + QString(";</pre>") + << entities[i].code; + } +} + +void tst_QTextDocumentFragment::html_entities() +{ + QFETCH(QString, html); + QFETCH(quint16, code); + + setHtml(html); + QCOMPARE(doc->blockCount(), 1); + QString txt = doc->begin().text(); + QCOMPARE(txt.length(), 1); + QCOMPARE(txt.at(0).unicode(), code); +} + +void tst_QTextDocumentFragment::html_ignore_script() +{ + doc->setHtml(QString::fromLatin1("<html><script>Test</script><body>Blah</body></html>")); + QCOMPARE(doc->toPlainText(), QString("Blah")); +} + +void tst_QTextDocumentFragment::html_directionWithHtml() +{ + doc->setHtml(QString::fromLatin1("<html><body><p>Test<p dir=rtl>RTL<p dir=ltr>LTR")); + QCOMPARE(doc->blockCount(), 3); + + QTextBlock block = doc->firstBlock(); + QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); + QVERIFY(block.blockFormat().layoutDirection() == Qt::LeftToRight); // HTML default + + block = block.next(); + QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); + QVERIFY(block.blockFormat().layoutDirection() == Qt::RightToLeft); + + block = block.next(); + QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); + QVERIFY(block.blockFormat().layoutDirection() == Qt::LeftToRight); +} + +void tst_QTextDocumentFragment::html_directionWithRichText() +{ + doc->setHtml(QString::fromLatin1("<p>Test<p dir=rtl>RTL<p dir=ltr>LTR")); + QCOMPARE(doc->blockCount(), 3); + + QTextBlock block = doc->firstBlock(); + QVERIFY(!block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); + + block = block.next(); + QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); + QVERIFY(block.blockFormat().layoutDirection() == Qt::RightToLeft); + + block = block.next(); + QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); + QVERIFY(block.blockFormat().layoutDirection() == Qt::LeftToRight); +} + +void tst_QTextDocumentFragment::html_metaInBody() +{ + setHtml("<body>Hello<meta>World</body>"); + QCOMPARE(doc->toPlainText(), QString("HelloWorld")); +} + +void tst_QTextDocumentFragment::html_importImageWithoutAspectRatio() +{ + doc->setHtml("<img src=\"foo\" width=\"100%\" height=\"43\">"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().isImageFormat()); + QTextImageFormat fmt = cursor.charFormat().toImageFormat(); + // qDebug() << fmt.width() << fmt.height(); + QVERIFY (fmt.hasProperty(QTextFormat::ImageWidth)); + QCOMPARE (fmt.height(), 43.); + + doc->setHtml("<img src=\"foo\" height=\"43\">"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().isImageFormat()); + fmt = cursor.charFormat().toImageFormat(); + QVERIFY (! fmt.hasProperty(QTextFormat::ImageWidth)); + QCOMPARE (fmt.height(), 43.); + + doc->setHtml("<img src=\"foo\" width=\"200\">"); + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextCharacter); + QVERIFY(cursor.charFormat().isImageFormat()); + fmt = cursor.charFormat().toImageFormat(); + QVERIFY (! fmt.hasProperty(QTextFormat::ImageHeight)); + QCOMPARE (fmt.width(), 200.); +} + +void tst_QTextDocumentFragment::html_fromFirefox() +{ + // if you have a html loaded in firefox like <html>Test\nText</html> then selecting all and copying will + // result in the following text on the clipboard (for text/html) + doc->setHtml(QString::fromLatin1("<!--StartFragment-->Test\nText\n\n<!--EndFragment-->")); + QCOMPARE(doc->toPlainText(), QString::fromLatin1("Test Text ")); +} + +QTEST_MAIN(tst_QTextDocumentFragment) +#include "tst_qtextdocumentfragment.moc" diff --git a/tests/auto/gui/text/qtextdocumentlayout/.gitignore b/tests/auto/gui/text/qtextdocumentlayout/.gitignore new file mode 100644 index 0000000000..80671c70d0 --- /dev/null +++ b/tests/auto/gui/text/qtextdocumentlayout/.gitignore @@ -0,0 +1 @@ +tst_qtextdocumentlayout diff --git a/tests/auto/gui/text/qtextdocumentlayout/qtextdocumentlayout.pro b/tests/auto/gui/text/qtextdocumentlayout/qtextdocumentlayout.pro new file mode 100644 index 0000000000..32b05ce061 --- /dev/null +++ b/tests/auto/gui/text/qtextdocumentlayout/qtextdocumentlayout.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qtextdocumentlayout.cpp + + diff --git a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp new file mode 100644 index 0000000000..f5c72cd4d0 --- /dev/null +++ b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qtextdocument.h> +#include <qabstracttextdocumentlayout.h> +#include <qdebug.h> +#include <qpainter.h> +#include <qtexttable.h> +#include <qtextedit.h> +#include <qscrollbar.h> + +//TESTED_CLASS= +//TESTED_FILES=gui/text/qtextdocumentlayout_p.h gui/text/qtextdocumentlayout.cpp + +class tst_QTextDocumentLayout : public QObject +{ + Q_OBJECT +public: + inline tst_QTextDocumentLayout() {} + virtual ~tst_QTextDocumentLayout() {} + +public slots: + void init(); + void cleanup(); + +private slots: + void defaultPageSizeHandling(); + void idealWidth(); + void lineSeparatorFollowingTable(); + void wrapAtWordBoundaryOrAnywhere(); + void inlineImage(); + void clippedTableCell(); + void floatingTablePageBreak(); + +private: + QTextDocument *doc; +}; + +void tst_QTextDocumentLayout::init() +{ + doc = new QTextDocument; +} + +void tst_QTextDocumentLayout::cleanup() +{ + delete doc; + doc = 0; +} + +void tst_QTextDocumentLayout::defaultPageSizeHandling() +{ + QAbstractTextDocumentLayout *layout = doc->documentLayout(); + QVERIFY(layout); + + QVERIFY(!doc->pageSize().isValid()); + QSizeF docSize = layout->documentSize(); + QVERIFY(docSize.width() > 0 && docSize.width() < 1000); + QVERIFY(docSize.height() > 0 && docSize.height() < 1000); + + doc->setPlainText("Some text\nwith a few lines\nand not real information\nor anything otherwise useful"); + + docSize = layout->documentSize(); + QVERIFY(docSize.isValid()); + QVERIFY(docSize.width() != INT_MAX); + QVERIFY(docSize.height() != INT_MAX); +} + +void tst_QTextDocumentLayout::idealWidth() +{ + doc->setPlainText("Some text\nwith a few lines\nand not real information\nor anything otherwise useful"); + doc->setTextWidth(1000); + QCOMPARE(doc->textWidth(), qreal(1000)); + QCOMPARE(doc->size().width(), doc->textWidth()); + QVERIFY(doc->idealWidth() < doc->textWidth()); + QVERIFY(doc->idealWidth() > 0); + + QTextBlockFormat fmt; + fmt.setAlignment(Qt::AlignRight | Qt::AlignAbsolute); + QTextCursor cursor(doc); + cursor.select(QTextCursor::Document); + cursor.mergeBlockFormat(fmt); + + QCOMPARE(doc->textWidth(), qreal(1000)); + QCOMPARE(doc->size().width(), doc->textWidth()); + QVERIFY(doc->idealWidth() < doc->textWidth()); + QVERIFY(doc->idealWidth() > 0); +} + +// none of the QTextLine items in the document should intersect with the margin rect +void tst_QTextDocumentLayout::lineSeparatorFollowingTable() +{ + QString html_begin("<html><table border=1><tr><th>Column 1</th></tr><tr><td>Data</td></tr></table><br>"); + QString html_text("bla bla bla bla bla bla bla bla<br>"); + QString html_end("<table border=1><tr><th>Column 1</th></tr><tr><td>Data</td></tr></table></html>"); + + QString html = html_begin; + + for (int i = 0; i < 80; ++i) + html += html_text; + + html += html_end; + + doc->setHtml(html); + + QTextCursor cursor(doc); + cursor.movePosition(QTextCursor::Start); + + const int margin = 87; + const int pageWidth = 873; + const int pageHeight = 1358; + + QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); + fmt.setMargin(margin); + doc->rootFrame()->setFrameFormat(fmt); + + QFont font(doc->defaultFont()); + font.setPointSize(10); + doc->setDefaultFont(font); + doc->setPageSize(QSizeF(pageWidth, pageHeight)); + + QRectF marginRect(QPointF(0, pageHeight - margin), QSizeF(pageWidth, 2 * margin)); + + // force layouting + doc->pageCount(); + + for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next()) { + QTextLayout *layout = block.layout(); + for (int i = 0; i < layout->lineCount(); ++i) { + QTextLine line = layout->lineAt(i); + QRectF rect = line.rect().translated(layout->position()); + QVERIFY(!rect.intersects(marginRect)); + } + } +} + +void tst_QTextDocumentLayout::wrapAtWordBoundaryOrAnywhere() +{ + //task 150562 + QTextEdit edit; + edit.setText("<table><tr><td>hello hello hello" + "thisisabigwordthisisabigwordthisisabigwordthisisabigwordthisisabigword" + "hello hello hello</td></tr></table>"); + edit.setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + edit.resize(100, 100); + edit.show(); + QVERIFY(!edit.horizontalScrollBar()->isVisible()); +} + +void tst_QTextDocumentLayout::inlineImage() +{ + doc->setPageSize(QSizeF(800, 500)); + + QImage img(400, 400, QImage::Format_RGB32); + QLatin1String name("bigImage"); + + doc->addResource(QTextDocument::ImageResource, QUrl(name), img); + + QTextImageFormat imgFormat; + imgFormat.setName(name); + imgFormat.setWidth(img.width()); + + QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); + qreal height = doc->pageSize().height() - fmt.topMargin() - fmt.bottomMargin(); + imgFormat.setHeight(height); + + QTextCursor cursor(doc); + cursor.insertImage(imgFormat); + + QCOMPARE(doc->pageCount(), 1); +} + +void tst_QTextDocumentLayout::clippedTableCell() +{ + const char *html = + "<table style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"" + "border=\"0\" margin=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td></td></tr></table>"; + + doc->setHtml(html); + doc->pageSize(); + + QTextCursor cursor(doc); + cursor.movePosition(QTextCursor::Right); + + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextCursor cellCursor = table->cellAt(0, 0).firstCursorPosition(); + QImage src(16, 16, QImage::Format_ARGB32_Premultiplied); + src.fill(0xffff0000); + cellCursor.insertImage(src); + + QTextBlock block = cellCursor.block(); + QRectF r = doc->documentLayout()->blockBoundingRect(block); + + QRectF rect(0, 0, r.left() + 1, 64); + + QImage img(64, 64, QImage::Format_ARGB32_Premultiplied); + img.fill(0x0); + QImage expected = img; + QPainter p(&img); + doc->drawContents(&p, rect); + p.end(); + p.begin(&expected); + r.setWidth(1); + p.fillRect(r, Qt::red); + p.end(); + + img.save("img.png"); + expected.save("expected.png"); + QCOMPARE(img, expected); +} + +void tst_QTextDocumentLayout::floatingTablePageBreak() +{ + doc->clear(); + + QTextCursor cursor(doc); + + QTextTableFormat tableFormat; + tableFormat.setPosition(QTextFrameFormat::FloatLeft); + QTextTable *table = cursor.insertTable(50, 1, tableFormat); + Q_UNUSED(table); + + // Make height of document 2/3 of the table, fitting the table into two pages + QSizeF documentSize = doc->size(); + documentSize.rheight() *= 2.0 / 3.0; + + doc->setPageSize(documentSize); + + QCOMPARE(doc->pageCount(), 2); +} + + +QTEST_MAIN(tst_QTextDocumentLayout) +#include "tst_qtextdocumentlayout.moc" diff --git a/tests/auto/gui/text/qtextformat/.gitignore b/tests/auto/gui/text/qtextformat/.gitignore new file mode 100644 index 0000000000..3e3be422fe --- /dev/null +++ b/tests/auto/gui/text/qtextformat/.gitignore @@ -0,0 +1 @@ +tst_qtextformat diff --git a/tests/auto/gui/text/qtextformat/qtextformat.pro b/tests/auto/gui/text/qtextformat/qtextformat.pro new file mode 100644 index 0000000000..30f6e50c61 --- /dev/null +++ b/tests/auto/gui/text/qtextformat/qtextformat.pro @@ -0,0 +1,9 @@ +############################################################ +# Project file for autotest for file qtextformat.h +############################################################ + +load(qttest_p4) + +SOURCES += tst_qtextformat.cpp + + diff --git a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp new file mode 100644 index 0000000000..b235b112b6 --- /dev/null +++ b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp @@ -0,0 +1,374 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qdebug.h> +#include <qsettings.h> +#include <qtextformat.h> +#include <qtextdocument.h> +#include <qtextcursor.h> +#include <qtextobject.h> +#include <qtextlayout.h> +#include <qabstracttextdocumentlayout.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QTextFormat : public QObject +{ +Q_OBJECT + +private slots: + void getSetCheck(); + void defaultAlignment(); + void testQTextCharFormat() const; + void testUnderlinePropertyPrecedence(); + void toFormat(); + void resolveFont(); + void getSetTabs(); + void testTabsUsed(); + void testFontStyleSetters(); +}; + +/*! \internal + This (used to) trigger a crash in: + + QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) + + which is most easily produced through QSettings. + */ +void tst_QTextFormat::testQTextCharFormat() const +{ + QSettings settings("test", "test"); + QTextCharFormat test; + + settings.value("test", test); +} + +// Testing get/set functions +void tst_QTextFormat::getSetCheck() +{ + QTextFormat obj1; + // int QTextFormat::objectIndex() + // void QTextFormat::setObjectIndex(int) + obj1.setObjectIndex(0); + QCOMPARE(0, obj1.objectIndex()); + obj1.setObjectIndex(INT_MIN); + QCOMPARE(INT_MIN, obj1.objectIndex()); + obj1.setObjectIndex(INT_MAX); + QCOMPARE(INT_MAX, obj1.objectIndex()); +} + +void tst_QTextFormat::defaultAlignment() +{ + QTextBlockFormat fmt; + QVERIFY(!fmt.hasProperty(QTextFormat::BlockAlignment)); + QCOMPARE(fmt.intProperty(QTextFormat::BlockAlignment), 0); + QVERIFY(fmt.alignment() == Qt::AlignLeft); +} + +void tst_QTextFormat::testUnderlinePropertyPrecedence() +{ + QTextCharFormat format; + // use normal accessors and check internal state + format.setUnderlineStyle(QTextCharFormat::NoUnderline); + QCOMPARE(format.property(QTextFormat::FontUnderline).isNull(), false); + QCOMPARE(format.property(QTextFormat::TextUnderlineStyle).isNull(), false); + QCOMPARE(format.property(QTextFormat::FontUnderline).toBool(), false); + QCOMPARE(format.property(QTextFormat::TextUnderlineStyle).toInt(), 0); + + format = QTextCharFormat(); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); + QCOMPARE(format.property(QTextFormat::FontUnderline).isNull(), false); + QCOMPARE(format.property(QTextFormat::TextUnderlineStyle).isNull(), false); + QCOMPARE(format.property(QTextFormat::FontUnderline).toBool(), true); + QCOMPARE(format.property(QTextFormat::TextUnderlineStyle).toInt(), 1); + + format = QTextCharFormat(); + format.setUnderlineStyle(QTextCharFormat::DotLine); + QCOMPARE(format.property(QTextFormat::FontUnderline).isNull(), false); + QCOMPARE(format.property(QTextFormat::TextUnderlineStyle).isNull(), false); + QCOMPARE(format.property(QTextFormat::FontUnderline).toBool(), false); + QVERIFY(format.property(QTextFormat::TextUnderlineStyle).toInt() > 0); + + // override accessors and use setProperty to create a false state. + // then check font() + format = QTextCharFormat(); + format.setProperty(QTextCharFormat::FontUnderline, true); + QCOMPARE(format.property(QTextFormat::FontUnderline).isNull(), false); + QCOMPARE(format.property(QTextFormat::TextUnderlineStyle).isNull(), true); + QCOMPARE(format.fontUnderline(), true); + QCOMPARE(format.font().underline(), true); + + format = QTextCharFormat(); + // create conflict. Should use the new property + format.setProperty(QTextCharFormat::TextUnderlineStyle, QTextCharFormat::SingleUnderline); + format.setProperty(QTextCharFormat::FontUnderline, false); + QCOMPARE(format.fontUnderline(), true); + QCOMPARE(format.font().underline(), true); + + format = QTextCharFormat(); + // create conflict. Should use the new property + format.setProperty(QTextCharFormat::TextUnderlineStyle, QTextCharFormat::NoUnderline); + format.setProperty(QTextCharFormat::FontUnderline, true); + QCOMPARE(format.fontUnderline(), false); + QCOMPARE(format.font().underline(), false); + + // do it again, but reverse the ordering (we use a QVector internally, so test a LOT ;) + // create conflict. Should use the new property + format.setProperty(QTextCharFormat::FontUnderline, false); + format.setProperty(QTextCharFormat::TextUnderlineStyle, QTextCharFormat::SingleUnderline); + QCOMPARE(format.fontUnderline(), true); + QCOMPARE(format.font().underline(), true); + + format = QTextCharFormat(); + // create conflict. Should use the new property + format.setProperty(QTextCharFormat::FontUnderline, true); + format.setProperty(QTextCharFormat::TextUnderlineStyle, QTextCharFormat::NoUnderline); + QCOMPARE(format.fontUnderline(), false); + QCOMPARE(format.font().underline(), false); +} + +void tst_QTextFormat::toFormat() +{ + { + QTextFormat fmt = QTextFrameFormat(); + QCOMPARE(fmt.toFrameFormat().type(), int(QTextFormat::FrameFormat)); + } + + { + QTextFormat fmt = QTextTableFormat(); + QCOMPARE(fmt.toTableFormat().type(), int(QTextFormat::FrameFormat)); + QCOMPARE(fmt.toTableFormat().objectType(), int(QTextFormat::TableObject)); + } + + { + QTextFormat fmt = QTextBlockFormat(); + QCOMPARE(fmt.toBlockFormat().type(), int(QTextFormat::BlockFormat)); + } + + { + QTextFormat fmt = QTextCharFormat(); + QCOMPARE(fmt.toCharFormat().type(), int(QTextFormat::CharFormat)); + } + + { + QTextFormat fmt = QTextListFormat(); + QCOMPARE(fmt.toListFormat().type(), int(QTextFormat::ListFormat)); + } +} + +void tst_QTextFormat::resolveFont() +{ + QTextDocument doc; + + QTextCharFormat fmt; + fmt.setProperty(QTextFormat::ForegroundBrush, Qt::blue); + fmt.setProperty(QTextFormat::FontItalic, true); + QTextCursor(&doc).insertText("Test", fmt); + + QVector<QTextFormat> formats = doc.allFormats(); + QCOMPARE(formats.count(), 3); + + QVERIFY(formats.at(2).type() == QTextFormat::CharFormat); + fmt = formats.at(2).toCharFormat(); + + QVERIFY(!fmt.font().underline()); + QVERIFY(fmt.hasProperty(QTextFormat::ForegroundBrush)); + + QFont f; + f.setUnderline(true); + doc.setDefaultFont(f); + formats = doc.allFormats(); + fmt = formats.at(2).toCharFormat(); + + QVERIFY(fmt.font().underline()); + QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); + + // verify that deleting a non-existent property does not affect the font resolving + + QVERIFY(!fmt.hasProperty(QTextFormat::BackgroundBrush)); + fmt.clearProperty(QTextFormat::BackgroundBrush); + QVERIFY(!fmt.hasProperty(QTextFormat::BackgroundBrush)); + + QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); + QVERIFY(fmt.font().underline()); + + // verify that deleting an existent but font _unrelated_ property does not affect the font resolving + + QVERIFY(fmt.hasProperty(QTextFormat::ForegroundBrush)); + fmt.clearProperty(QTextFormat::ForegroundBrush); + QVERIFY(!fmt.hasProperty(QTextFormat::ForegroundBrush)); + + QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); + QVERIFY(fmt.font().underline()); + + // verify that removing a font property _does_ clear the resolving + + QVERIFY(fmt.hasProperty(QTextFormat::FontItalic)); + fmt.clearProperty(QTextFormat::FontItalic); + QVERIFY(!fmt.hasProperty(QTextFormat::FontItalic)); + + QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); + QVERIFY(!fmt.font().underline()); + QVERIFY(!fmt.font().italic()); + + // reset + fmt = formats.at(2).toCharFormat(); + + QVERIFY(fmt.font().underline()); + QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); + + // verify that _setting_ an unrelated property does _not_ affect the resolving + + QVERIFY(!fmt.hasProperty(QTextFormat::IsAnchor)); + fmt.setProperty(QTextFormat::IsAnchor, true); + QVERIFY(fmt.hasProperty(QTextFormat::IsAnchor)); + + QVERIFY(fmt.font().underline()); + QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); + + // verify that setting a _related_ font property does affect the resolving + // + QVERIFY(!fmt.hasProperty(QTextFormat::FontStrikeOut)); + fmt.setProperty(QTextFormat::FontStrikeOut, true); + QVERIFY(fmt.hasProperty(QTextFormat::FontStrikeOut)); + + QVERIFY(!fmt.font().underline()); + QVERIFY(!fmt.hasProperty(QTextFormat::FontUnderline)); + QVERIFY(fmt.font().strikeOut()); +} + +void tst_QTextFormat::getSetTabs() +{ + class Comparator { + public: + Comparator(const QList<QTextOption::Tab> &tabs, const QList<QTextOption::Tab> &tabs2) + { + QCOMPARE(tabs.count(), tabs2.count()); + for(int i=0; i < tabs.count(); i++) { + QTextOption::Tab t1 = tabs[i]; + QTextOption::Tab t2 = tabs2[i]; + QCOMPARE(t1.position, t2.position); + QCOMPARE(t1.type, t2.type); + QCOMPARE(t1.delimiter, t2.delimiter); + } + } + }; + + QList<QTextOption::Tab> tabs; + QTextBlockFormat format; + format.setTabPositions(tabs); + Comparator c1(tabs, format.tabPositions()); + + QTextOption::Tab tab1; + tab1.position = 1234; + tabs.append(tab1); + format.setTabPositions(tabs); + Comparator c2(tabs, format.tabPositions()); + + QTextOption::Tab tab2(3456, QTextOption::RightTab, QChar('x')); + tabs.append(tab2); + format.setTabPositions(tabs); + Comparator c3(tabs, format.tabPositions()); +} + +void tst_QTextFormat::testTabsUsed() +{ + QTextDocument doc; + QTextCursor cursor(&doc); + + QList<QTextOption::Tab> tabs; + QTextBlockFormat format; + QTextOption::Tab tab; + tab.position = 100; + tabs.append(tab); + format.setTabPositions(tabs); + cursor.mergeBlockFormat(format); + cursor.insertText("foo\tbar"); + //doc.setPageSize(QSizeF(200, 200)); + doc.documentLayout()->pageCount(); // force layout; + + QTextBlock block = doc.begin(); + QTextLayout *layout = block.layout(); + QVERIFY(layout); + QCOMPARE(layout->lineCount(), 1); + QTextLine line = layout->lineAt(0); + QCOMPARE(line.cursorToX(4), 100.); + + QTextOption option = layout->textOption(); + QCOMPARE(option.tabs().count(), tabs.count()); + +} + +void tst_QTextFormat::testFontStyleSetters() +{ + QTextCharFormat format; + + // test the setters + format.setFontStyleHint(QFont::Serif); + QCOMPARE(format.font().styleHint(), QFont::Serif); + QCOMPARE(format.font().styleStrategy(), QFont::PreferDefault); + format.setFontStyleStrategy(QFont::PreferOutline); + QCOMPARE(format.font().styleStrategy(), QFont::PreferOutline); + + // test setting properties through setFont() + QFont font; + font.setStyleHint(QFont::SansSerif, QFont::PreferAntialias); + format.setFont(font); + QCOMPARE(format.font().styleHint(), QFont::SansSerif); + QCOMPARE(format.font().styleStrategy(), QFont::PreferAntialias); + + // test kerning + format.setFontKerning(false); + QCOMPARE(format.font().kerning(), false); + format.setFontKerning(true); + QCOMPARE(format.font().kerning(), true); + font.setKerning(false); + format.setFont(font); + QCOMPARE(format.font().kerning(), false); +} + +QTEST_MAIN(tst_QTextFormat) +#include "tst_qtextformat.moc" diff --git a/tests/auto/gui/text/qtextlayout/.gitignore b/tests/auto/gui/text/qtextlayout/.gitignore new file mode 100644 index 0000000000..11758969db --- /dev/null +++ b/tests/auto/gui/text/qtextlayout/.gitignore @@ -0,0 +1 @@ +tst_qtextlayout diff --git a/tests/auto/gui/text/qtextlayout/qtextlayout.pro b/tests/auto/gui/text/qtextlayout/qtextlayout.pro new file mode 100644 index 0000000000..6bf0065e4f --- /dev/null +++ b/tests/auto/gui/text/qtextlayout/qtextlayout.pro @@ -0,0 +1,12 @@ +load(qttest_p4) +QT += core-private gui-private +HEADERS += +SOURCES += tst_qtextlayout.cpp +DEFINES += QT_COMPILES_IN_HARFBUZZ +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src + +symbian { + TARGET.EPOCHEAPSIZE = 100000 20000000 +} + +qpa:contains(QT_CONFIG,qpa):CONFIG+=insignificant_test # QTBUG-20979 diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp new file mode 100644 index 0000000000..2414ab3e37 --- /dev/null +++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp @@ -0,0 +1,1506 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +/* + !!!!!! Warning !!!!! + Please don't save this file in emacs. It contains utf8 text sequences emacs will + silently convert to a series of question marks. + */ +#include <QtTest/QtTest> + + + +#include <private/qtextengine_p.h> +#include <qtextlayout.h> + +#include <qdebug.h> + + +#define TESTFONT_SIZE 12 + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QTextLayout : public QObject +{ + Q_OBJECT + +public: + tst_QTextLayout(); + virtual ~tst_QTextLayout(); + + +public slots: + void init(); + void cleanup(); +private slots: + void getSetCheck(); + void lineBreaking(); + void simpleBoundingRect(); + void threeLineBoundingRect(); + void boundingRectWithLongLineAndNoWrap(); + void forcedBreaks(); + void breakAny(); + void noWrap(); + void cursorToXForInlineObjects(); + void cursorToXForSetColumns(); + void defaultWordSeparators_data(); + void defaultWordSeparators(); + void cursorMovementFromInvalidPositions(); + void cursorMovementInsideSpaces(); + void charWordStopOnLineSeparator(); + void xToCursorAtEndOfLine(); + void boundingRectTopLeft(); + void charStopForSurrogatePairs(); + void tabStops(); + void integerOverflow(); + void testDefaultTabs(); + void testTabs(); + void testMultilineTab(); + void testRightTab(); + void testTabsInAlignedParag(); + void testCenteredTab(); + void testDelimiterTab(); + void testMultiTab(); + void testTabDPIScale(); + void tabsForRtl(); + void tabHeight(); + void capitalization_allUpperCase(); + void capitalization_allLowerCase(); + void capitalization_smallCaps(); + void capitalization_capitalize(); + void longText(); + void widthOfTabs(); + void columnWrapWithTabs(); + void boundingRectForUnsetLineWidth(); + void boundingRectForSetLineWidth(); + void glyphLessItems(); + + // QTextLine stuff + void setNumColumnsWrapAtWordBoundaryOrAnywhere(); + void setNumColumnsWordWrap(); + void smallTextLengthNoWrap(); + void smallTextLengthWordWrap(); + void smallTextLengthWrapAtWordBoundaryOrAnywhere(); + void testLineBreakingAllSpaces(); + void lineWidthFromBOM(); + void textWidthVsWIdth(); + void textWithSurrogates_qtbug15679(); + void textWidthWithStackedTextEngine(); + void textWidthWithLineSeparator(); + void cursorInLigatureWithMultipleLines(); + void xToCursorForLigatures(); + +private: + QFont testFont; +}; + +// Testing get/set functions +void tst_QTextLayout::getSetCheck() +{ + QString str("Bogus text"); + QTextLayout layout(str, testFont); + layout.beginLayout(); + QTextEngine *engine = layout.engine(); + QTextInlineObject obj1(0, engine); + // qreal QTextInlineObject::width() + // void QTextInlineObject::setWidth(qreal) + obj1.setWidth(0.0); + QCOMPARE(0.0, obj1.width()); + obj1.setWidth(1.2); + QVERIFY(1.0 < obj1.width()); + + // qreal QTextInlineObject::ascent() + // void QTextInlineObject::setAscent(qreal) + obj1.setAscent(0.0); + QCOMPARE(0.0, obj1.ascent()); + obj1.setAscent(1.2); + QVERIFY(1.0 < obj1.ascent()); + + // qreal QTextInlineObject::descent() + // void QTextInlineObject::setDescent(qreal) + obj1.setDescent(0.0); + QCOMPARE(0.0, obj1.descent()); + obj1.setDescent(1.2); + QVERIFY(1.0 < obj1.descent()); + + QTextLayout obj2; + // bool QTextLayout::cacheEnabled() + // void QTextLayout::setCacheEnabled(bool) + obj2.setCacheEnabled(false); + QCOMPARE(false, obj2.cacheEnabled()); + obj2.setCacheEnabled(true); + QCOMPARE(true, obj2.cacheEnabled()); +} + +QT_BEGIN_NAMESPACE +extern void qt_setQtEnableTestFont(bool value); +QT_END_NAMESPACE + +tst_QTextLayout::tst_QTextLayout() +{ + qt_setQtEnableTestFont(true); +} + +tst_QTextLayout::~tst_QTextLayout() +{ +} + +void tst_QTextLayout::init() +{ + testFont = QFont(); + testFont.setFamily("__Qt__Box__Engine__"); + testFont.setPixelSize(TESTFONT_SIZE); + testFont.setWeight(QFont::Normal); + QCOMPARE(QFontMetrics(testFont).width('a'), testFont.pixelSize()); +} + +void tst_QTextLayout::cleanup() +{ + testFont = QFont(); +} + + +void tst_QTextLayout::lineBreaking() +{ +#if defined(Q_WS_X11) + struct Breaks { + const char *utf8; + uchar breaks[32]; + }; + Breaks brks[] = { + { "11", { false, 0xff } }, + { "aa", { false, 0xff } }, + { "++", { false, 0xff } }, + { "--", { false, 0xff } }, + { "((", { false, 0xff } }, + { "))", { false, 0xff } }, + { "..", { false, 0xff } }, + { "\"\"", { false, 0xff } }, + { "$$", { false, 0xff } }, + { "!!", { false, 0xff } }, + { "??", { false, 0xff } }, + { ",,", { false, 0xff } }, + + { ")()", { true, false, 0xff } }, + { "?!?", { false, false, 0xff } }, + { ".,.", { false, false, 0xff } }, + { "+-+", { false, false, 0xff } }, + { "+=+", { false, false, 0xff } }, + { "+(+", { false, false, 0xff } }, + { "+)+", { false, false, 0xff } }, + + { "a b", { false, true, 0xff } }, + { "a(b", { false, false, 0xff } }, + { "a)b", { false, false, 0xff } }, + { "a-b", { false, true, 0xff } }, + { "a.b", { false, false, 0xff } }, + { "a+b", { false, false, 0xff } }, + { "a?b", { false, false, 0xff } }, + { "a!b", { false, false, 0xff } }, + { "a$b", { false, false, 0xff } }, + { "a,b", { false, false, 0xff } }, + { "a/b", { false, false, 0xff } }, + { "1/2", { false, false, 0xff } }, + { "./.", { false, false, 0xff } }, + { ",/,", { false, false, 0xff } }, + { "!/!", { false, false, 0xff } }, + { "\\/\\", { false, false, 0xff } }, + { "1 2", { false, true, 0xff } }, + { "1(2", { false, false, 0xff } }, + { "1)2", { false, false, 0xff } }, + { "1-2", { false, false, 0xff } }, + { "1.2", { false, false, 0xff } }, + { "1+2", { false, false, 0xff } }, + { "1?2", { false, true, 0xff } }, + { "1!2", { false, true, 0xff } }, + { "1$2", { false, false, 0xff } }, + { "1,2", { false, false, 0xff } }, + { "1/2", { false, false, 0xff } }, + { "\330\260\331\216\331\204\331\220\331\203\331\216", { false, false, false, false, false, 0xff } }, + { "\330\247\331\204\331\205 \330\247\331\204\331\205", { false, false, false, true, false, false, 0xff } }, + { "1#2", { false, false, 0xff } }, + { "!#!", { false, false, 0xff } }, + { 0, {} } + }; + Breaks *b = brks; + while (b->utf8) { + QString str = QString::fromUtf8(b->utf8); + QTextEngine engine(str, QFont()); + const HB_CharAttributes *attrs = engine.attributes(); + int i; + for (i = 0; i < (int)str.length() - 1; ++i) { + QVERIFY(b->breaks[i] != 0xff); + if ( (attrs[i].lineBreakType != HB_NoBreak) != (bool)b->breaks[i] ) { + qDebug("test case \"%s\" failed at char %d; break type: %d", b->utf8, i, attrs[i].lineBreakType); + QCOMPARE( (attrs[i].lineBreakType != HB_NoBreak), (bool)b->breaks[i] ); + } + } + QVERIFY(attrs[i].lineBreakType == HB_ForcedBreak); + QCOMPARE(b->breaks[i], (uchar)0xff); + ++b; + } +#else + QSKIP("This test can not be run on non-X11 platforms", SkipAll); +#endif +} + +void tst_QTextLayout::simpleBoundingRect() +{ + /* just check if boundingRect() gives sane values. The text is not broken. */ + + QString hello("hello world"); + + const int width = hello.length() * testFont.pixelSize(); + + QTextLayout layout(hello, testFont); + layout.beginLayout(); + + QTextLine line = layout.createLine(); + line.setLineWidth(width); + QCOMPARE(line.textLength(), hello.length()); + QCOMPARE(layout.boundingRect(), QRectF(0, 0, width, QFontMetrics(testFont).height())); +} + +void tst_QTextLayout::threeLineBoundingRect() +{ +#if defined(Q_WS_MAC) + QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll); +#endif + /* stricter check. break text into three lines */ + + QString firstWord("hello"); + QString secondWord("world"); + QString thirdWord("test"); + QString text(firstWord + ' ' + secondWord + ' ' + thirdWord); + + const int firstLineWidth = firstWord.length() * testFont.pixelSize(); + const int secondLineWidth = secondWord.length() * testFont.pixelSize(); + const int thirdLineWidth = thirdWord.length() * testFont.pixelSize(); + + const int longestLine = qMax(firstLineWidth, qMax(secondLineWidth, thirdLineWidth)); + + QTextLayout layout(text, testFont); + layout.beginLayout(); + + int pos = 0; + int y = 0; + QTextLine line = layout.createLine(); + line.setLineWidth(firstLineWidth); + line.setPosition(QPoint(0, y)); + QCOMPARE(line.textStart(), pos); + // + 1 for trailing space + QCOMPARE(line.textLength(), firstWord.length() + 1); + QCOMPARE(qRound(line.naturalTextWidth()), firstLineWidth); + + pos += line.textLength(); + y += qRound(line.ascent() + line.descent()); + + line = layout.createLine(); + line.setLineWidth(secondLineWidth); + line.setPosition(QPoint(0, y)); + // + 1 for trailing space + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), secondWord.length() + 1); + QCOMPARE(qRound(line.naturalTextWidth()), secondLineWidth); + + pos += line.textLength(); + y += qRound(line.ascent() + line.descent()); + + line = layout.createLine(); + line.setLineWidth(secondLineWidth); + line.setPosition(QPoint(0, y)); + // no trailing space here! + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), thirdWord.length()); + QCOMPARE(qRound(line.naturalTextWidth()), thirdLineWidth); + y += qRound(line.ascent() + line.descent()); + + QCOMPARE(layout.boundingRect(), QRectF(0, 0, longestLine, y + 1)); +} + +void tst_QTextLayout::boundingRectWithLongLineAndNoWrap() +{ + QString longString("thisisaverylongstringthatcannotbewrappedatallitjustgoesonandonlikeonebigword"); + + const int width = longString.length() * testFont.pixelSize() / 20; // very small widthx + + QTextLayout layout(longString, testFont); + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(width); + + QVERIFY(layout.boundingRect().width() >= line.width()); + QCOMPARE(layout.boundingRect().width(), line.naturalTextWidth()); +} + +void tst_QTextLayout::forcedBreaks() +{ + QString text = "A\n\nB\nC"; + text.replace('\n', QChar::LineSeparator); + + QTextLayout layout(text, testFont); + + layout.beginLayout(); + + int pos = 0; + + QTextLine line = layout.createLine(); + line.setLineWidth(0x10000); + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(),2); + QCOMPARE(qRound(line.naturalTextWidth()),testFont.pixelSize()); + QCOMPARE((int) line.height(), testFont.pixelSize() + 1); // + 1 baseline + QCOMPARE(line.xToCursor(0), line.textStart()); + pos += line.textLength(); + + line = layout.createLine(); + line.setLineWidth(0x10000); + QCOMPARE(line.textStart(),pos); + QCOMPARE(line.textLength(),1); + QCOMPARE(qRound(line.naturalTextWidth()), 0); + QCOMPARE((int) line.height(), testFont.pixelSize() + 1); // + 1 baseline + QCOMPARE(line.xToCursor(0), line.textStart()); + pos += line.textLength(); + + line = layout.createLine(); + line.setLineWidth(0x10000); + QCOMPARE(line.textStart(),pos); + QCOMPARE(line.textLength(),2); + QCOMPARE(qRound(line.naturalTextWidth()),testFont.pixelSize()); + QCOMPARE(qRound(line.height()), testFont.pixelSize() + 1); // + 1 baseline + QCOMPARE(line.xToCursor(0), line.textStart()); + pos += line.textLength(); + + line = layout.createLine(); + line.setLineWidth(0x10000); + QCOMPARE(line.textStart(),pos); + QCOMPARE(line.textLength(),1); + QCOMPARE(qRound(line.naturalTextWidth()), testFont.pixelSize()); + QCOMPARE((int) line.height(), testFont.pixelSize() + 1); // + 1 baseline + QCOMPARE(line.xToCursor(0), line.textStart()); +} + +void tst_QTextLayout::breakAny() +{ +#if defined(Q_WS_MAC) + QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll); +#endif + QString text = "ABCD"; + + QTextLayout layout(text, testFont); + QTextLine line; + + QTextOption opt; + opt.setWrapMode(QTextOption::WrapAnywhere); + layout.setTextOption(opt); + layout.beginLayout(); + + line = layout.createLine(); + line.setLineWidth(testFont.pixelSize() * 2); + QCOMPARE(line.textStart(), 0); + QCOMPARE(line.textLength(), 2); + + line = layout.createLine(); + line.setLineWidth(testFont.pixelSize() * 2); + QCOMPARE(line.textStart(), 2); + QCOMPARE(line.textLength(), 2); + + line = layout.createLine(); + QVERIFY(!line.isValid()); + + layout.endLayout(); + + text = "ABCD EFGH"; + layout.setText(text); + layout.beginLayout(); + + line = layout.createLine(); + line.setLineWidth(testFont.pixelSize() * 7); + QCOMPARE(line.textStart(), 0); + QCOMPARE(line.textLength(), 7); + + layout.endLayout(); +} + +void tst_QTextLayout::noWrap() +{ +#if defined(Q_WS_MAC) + QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll); +#endif + QString text = "AB CD"; + + QTextLayout layout(text, testFont); + QTextLine line; + + QTextOption opt; + opt.setWrapMode(QTextOption::NoWrap); + layout.setTextOption(opt); + layout.beginLayout(); + + line = layout.createLine(); + line.setLineWidth(testFont.pixelSize() * 2); + QCOMPARE(line.textStart(), 0); + QCOMPARE(line.textLength(), 5); + + line = layout.createLine(); + QVERIFY(!line.isValid()); + + layout.endLayout(); +} + +void tst_QTextLayout::cursorToXForInlineObjects() +{ + QChar ch(QChar::ObjectReplacementCharacter); + QString text(ch); + QTextLayout layout(text, testFont); + layout.beginLayout(); + + QTextEngine *engine = layout.engine(); + const int item = engine->findItem(0); + engine->layoutData->items[item].width = 32; + + QTextLine line = layout.createLine(); + line.setLineWidth(0x10000); + + QCOMPARE(line.cursorToX(0), qreal(0)); + QCOMPARE(line.cursorToX(1), qreal(32)); +} + +void tst_QTextLayout::cursorToXForSetColumns() +{ + QTextLayout lay("abc", testFont); + QTextOption o = lay.textOption(); + o.setWrapMode(QTextOption::WrapAnywhere); + + // enable/disable this line for full effect ;) + o.setAlignment(Qt::AlignHCenter); + + lay.setTextOption(o); + lay.beginLayout(); + QTextLine line = lay.createLine(); + line.setNumColumns(1); + lay.endLayout(); + QCOMPARE(line.cursorToX(0), 0.); + QCOMPARE(line.cursorToX(1), (qreal) TESTFONT_SIZE); +} + +void tst_QTextLayout::defaultWordSeparators_data() +{ + QTest::addColumn<QString>("text"); + QTest::addColumn<int>("startPos"); + QTest::addColumn<int>("endPos"); + + QString separators(".,:;-<>[](){}=/+%&^*"); + separators += QLatin1String("!?"); + for (int i = 0; i < separators.count(); ++i) { + QTest::newRow(QString::number(i).toAscii().data()) + << QString::fromLatin1("abcd") + separators.at(i) + QString::fromLatin1("efgh") + << 0 << 4; + } + + QTest::newRow("nbsp") + << QString::fromLatin1("abcd") + QString(QChar::Nbsp) + QString::fromLatin1("efgh") + << 0 << 5; + + QTest::newRow("tab") + << QString::fromLatin1("abcd") + QString::fromLatin1("\t") + QString::fromLatin1("efgh") + << 0 << 5; + + QTest::newRow("lineseparator") + << QString::fromLatin1("abcd") + QString(QChar::LineSeparator) + QString::fromLatin1("efgh") + << 0 << 5; + + QTest::newRow("empty") + << QString() + << 0 << 0; +} + +void tst_QTextLayout::defaultWordSeparators() +{ + QFETCH(QString, text); + QFETCH(int, startPos); + QFETCH(int, endPos); + QTextLayout layout(text, testFont); + + QCOMPARE(layout.nextCursorPosition(startPos, QTextLayout::SkipWords), endPos); + QCOMPARE(layout.previousCursorPosition(endPos, QTextLayout::SkipWords), startPos); +} + +void tst_QTextLayout::cursorMovementFromInvalidPositions() +{ + int badpos = 10000; + + QTextLayout layout("ABC", testFont); + + QCOMPARE(layout.previousCursorPosition(-badpos, QTextLayout::SkipCharacters), -badpos); + QCOMPARE(layout.nextCursorPosition(-badpos, QTextLayout::SkipCharacters), -badpos); + + QCOMPARE(layout.previousCursorPosition(badpos, QTextLayout::SkipCharacters), badpos); + QCOMPARE(layout.nextCursorPosition(badpos, QTextLayout::SkipCharacters), badpos); +} + +void tst_QTextLayout::cursorMovementInsideSpaces() +{ + QTextLayout layout("ABC DEF", testFont); + + QCOMPARE(layout.previousCursorPosition(6, QTextLayout::SkipWords), 0); + QCOMPARE(layout.nextCursorPosition(6, QTextLayout::SkipWords), 15); + + + QTextLayout layout2("ABC\t\t\t\t\t\t\t\t\t\t\t\tDEF", testFont); + + QCOMPARE(layout2.previousCursorPosition(6, QTextLayout::SkipWords), 0); + QCOMPARE(layout2.nextCursorPosition(6, QTextLayout::SkipWords), 15); +} + +void tst_QTextLayout::charWordStopOnLineSeparator() +{ + const QChar lineSeparator(QChar::LineSeparator); + QString txt; + txt.append(lineSeparator); + txt.append(lineSeparator); + QTextLayout layout(txt, testFont); + QTextEngine *engine = layout.engine(); + const HB_CharAttributes *attrs = engine->attributes(); + QVERIFY(attrs); + QVERIFY(attrs[1].charStop); +} + +void tst_QTextLayout::xToCursorAtEndOfLine() +{ +#if defined(Q_WS_MAC) + QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll); +#endif + QString text = "FirstLine SecondLine"; + text.replace('\n', QChar::LineSeparator); + + const qreal firstLineWidth = QString("FirstLine").length() * testFont.pixelSize(); + + QTextLayout layout(text, testFont); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + QVERIFY(line.isValid()); + line.setLineWidth(firstLineWidth); + QVERIFY(layout.createLine().isValid()); + QVERIFY(!layout.createLine().isValid()); + layout.endLayout(); + + line = layout.lineAt(0); + QCOMPARE(line.xToCursor(100000), 9); + line = layout.lineAt(1); + QCOMPARE(line.xToCursor(100000), 20); +} + +void tst_QTextLayout::boundingRectTopLeft() +{ + QString text = "FirstLine\nSecondLine"; + text.replace('\n', QChar::LineSeparator); + + QTextLayout layout(text, testFont); + + layout.beginLayout(); + QTextLine firstLine = layout.createLine(); + QVERIFY(firstLine.isValid()); + firstLine.setPosition(QPointF(10, 10)); + QTextLine secondLine = layout.createLine(); + QVERIFY(secondLine.isValid()); + secondLine.setPosition(QPointF(20, 20)); + layout.endLayout(); + + QCOMPARE(layout.boundingRect().topLeft(), firstLine.position()); +} + +void tst_QTextLayout::charStopForSurrogatePairs() +{ + QString txt; + txt.append("a"); + txt.append(0xd87e); + txt.append(0xdc25); + txt.append("b"); + QTextLayout layout(txt, testFont); + QTextEngine *engine = layout.engine(); + const HB_CharAttributes *attrs = engine->attributes(); + QVERIFY(attrs); + QVERIFY(attrs[0].charStop); + QVERIFY(attrs[1].charStop); + QVERIFY(!attrs[2].charStop); + QVERIFY(attrs[3].charStop); +} + +void tst_QTextLayout::tabStops() +{ +#if defined(Q_WS_MAC) + QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll); +#endif + QString txt("Hello there\tworld"); + QTextLayout layout(txt, testFont); + layout.beginLayout(); + QTextLine line = layout.createLine(); + + QVERIFY(line.isValid()); + line.setNumColumns(11); + QCOMPARE(line.textLength(), TESTFONT_SIZE); + + line = layout.createLine(); + QVERIFY(line.isValid()); + line.setNumColumns(5); + QCOMPARE(line.textLength(), 5); + + layout.endLayout(); +} + +void tst_QTextLayout::integerOverflow() +{ + QString txt("Hello world... "); + + for (int i = 0; i < 8; ++i) + txt += txt; + + QTextLayout layout(txt, testFont); + layout.beginLayout(); + QTextLine line = layout.createLine(); + + QVERIFY(line.isValid()); + line.setLineWidth(INT_MAX); + QCOMPARE(line.textLength(), txt.length()); + + QVERIFY(!layout.createLine().isValid()); + + layout.endLayout(); +} + +void tst_QTextLayout::setNumColumnsWrapAtWordBoundaryOrAnywhere() +{ + QString txt("This is a small test text"); + QTextLayout layout(txt, testFont); + QTextOption option = layout.textOption(); + option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line1 = layout.createLine(); + QVERIFY(line1.isValid()); + line1.setNumColumns(1); + + // qDebug() << line1.naturalTextWidth(); + QCOMPARE(line1.textLength(), 1); + QVERIFY(line1.naturalTextWidth() == testFont.pixelSize()); // contains only one character + + QTextLine line2 = layout.createLine(); + QVERIFY(line2.isValid()); + + layout.endLayout(); +} + +void tst_QTextLayout::setNumColumnsWordWrap() +{ + QString txt("This is a small test text"); + QTextLayout layout(txt, testFont); + QTextOption option = layout.textOption(); + option.setWrapMode(QTextOption::WordWrap); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line1 = layout.createLine(); + QVERIFY(line1.isValid()); + line1.setNumColumns(1); + + // qDebug() << line1.naturalTextWidth(); + QCOMPARE(line1.textLength(), 5); + QVERIFY(line1.naturalTextWidth() > 20.0); // contains the whole first word. + + QTextLine line2 = layout.createLine(); + QVERIFY(line2.isValid()); + + layout.endLayout(); +} + +void tst_QTextLayout::smallTextLengthNoWrap() +{ + QString txt("This is a small test text"); + QTextLayout layout(txt, testFont); + QTextOption option = layout.textOption(); + option.setWrapMode(QTextOption::NoWrap); + layout.setTextOption(option); + + /// NoWrap + layout.beginLayout(); + QTextLine line1 = layout.createLine(); + QVERIFY(line1.isValid()); + line1.setLineWidth(5); // most certainly too short for the word 'This' to fit. + + QCOMPARE(line1.width(), 5.0); + QVERIFY(line1.naturalTextWidth() > 70); // contains all the text. + + QTextLine line2 = layout.createLine(); + QVERIFY(! line2.isValid()); + + layout.endLayout(); +} + +void tst_QTextLayout::smallTextLengthWordWrap() +{ + QString txt("This is a small test text"); + QTextLayout layout(txt, testFont); + QTextOption option = layout.textOption(); + option.setWrapMode(QTextOption::WordWrap); + layout.setTextOption(option); + + /// WordWrap + layout.beginLayout(); + QTextLine line1 = layout.createLine(); + QVERIFY(line1.isValid()); + line1.setLineWidth(5); // most certainly too short for the word 'This' to fit. + + QCOMPARE(line1.width(), 5.0); + QVERIFY(line1.naturalTextWidth() > 20.0); // contains the whole first word. + QCOMPARE(line1.textLength(), 5); + + QTextLine line2 = layout.createLine(); + QVERIFY(line2.isValid()); + + layout.endLayout(); +} + +void tst_QTextLayout::smallTextLengthWrapAtWordBoundaryOrAnywhere() +{ + QString txt("This is a small test text"); + QTextLayout layout(txt, testFont); + QTextOption option = layout.textOption(); + option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line1 = layout.createLine(); + QVERIFY(line1.isValid()); + line1.setLineWidth(5); // most certainly too short for the word 'This' to fit. + + QCOMPARE(line1.width(), 5.0); + // qDebug() << line1.naturalTextWidth(); + QCOMPARE(line1.textLength(), 1); + QVERIFY(line1.naturalTextWidth() == testFont.pixelSize()); // contains just the characters that fit. + + QTextLine line2 = layout.createLine(); + QVERIFY(line2.isValid()); + + layout.endLayout(); +} + +void tst_QTextLayout::testDefaultTabs() +{ + QTextLayout layout("Foo\tBar\ta slightly longer text\tend.", testFont); + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(1000); + layout.endLayout(); + + //qDebug() << "After the tab: " << line.cursorToX(4); + QCOMPARE(line.cursorToX(4), 80.); // default tab is 80 + QCOMPARE(line.cursorToX(8), 160.); + QCOMPARE(line.cursorToX(31), 480.); + + QTextOption option = layout.textOption(); + option.setTabStop(90); + layout.setTextOption(option); + layout.beginLayout(); + line = layout.createLine(); + line.setLineWidth(1000); + layout.endLayout(); + + QCOMPARE(line.cursorToX(4), 90.); + QCOMPARE(line.cursorToX(8), 180.); + QCOMPARE(line.cursorToX(31), 450.); + + QList<QTextOption::Tab> tabs; + QTextOption::Tab tab; + tab.position = 110; // set one tab to 110, but since the rest is unset they will be at the normal interval again. + tabs.append(tab); + option.setTabs(tabs); + layout.setTextOption(option); + layout.beginLayout(); + line = layout.createLine(); + line.setLineWidth(1000); + layout.endLayout(); + + QCOMPARE(line.cursorToX(4), 110.); + QCOMPARE(line.cursorToX(8), 180.); + QCOMPARE(line.cursorToX(31), 450.); +} + +void tst_QTextLayout::testTabs() +{ + QTextLayout layout("Foo\tBar.", testFont); + QTextOption option = layout.textOption(); + option.setTabStop(150); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(200.); + layout.endLayout(); + + QVERIFY(line.naturalTextWidth() > 150); + QCOMPARE(line.cursorToX(4), 150.); +} + +void tst_QTextLayout::testMultilineTab() +{ + QTextLayout layout("Lorem ipsum dolor sit\tBar.", testFont); + // test if this works on the second line. + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(220.); // moves 'sit' to next line. + line = layout.createLine(); + line.setLineWidth(220.); + layout.endLayout(); + + QCOMPARE(line.cursorToX(22), 80.); +} + +void tst_QTextLayout::testMultiTab() +{ + QTextLayout layout("Foo\t\t\tBar.", testFont); + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(1000.); + layout.endLayout(); + + QCOMPARE(line.cursorToX(6), 80. * 3); +} + +void tst_QTextLayout::testTabsInAlignedParag() +{ + QTextLayout layout("Foo\tsome more words", testFont); + QTextOption option = layout.textOption(); + // right + option.setAlignment(Qt::AlignRight); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(300.); + layout.endLayout(); + + const qreal textWidth = 80 + 15 * TESTFONT_SIZE; // 15 chars right of the tab + QCOMPARE(line.naturalTextWidth(), textWidth); + QCOMPARE(line.cursorToX(0), 300. - textWidth); + + // centered + option.setAlignment(Qt::AlignCenter); + layout.setTextOption(option); + + layout.beginLayout(); + line = layout.createLine(); + line.setLineWidth(300.); + layout.endLayout(); + + QCOMPARE(line.naturalTextWidth(), textWidth); + QCOMPARE(line.cursorToX(0), (300. - textWidth) / 2.); + + // justified + option.setAlignment(Qt::AlignJustify); + layout.setTextOption(option); + + layout.beginLayout(); + line = layout.createLine(); + line.setLineWidth(textWidth - 10); // make the last word slip to the next line so justification actually happens. + layout.endLayout(); + + QCOMPARE(line.cursorToX(0), 0.); + QCOMPARE(line.cursorToX(4), 80.); + + //QTextLayout layout2("Foo\tUt wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis", testFont); // means it will be more then one line long. +} + +void tst_QTextLayout::testRightTab() +{ + QTextLayout layout("Foo\tLorem ipsum te sit\tBar baz\tText\tEnd", testFont); + /* ^ a ^ b ^ c ^ d + a = 4, b = 22, c = 30, d = 35 (position) + + I expect the output to be: + Foo Lorem ipsum te + sit Bar Baz + Text End + + a) tab replaced with a single space due to the text not fitting before the tab. + b) tab takes space so the text until the 3th tab fits to the tab pos. + c) tab is after last tab (both auto and defined) and thus moves text to start of next line. + d) tab takes space so text until enter fits to tab pos. + */ + + QTextOption option = layout.textOption(); + QList<QTextOption::Tab> tabs; + QTextOption::Tab tab; + tab.type = QTextOption::RightTab; + tab.position = 190; // which means only 15(.8) chars of our test font fit left of it. + tabs.append(tab); + option.setTabs(tabs); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line1 = layout.createLine(); + line1.setLineWidth(220.); + // qDebug() << "=====line 2"; + QTextLine line2 = layout.createLine(); + QVERIFY(line2.isValid()); + line2.setLineWidth(220.); + // qDebug() << "=====line 3"; + QTextLine line3 = layout.createLine(); + QVERIFY(line3.isValid()); + line3.setLineWidth(220.); + // qDebug() << "=====line 4"; + QTextLine line4 = layout.createLine(); + QVERIFY(! line4.isValid()); + layout.endLayout(); + // qDebug() << "--------"; + + QCOMPARE(line1.cursorToX(4), 3. * TESTFONT_SIZE ); // a + QCOMPARE(line1.textLength(), 19); + QCOMPARE(line2.cursorToX(23), 190. - 7. * TESTFONT_SIZE); // b + QCOMPARE(line2.textLength(), 12); + QCOMPARE(line3.cursorToX(31), 0.); // c + QCOMPARE(line3.cursorToX(36), 190 - 3. * TESTFONT_SIZE); // d +} + +void tst_QTextLayout::testCenteredTab() +{ + QTextLayout layout("Foo\tBar", testFont); + // test if centering the tab works. We expect the center of 'Bar.' to be at the tab point. + QTextOption option = layout.textOption(); + QList<QTextOption::Tab> tabs; + QTextOption::Tab tab(150, QTextOption::CenterTab); + tabs.append(tab); + option.setTabs(tabs); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(200.); + layout.endLayout(); + + const qreal wordLength = 3 * TESTFONT_SIZE; // the length of 'Bar' + QCOMPARE(line.cursorToX(4), 150 - wordLength / 2.); +} + +void tst_QTextLayout::testDelimiterTab() +{ + QTextLayout layout("Foo\tBar. Barrabas", testFont); + // try the different delimiter characters to see if the alignment works there. + QTextOption option = layout.textOption(); + QList<QTextOption::Tab> tabs; + QTextOption::Tab tab(100, QTextOption::DelimiterTab, QChar('.')); + tabs.append(tab); + option.setTabs(tabs); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(200.); + layout.endLayout(); + + const qreal distanceBeforeTab = 3.5 * TESTFONT_SIZE; // the length of 'bar' and half the width of the dot. + QCOMPARE(line.cursorToX(4), 100 - distanceBeforeTab); +} + +void tst_QTextLayout::testLineBreakingAllSpaces() +{ + QTextLayout layout(" 123", testFont); // thats 20 spaces + const qreal firstLineWidth = 17 * TESTFONT_SIZE; + layout.beginLayout(); + QTextLine line1 = layout.createLine(); + line1.setLineWidth(firstLineWidth); + QTextLine line2 = layout.createLine(); + line2.setLineWidth(1000); // the rest + layout.endLayout(); + QCOMPARE(line1.width(), firstLineWidth); + QCOMPARE(line1.naturalTextWidth(), 0.); // spaces don't take space + QCOMPARE(line1.textLength(), 20); + QCOMPARE(line2.textLength(), 3); + QCOMPARE(line2.naturalTextWidth(), 3. * TESTFONT_SIZE); +} + +void tst_QTextLayout::tabsForRtl() +{ + QString word(QChar(0x5e9)); // a hebrew character + word = word + word + word; // 3 hebrew characters ;) + + QTextLayout layout(word +'\t'+ word +'\t'+ word +'\t'+ word, testFont); +//QTextLayout layout(word +' '+ word +' '+ word +' '+ word, testFont);// tester ;) + /* ^ a ^ b ^ c + a = 4, b = 8, c = 12, d = 16 (position) + + a) Left tab in RTL is a righ tab; so a is at width - 80 + b) Like a + c) right tab on RTL is a left tab; so its at width - 240 + d) center tab is still a centered tab. + */ + + QTextOption option = layout.textOption(); + QList<QTextOption::Tab> tabs; + QTextOption::Tab tab; + tab.position = 80; + tabs.append(tab); + tab.position = 160; + tabs.append(tab); + tab.position = 240; + tab.type = QTextOption::RightTab; + tabs.append(tab); + option.setTabs(tabs); + option.setTextDirection(Qt::RightToLeft); + option.setAlignment(Qt::AlignRight); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + const qreal WIDTH = 400.; + line.setLineWidth(WIDTH); + layout.endLayout(); + +//qDebug() << "layout ended --------------"; + + QCOMPARE(line.cursorToX(0), WIDTH); + QCOMPARE(line.cursorToX(1), WIDTH - TESTFONT_SIZE); // check its right-aligned + QCOMPARE(line.cursorToX(4), WIDTH - 80 + 3 * TESTFONT_SIZE); + QCOMPARE(line.cursorToX(8), WIDTH - 160 + 3 * TESTFONT_SIZE); + QCOMPARE(line.cursorToX(12), WIDTH - 240); +} + +QT_BEGIN_NAMESPACE +extern int qt_defaultDpiY(); +QT_END_NAMESPACE + +void tst_QTextLayout::testTabDPIScale() +{ + class MyPaintDevice : public QPaintDevice { + QPaintEngine *paintEngine () const { return 0; } + int metric (QPaintDevice::PaintDeviceMetric metric) const { + switch(metric) { + case QPaintDevice::PdmWidth: + case QPaintDevice::PdmHeight: + case QPaintDevice::PdmWidthMM: + case QPaintDevice::PdmHeightMM: + case QPaintDevice::PdmNumColors: + return INT_MAX; + case QPaintDevice::PdmDepth: + return 32; + case QPaintDevice::PdmDpiX: + case QPaintDevice::PdmDpiY: + case QPaintDevice::PdmPhysicalDpiX: + case QPaintDevice::PdmPhysicalDpiY: + return 72; + } + return 0; + } + }; + + MyPaintDevice pd; + + QTextLayout layout("text1\ttext2\ttext3\tend", testFont, &pd); + + QTextOption option = layout.textOption(); + QList<QTextOption::Tab> tabs; + QTextOption::Tab tab; + tab.position = 300; + tabs.append(tab); + + tab.position = 600; + tab.type = QTextOption::RightTab; + tabs.append(tab); + + tab.position = 800; + tab.type = QTextOption::CenterTab; + tabs.append(tab); + option.setTabs(tabs); + layout.setTextOption(option); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(1500.); + layout.endLayout(); + QCOMPARE(line.cursorToX(0), 0.); + QCOMPARE(line.cursorToX(1), (double) TESTFONT_SIZE); // check that the font does not resize + qreal scale = 72 / (qreal) qt_defaultDpiY(); + // lets do the transformation of deminishing resolution that QFixed has as effect. + int fixedScale = (int)( scale * qreal(64)); // into a QFixed + scale = ((qreal)fixedScale)/(qreal)64; // and out of a QFixed + + QCOMPARE(line.cursorToX(6), tabs.at(0).position * scale); + QCOMPARE(line.cursorToX(12), tabs.at(1).position * scale - TESTFONT_SIZE * 5); + QCOMPARE(line.cursorToX(18), tabs.at(2).position * scale - TESTFONT_SIZE * 3 / 2.0); +} + +void tst_QTextLayout::tabHeight() +{ + QTextLayout layout("\t", testFont); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QCOMPARE(qRound(line.ascent()), QFontMetrics(testFont).ascent()); + QCOMPARE(qRound(line.descent()), QFontMetrics(testFont).descent()); +} + +void tst_QTextLayout::capitalization_allUpperCase() +{ + QFont font(testFont); + font.setCapitalization(QFont::AllUppercase); + QTextLayout layout("Test", font); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QTextEngine *engine = layout.engine(); + engine->itemize(); + QCOMPARE(engine->layoutData->items.count(), 1); + QVERIFY(engine->layoutData->items.at(0).analysis.flags == QScriptAnalysis::Uppercase); +} + +void tst_QTextLayout::capitalization_allLowerCase() +{ + QFont font(testFont); + font.setCapitalization(QFont::AllLowercase); + QTextLayout layout("Test", font); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QTextEngine *engine = layout.engine(); + engine->itemize(); + QCOMPARE(engine->layoutData->items.count(), 1); + QVERIFY(engine->layoutData->items.at(0).analysis.flags == QScriptAnalysis::Lowercase); +} + +void tst_QTextLayout::capitalization_smallCaps() +{ + QFont font(testFont); + font.setCapitalization(QFont::SmallCaps); + QTextLayout layout("Test", font); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QTextEngine *engine = layout.engine(); + engine->itemize(); + QCOMPARE(engine->layoutData->items.count(), 2); + QVERIFY(engine->layoutData->items.at(0).analysis.flags == QScriptAnalysis::None); + QVERIFY(engine->layoutData->items.at(1).analysis.flags == QScriptAnalysis::SmallCaps); +} + +void tst_QTextLayout::capitalization_capitalize() +{ + QFont font(testFont); + font.setCapitalization(QFont::Capitalize); + QTextLayout layout("hello\tworld", font); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QTextEngine *engine = layout.engine(); + engine->itemize(); + QCOMPARE(engine->layoutData->items.count(), 5); + QVERIFY(engine->layoutData->items.at(0).analysis.flags == QScriptAnalysis::Uppercase); + QVERIFY(engine->layoutData->items.at(1).analysis.flags == QScriptAnalysis::None); + QVERIFY(engine->layoutData->items.at(2).analysis.flags == QScriptAnalysis::Tab); + QVERIFY(engine->layoutData->items.at(3).analysis.flags == QScriptAnalysis::Uppercase); + QVERIFY(engine->layoutData->items.at(4).analysis.flags == QScriptAnalysis::None); +} + +void tst_QTextLayout::longText() +{ + QString longText(128000, 'a'); + + { + QTextLayout layout(longText, testFont); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QVERIFY(line.isValid()); + QVERIFY(line.cursorToX(line.textLength() - 1) > 0); + } + + for (int cap = QFont::MixedCase; cap < QFont::Capitalize + 1; ++cap) { + QFont f(testFont); + f.setCapitalization(QFont::Capitalization(cap)); + QTextLayout layout(longText, f); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QVERIFY(line.isValid()); + QVERIFY(line.cursorToX(line.textLength() - 1) > 0); + } + + { + QTextLayout layout(longText, testFont); + layout.setFlags(Qt::TextForceLeftToRight); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QVERIFY(line.isValid()); + QVERIFY(line.cursorToX(line.textLength() - 1) > 0); + } + + { + QTextLayout layout(longText, testFont); + layout.setFlags(Qt::TextForceRightToLeft); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QVERIFY(line.isValid()); + QVERIFY(line.cursorToX(line.textLength() - 1) > 0); + } +} + +void tst_QTextLayout::widthOfTabs() +{ + QTextEngine engine("ddd\t\t", testFont); + engine.ignoreBidi = true; + engine.itemize(); + QCOMPARE(qRound(engine.width(0, 5)), qRound(engine.boundingBox(0, 5).width)); +} + +void tst_QTextLayout::columnWrapWithTabs() +{ + QTextLayout textLayout; + { + QTextOption textOption; + textOption.setWrapMode(QTextOption::WordWrap); + textLayout.setTextOption(textOption); + } + + // Make sure string with spaces does not break + { + QString text = "Foo bar foo bar foo bar"; + textLayout.setText(text); + + textLayout.beginLayout(); + QTextLine line = textLayout.createLine(); + line.setNumColumns(30); + QCOMPARE(line.textLength(), text.length()); + textLayout.endLayout(); + } + + // Make sure string with tabs breaks + { + QString text = "Foo\tbar\tfoo\tbar\tfoo\tbar"; + textLayout.setText(text); + textLayout.beginLayout(); + QTextLine line = textLayout.createLine(); + line.setNumColumns(30); + QVERIFY(line.textLength() < text.length()); + textLayout.endLayout(); + } + +} + +void tst_QTextLayout::boundingRectForUnsetLineWidth() +{ + QTextLayout layout("FOOBAR"); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QCOMPARE(layout.boundingRect().width(), line.naturalTextWidth()); +} + +void tst_QTextLayout::boundingRectForSetLineWidth() +{ + QTextLayout layout("FOOBAR"); + + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(QFIXED_MAX - 1); + layout.endLayout(); + + QCOMPARE(layout.boundingRect().width(), qreal(QFIXED_MAX - 1)); +} + +void tst_QTextLayout::lineWidthFromBOM() +{ + const QString string(QChar(0xfeff)); // BYTE ORDER MARK + QTextLayout layout(string); + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(INT_MAX / 256); + layout.endLayout(); + + // Don't spin into an infinite loop + } + +void tst_QTextLayout::glyphLessItems() +{ + { + QTextLayout layout; + layout.setText("\t\t"); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + } + + { + QTextLayout layout; + layout.setText(QString::fromLatin1("AA") + QChar(QChar::LineSeparator)); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + } +} + +void tst_QTextLayout::textWidthVsWIdth() +{ + QTextLayout layout; + QTextOption opt; + opt.setWrapMode(QTextOption::WrapAnywhere); + layout.setTextOption(opt); + layout.setText(QString::fromLatin1( + "g++ -c -m64 -pipe -g -fvisibility=hidden -fvisibility-inlines-hidden -Wall -W -D_REENTRANT -fPIC -DCORE_LIBRARY -DIDE_LIBRARY_BASENAME=\"lib\" -DWITH_TESTS " + "-DQT_NO_CAST_TO_ASCII -DQT_USE_FAST_OPERATOR_PLUS -DQT_USE_FAST_CONCATENATION -DQT_PLUGIN -DQT_TESTLIB_LIB -DQT_SCRIPT_LIB -DQT_SVG_LIB -DQT_SQL_LIB -DQT_XM" + "L_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_SHARED -I../../../../qt-qml/mkspecs/linux-g++-64 -I. -I../../../../qt-qml/include/QtCore -I../../../." + "./qt-qml/include/QtNetwork -I../../../../qt-qml/include/QtGui -I../../../../qt-qml/include/QtXml -I../../../../qt-qml/include/QtSql -I../../../../qt-qml/inc" + "lude/QtSvg -I../../../../qt-qml/include/QtScript -I../../../../qt-qml/include/QtTest -I../../../../qt-qml/include -I../../../../qt-qml/include/QtHelp -I../." + "./libs -I/home/ettrich/dev/creator/tools -I../../plugins -I../../shared/scriptwrapper -I../../libs/3rdparty/botan/build -Idialogs -Iactionmanager -Ieditorma" + "nager -Iprogressmanager -Iscriptmanager -I.moc/debug-shared -I.uic -o .obj/debug-shared/sidebar.o sidebar.cpp")); + + // textWidth includes right bearing, but it should never be LARGER than width if there is space for at least one character + for (int width = 100; width < 1000; ++width) { + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(width); + layout.endLayout(); + + qreal textWidthIsLargerBy = qMax(qreal(0), line.naturalTextWidth() - line.width()); + qreal thisMustBeZero = 0; + QCOMPARE(textWidthIsLargerBy, thisMustBeZero); + } +} + +void tst_QTextLayout::textWithSurrogates_qtbug15679() +{ + QString str = QString::fromUtf8("🀀a🀀"); + QTextLayout layout(str); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + qreal x[6]; + for (int i = 0; i < 6; i++) + x[i] = line.cursorToX(i); + + // If the first and third character are using the same + // font, they must have the same advance (since they + // are surrogate pairs, we need to add two for each + // character) + QCOMPARE(x[2] - x[0], x[5] - x[3]); +} + +void tst_QTextLayout::textWidthWithStackedTextEngine() +{ + QString text = QString::fromUtf8("คลิภถัดไป เพื่à¸à¸”ำเนินà¸à¸²à¸£à¸•à¹ˆà¸"); + QTextLayout layout(text); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QFontMetricsF fm(layout.font()); + QCOMPARE(line.naturalTextWidth(), fm.width(text)); +} + +void tst_QTextLayout::textWidthWithLineSeparator() +{ + QString s1("Save Project"), s2("Save Project\ntest"); + s2.replace('\n', QChar::LineSeparator); + + QTextLayout layout1(s1), layout2(s2); + layout1.beginLayout(); + layout2.beginLayout(); + + QTextLine line1 = layout1.createLine(); + QTextLine line2 = layout2.createLine(); + line1.setLineWidth(0x1000); + line2.setLineWidth(0x1000); + QCOMPARE(line1.naturalTextWidth(), line2.naturalTextWidth()); +} + +void tst_QTextLayout::cursorInLigatureWithMultipleLines() +{ +#if !defined(Q_WS_MAC) + QSKIP("This test can not be run on Mac", SkipAll); +#endif + QTextLayout layout("first line finish", QFont("Times", 20)); + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(70); + line = layout.createLine(); + layout.endLayout(); + + // The second line will be "finish", with "fi" as a ligature + QVERIFY(line.cursorToX(0) != line.cursorToX(1)); +} + +void tst_QTextLayout::xToCursorForLigatures() +{ +#if !defined(Q_WS_MAC) + QSKIP("This test can not be run on Mac", SkipAll); +#endif + QTextLayout layout("fi", QFont("Times", 20)); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + QVERIFY(line.xToCursor(0) != line.xToCursor(line.naturalTextWidth() / 2)); + + // U+0061 U+0308 + QTextLayout layout2(QString::fromUtf8("\x61\xCC\x88"), QFont("Times", 20)); + + layout2.beginLayout(); + line = layout2.createLine(); + layout2.endLayout(); + + qreal width = line.naturalTextWidth(); + QVERIFY(line.xToCursor(0) == line.xToCursor(width / 2) || + line.xToCursor(width) == line.xToCursor(width / 2)); +} + +QTEST_MAIN(tst_QTextLayout) +#include "tst_qtextlayout.moc" diff --git a/tests/auto/gui/text/qtextlist/.gitignore b/tests/auto/gui/text/qtextlist/.gitignore new file mode 100644 index 0000000000..f1c4f6acab --- /dev/null +++ b/tests/auto/gui/text/qtextlist/.gitignore @@ -0,0 +1 @@ +tst_qtextlist diff --git a/tests/auto/gui/text/qtextlist/qtextlist.pro b/tests/auto/gui/text/qtextlist/qtextlist.pro new file mode 100644 index 0000000000..f66fb96dd0 --- /dev/null +++ b/tests/auto/gui/text/qtextlist/qtextlist.pro @@ -0,0 +1,9 @@ +load(qttest_p4) + +QT += core-private gui-private + +SOURCES += tst_qtextlist.cpp +HEADERS += ../qtextdocument/common.h + + + diff --git a/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp new file mode 100644 index 0000000000..164dd6fc68 --- /dev/null +++ b/tests/auto/gui/text/qtextlist/tst_qtextlist.cpp @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qtextdocument.h> +#include <qtextdocumentfragment.h> +#include <qtextlist.h> +#include <qabstracttextdocumentlayout.h> +#include <qtextcursor.h> +#include "../qtextdocument/common.h" + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QTextList : public QObject +{ + Q_OBJECT + +public: + tst_QTextList(); + + +public slots: + void init(); + void cleanup(); +private slots: + void item(); + void autoNumbering(); + void autoNumberingRTL(); + void autoNumberingPrefixAndSuffix(); + void autoNumberingPrefixAndSuffixRTL(); + void autoNumberingPrefixAndSuffixHtmlExportImport(); + void romanNumbering(); + void romanNumberingLimit(); + void formatChange(); + void cursorNavigation(); + void partialRemoval(); + void formatReferenceChange(); + void ensureItemOrder(); + void add(); + void defaultIndent(); + void blockUpdate(); + void numbering_data(); + void numbering(); + +private: + QTextDocument *doc; + QTextCursor cursor; + QTestDocumentLayout *layout; +}; + +tst_QTextList::tst_QTextList() +{} + +void tst_QTextList::init() +{ + doc = new QTextDocument(); + layout = new QTestDocumentLayout(doc); + doc->setDocumentLayout(layout); + cursor = QTextCursor(doc); +} + +void tst_QTextList::cleanup() +{ + cursor = QTextCursor(); + delete doc; + doc = 0; +} + +void tst_QTextList::item() +{ + // this is basically a test for the key() + 1 in QTextList::item. + QTextList *list = cursor.createList(QTextListFormat()); + QVERIFY(list->item(0).blockFormat().objectIndex() != -1); +} + +void tst_QTextList::autoNumbering() +{ + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListLowerAlpha); + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + for (int i = 0; i < 27; ++i) + cursor.insertBlock(); + + QVERIFY(list->count() == 28); + + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->itemNumber(cursor.block()) == 27); + QVERIFY(cursor.currentList()->itemText(cursor.block()) == "ab."); +} + +void tst_QTextList::autoNumberingPrefixAndSuffix() +{ + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListLowerAlpha); + fmt.setNumberPrefix("-"); + fmt.setNumberSuffix(")"); + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + for (int i = 0; i < 27; ++i) + cursor.insertBlock(); + + QVERIFY(list->count() == 28); + + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->itemNumber(cursor.block()) == 27); + QVERIFY(cursor.currentList()->itemText(cursor.block()) == "-ab)"); +} + +void tst_QTextList::autoNumberingPrefixAndSuffixRTL() +{ + QTextBlockFormat bfmt; + bfmt.setLayoutDirection(Qt::RightToLeft); + cursor.setBlockFormat(bfmt); + + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListUpperAlpha); + fmt.setNumberPrefix("-"); + fmt.setNumberSuffix("*"); + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + cursor.insertBlock(); + + QVERIFY(list->count() == 2); + + QVERIFY(cursor.currentList()->itemText(cursor.block()) == "*B-"); +} + +void tst_QTextList::autoNumberingPrefixAndSuffixHtmlExportImport() +{ + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListLowerAlpha); + fmt.setNumberPrefix("\""); + fmt.setNumberSuffix("#"); + fmt.setIndent(10); + // FIXME: Would like to test "'" but there's a problem in the css parser (Scanner::preprocess + // is called before the values are being parsed), so the quoting does not work. + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + for (int i = 0; i < 27; ++i) + cursor.insertBlock(); + + QVERIFY(list->count() == 28); + + QString htmlExport = doc->toHtml(); + QTextDocument importDoc; + importDoc.setHtml(htmlExport); + + QTextCursor importCursor(&importDoc); + for (int i = 0; i < 27; ++i) + importCursor.movePosition(QTextCursor::NextBlock); + + QVERIFY(importCursor.currentList()); + QVERIFY(importCursor.currentList()->itemNumber(importCursor.block()) == 27); + QVERIFY(importCursor.currentList()->itemText(importCursor.block()) == "\"ab#"); + QVERIFY(importCursor.currentList()->format().indent() == 10); +} + +void tst_QTextList::autoNumberingRTL() +{ + QTextBlockFormat bfmt; + bfmt.setLayoutDirection(Qt::RightToLeft); + cursor.setBlockFormat(bfmt); + + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListUpperAlpha); + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + cursor.insertBlock(); + + QVERIFY(list->count() == 2); + + QVERIFY(cursor.currentList()->itemText(cursor.block()) == ".B"); +} + +void tst_QTextList::romanNumbering() +{ + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListUpperRoman); + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + for (int i = 0; i < 4998; ++i) + cursor.insertBlock(); + + QVERIFY(list->count() == 4999); + + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->itemNumber(cursor.block()) == 4998); + QVERIFY(cursor.currentList()->itemText(cursor.block()) == "MMMMCMXCIX."); +} + +void tst_QTextList::romanNumberingLimit() +{ + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListLowerRoman); + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + for (int i = 0; i < 4999; ++i) + cursor.insertBlock(); + + QVERIFY(list->count() == 5000); + + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->itemNumber(cursor.block()) == 4999); + QVERIFY(cursor.currentList()->itemText(cursor.block()) == "?."); +} + +void tst_QTextList::formatChange() +{ + // testing the formatChanged slot in QTextListManager + + /* <initial block> + * 1. + * 2. + */ + QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); + QTextList *firstList = list; + cursor.insertBlock(); + + QVERIFY(list && list->count() == 2); + + QTextBlockFormat bfmt = cursor.blockFormat(); +// QVERIFY(bfmt.object() == list); + + bfmt.setObjectIndex(-1); + cursor.setBlockFormat(bfmt); + + QVERIFY(firstList->count() == 1); +} + +void tst_QTextList::cursorNavigation() +{ + // testing some cursor list methods + + /* <initial block> + * 1. + * 2. + */ + cursor.insertList(QTextListFormat::ListDecimal); + cursor.insertBlock(); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.currentList()); + cursor.movePosition(QTextCursor::PreviousBlock); + QVERIFY(cursor.currentList()); + QVERIFY(cursor.currentList()->itemNumber(cursor.block()) == 0); +} + +void tst_QTextList::partialRemoval() +{ + /* this is essentially a test for PieceTable::removeBlock to not miss any + blocks with the blockChanged signal emission that actually get removed. + + It creates two lists, like this: + + 1. Hello World + a. Foobar + + and then removes from within the 'Hello World' into the 'Foobar' . + There used to be no emission for the removal of the second (a.) block, + causing list inconsistencies. + + */ + + QTextList *firstList = cursor.insertList(QTextListFormat::ListDecimal); + + QTextCursor selStart = cursor; + selStart.movePosition(QTextCursor::PreviousCharacter); + + cursor.insertText("Hello World"); + + // position it well into the 'hello world' text. + selStart.movePosition(QTextCursor::NextCharacter); + selStart.movePosition(QTextCursor::NextCharacter); + selStart.clearSelection(); + + QPointer<QTextList> secondList = cursor.insertList(QTextListFormat::ListCircle); + cursor.insertText("Foobar"); + + // position it into the 'foo bar' text. + cursor.movePosition(QTextCursor::PreviousCharacter); + QTextCursor selEnd = cursor; + + // this creates a selection that includes parts of both text-fragments and also the list item of the second list. + QTextCursor selection = selStart; + selection.setPosition(selEnd.position(), QTextCursor::KeepAnchor); + + selection.deleteChar(); // deletes the second list + + QVERIFY(!secondList); + QVERIFY(!firstList->isEmpty()); + + doc->undo(); +} + +void tst_QTextList::formatReferenceChange() +{ + QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); + cursor.insertText("Some Content..."); + cursor.insertBlock(QTextBlockFormat()); + + cursor.setPosition(list->item(0).position()); + int listItemStartPos = cursor.position(); + cursor.movePosition(QTextCursor::NextBlock); + int listItemLen = cursor.position() - listItemStartPos; + layout->expect(listItemStartPos, listItemLen, listItemLen); + + QTextListFormat fmt = list->format(); + fmt.setStyle(QTextListFormat::ListCircle); + list->setFormat(fmt); + + QVERIFY(layout->called); + QVERIFY(!layout->error); +} + +void tst_QTextList::ensureItemOrder() +{ + /* + * Insert a new list item before the first one and verify the blocks + * are sorted after that. + */ + QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); + + QTextBlockFormat fmt = cursor.blockFormat(); + cursor.movePosition(QTextCursor::Start); + cursor.insertBlock(fmt); + + QCOMPARE(list->item(0).position(), 1); + QCOMPARE(list->item(1).position(), 2); +} + +void tst_QTextList::add() +{ + QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); + cursor.insertBlock(QTextBlockFormat()); + QCOMPARE(list->count(), 1); + cursor.insertBlock(QTextBlockFormat()); + list->add(cursor.block()); + QCOMPARE(list->count(), 2); +} + +// Task #72036 +void tst_QTextList::defaultIndent() +{ + QTextListFormat fmt; + QCOMPARE(fmt.indent(), 1); +} + +void tst_QTextList::blockUpdate() +{ + // three items + QTextList *list = cursor.insertList(QTextListFormat::ListDecimal); + cursor.insertBlock(); + cursor.insertBlock(); + + // remove second, needs also update on the third + // since the numbering might have changed + const int len = cursor.position() + cursor.block().length() - 1; + layout->expect(1, len, len); + list->remove(list->item(1)); + QVERIFY(!layout->error); +} + +void tst_QTextList::numbering_data() +{ + QTest::addColumn<int>("format"); + QTest::addColumn<int>("number"); + QTest::addColumn<QString>("result"); + + QTest::newRow("E.") << int(QTextListFormat::ListUpperAlpha) << 5 << "E."; + QTest::newRow("abc.") << int(QTextListFormat::ListLowerAlpha) << (26 + 2) * 26 + 3 << "abc."; + QTest::newRow("12.") << int(QTextListFormat::ListDecimal) << 12 << "12."; + QTest::newRow("XXIV.") << int(QTextListFormat::ListUpperRoman) << 24 << "XXIV."; + QTest::newRow("VIII.") << int(QTextListFormat::ListUpperRoman) << 8 << "VIII."; + QTest::newRow("xxx.") << int(QTextListFormat::ListLowerRoman) << 30 << "xxx."; + QTest::newRow("xxix.") << int(QTextListFormat::ListLowerRoman) << 29 << "xxix."; +// QTest::newRow("xxx. alpha") << int(QTextListFormat::ListLowerAlpha) << (24 * 26 + 24) * 26 + 24 << "xxx."; //Too slow +} + +void tst_QTextList::numbering() +{ + QFETCH(int, format); + QFETCH(int, number); + QFETCH(QString, result); + + + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::Style(format)); + QTextList *list = cursor.createList(fmt); + QVERIFY(list); + + for (int i = 1; i < number; ++i) + cursor.insertBlock(); + + QCOMPARE(list->count(), number); + + QVERIFY(cursor.currentList()); + QCOMPARE(cursor.currentList()->itemNumber(cursor.block()), number - 1); + QCOMPARE(cursor.currentList()->itemText(cursor.block()), result); +} + +QTEST_MAIN(tst_QTextList) +#include "tst_qtextlist.moc" diff --git a/tests/auto/gui/text/qtextobject/.gitignore b/tests/auto/gui/text/qtextobject/.gitignore new file mode 100644 index 0000000000..6a3da09549 --- /dev/null +++ b/tests/auto/gui/text/qtextobject/.gitignore @@ -0,0 +1 @@ +tst_qtextobject diff --git a/tests/auto/gui/text/qtextobject/qtextobject.pro b/tests/auto/gui/text/qtextobject/qtextobject.pro new file mode 100644 index 0000000000..e87a364ab6 --- /dev/null +++ b/tests/auto/gui/text/qtextobject/qtextobject.pro @@ -0,0 +1,9 @@ +############################################################ +# Project file for autotest for file qtextobject.h +############################################################ + +load(qttest_p4) +QT += widgets +SOURCES += tst_qtextobject.cpp + + diff --git a/tests/auto/gui/text/qtextobject/tst_qtextobject.cpp b/tests/auto/gui/text/qtextobject/tst_qtextobject.cpp new file mode 100644 index 0000000000..0d1773e3fa --- /dev/null +++ b/tests/auto/gui/text/qtextobject/tst_qtextobject.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#include <qcoreapplication.h> +#include <qdebug.h> +#include <qtextobject.h> +#include <qtextdocument.h> +#include <qtextedit.h> +#include <qtextcursor.h> + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QTextObject : public QObject +{ +Q_OBJECT + +public: + tst_QTextObject(); + virtual ~tst_QTextObject(); + +private slots: + void getSetCheck(); + void testStandAloneTextObject(); +}; + +tst_QTextObject::tst_QTextObject() +{ +} + +tst_QTextObject::~tst_QTextObject() +{ +} + +// Testing get/set functions +void tst_QTextObject::getSetCheck() +{ + QTextEdit edit; + QTextFrame obj1(edit.document()); + // QTextFrameLayoutData * QTextFrame::layoutData() + // void QTextFrame::setLayoutData(QTextFrameLayoutData *) + QTextFrameLayoutData *var1 = new QTextFrameLayoutData; + obj1.setLayoutData(var1); + QCOMPARE(var1, obj1.layoutData()); + obj1.setLayoutData((QTextFrameLayoutData *)0); + QCOMPARE((QTextFrameLayoutData *)0, obj1.layoutData()); + // delete var1; // No delete, since QTextFrame takes ownership + + QTextBlock obj2 = edit.textCursor().block(); + // QTextBlockUserData * QTextBlock::userData() + // void QTextBlock::setUserData(QTextBlockUserData *) + QTextBlockUserData *var2 = new QTextBlockUserData; + obj2.setUserData(var2); + QCOMPARE(var2, obj2.userData()); + obj2.setUserData((QTextBlockUserData *)0); + QCOMPARE((QTextBlockUserData *)0, obj2.userData()); + + // int QTextBlock::userState() + // void QTextBlock::setUserState(int) + obj2.setUserState(0); + QCOMPARE(0, obj2.userState()); + obj2.setUserState(INT_MIN); + QCOMPARE(INT_MIN, obj2.userState()); + obj2.setUserState(INT_MAX); + QCOMPARE(INT_MAX, obj2.userState()); +} + +class TestTextObject : public QTextObject +{ +public: + TestTextObject(QTextDocument *document) : QTextObject(document) {} +}; + +void tst_QTextObject::testStandAloneTextObject() +{ + QTextDocument document; + TestTextObject textObject(&document); + + QCOMPARE(textObject.document(), &document); + // don't crash + textObject.format(); + textObject.formatIndex(); + QCOMPARE(textObject.objectIndex(), -1); +} + +QTEST_MAIN(tst_QTextObject) +#include "tst_qtextobject.moc" diff --git a/tests/auto/gui/text/qtextodfwriter/.gitignore b/tests/auto/gui/text/qtextodfwriter/.gitignore new file mode 100644 index 0000000000..791445d7a9 --- /dev/null +++ b/tests/auto/gui/text/qtextodfwriter/.gitignore @@ -0,0 +1 @@ +tst_qtextodfwriter diff --git a/tests/auto/gui/text/qtextodfwriter/qtextodfwriter.pro b/tests/auto/gui/text/qtextodfwriter/qtextodfwriter.pro new file mode 100644 index 0000000000..25bb5a5ed0 --- /dev/null +++ b/tests/auto/gui/text/qtextodfwriter/qtextodfwriter.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += core-private gui-private +SOURCES += tst_qtextodfwriter.cpp + +!symbian:DEFINES += SRCDIR=\\\"$$PWD\\\" +symbian:INCLUDEPATH+=$$[QT_INSTALL_PREFIX]/include/QtGui/private diff --git a/tests/auto/gui/text/qtextodfwriter/tst_qtextodfwriter.cpp b/tests/auto/gui/text/qtextodfwriter/tst_qtextodfwriter.cpp new file mode 100644 index 0000000000..765afce66e --- /dev/null +++ b/tests/auto/gui/text/qtextodfwriter/tst_qtextodfwriter.cpp @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtTest/QtTest> +#include <QTextDocument> +#include <QTextCursor> +#include <QTextBlock> +#include <QTextList> +#include <QTextTable> +#include <QBuffer> +#include <QDebug> + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "." +#endif + +#include <private/qtextodfwriter_p.h> + +class tst_QTextOdfWriter : public QObject +{ + Q_OBJECT +public slots: + void init(); + void cleanup(); + +private slots: + void testWriteParagraph_data(); + void testWriteParagraph(); + void testWriteStyle1_data(); + void testWriteStyle1(); + void testWriteStyle2(); + void testWriteList(); + void testWriteList2(); + void createArchive(); + void testWriteAll(); + void testWriteSection(); + void testWriteTable(); + +private: + /// closes the document and returns the part of the XML stream that the test wrote + QString getContentFromXml(); + +private: + QTextDocument *document; + QXmlStreamWriter *xmlWriter; + QTextOdfWriter *odfWriter; + QBuffer *buffer; +}; + +void tst_QTextOdfWriter::init() +{ + document = new QTextDocument(); + odfWriter = new QTextOdfWriter(*document, 0); + + buffer = new QBuffer(); + buffer->open(QIODevice::WriteOnly); + xmlWriter = new QXmlStreamWriter(buffer); + xmlWriter->writeNamespace(odfWriter->officeNS, "office"); + xmlWriter->writeNamespace(odfWriter->textNS, "text"); + xmlWriter->writeNamespace(odfWriter->styleNS, "style"); + xmlWriter->writeNamespace(odfWriter->foNS, "fo"); + xmlWriter->writeNamespace(odfWriter->tableNS, "table"); + xmlWriter->writeStartDocument(); + xmlWriter->writeStartElement("dummy"); +} + +void tst_QTextOdfWriter::cleanup() +{ + delete document; + delete odfWriter; + delete xmlWriter; + delete buffer; +} + +QString tst_QTextOdfWriter::getContentFromXml() +{ + xmlWriter->writeEndDocument(); + buffer->close(); + QString stringContent = QString::fromUtf8(buffer->data()); + QString ret; + int index = stringContent.indexOf("<dummy"); + if (index > 0) { + index = stringContent.indexOf('>', index); + if (index > 0) + ret = stringContent.mid(index+1, stringContent.length() - index - 10); + } + return ret; +} + +void tst_QTextOdfWriter::testWriteParagraph_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<QString>("xml"); + + QTest::newRow("empty") << "" << + "<text:p text:style-name=\"p1\"/>"; + QTest::newRow("spaces") << "foobar word" << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">foobar <text:s text:c=\"2\"/>word</text:span></text:p>"; + QTest::newRow("starting spaces") << " starting spaces" << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\"><text:s text:c=\"2\"/>starting spaces</text:span></text:p>"; + QTest::newRow("trailing spaces") << "trailing spaces " << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">trailing spaces <text:s/></text:span></text:p>"; + QTest::newRow("tab") << "word\ttab x" << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">word<text:tab/>tab x</text:span></text:p>"; + QTest::newRow("tab2") << "word\t\ttab\tx" << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">word<text:tab/><text:tab/>tab<text:tab/>x</text:span></text:p>"; + QTest::newRow("misc") << "foobar word\ttab x" << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">foobar <text:s text:c=\"2\"/>word<text:tab/>tab x</text:span></text:p>"; + QTest::newRow("misc2") << "\t \tFoo" << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\"><text:tab/> <text:s text:c=\"4\"/><text:tab/>Foo</text:span></text:p>"; + QTest::newRow("linefeed") << QString("line1%1line2").arg(QChar(0x2028)) << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">line1<text:line-break/>line2</text:span></text:p>"; + QTest::newRow("spaces") << "The quick brown fox jumped over the lazy dog" << + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">The quick brown fox jumped over the lazy dog</text:span></text:p>"; +} + +void tst_QTextOdfWriter::testWriteParagraph() +{ + QFETCH(QString, input); + QFETCH(QString, xml); + + QTextCursor cursor(document); + cursor.insertText(input); + + odfWriter->writeBlock(*xmlWriter, document->begin()); + QCOMPARE( getContentFromXml(), xml); +} + +void tst_QTextOdfWriter::testWriteStyle1_data() +{ + QTest::addColumn<QString>("htmlInput"); + QTest::addColumn<int>("cursorPosition"); + QTest::addColumn<QString>("xml"); + + QString text1 = "Normal<b>bold</b><i>italic</i><b><i>Bold/Italic</i></b>"; + QTest::newRow("normal") << text1 << 2 << + "<style:style style:name=\"c4\" style:family=\"text\"><style:text-properties fo:font-family=\"Sans\"/></style:style>"; + QTest::newRow("bold") << text1 << 10 << + "<style:style style:name=\"c4\" style:family=\"text\"><style:text-properties fo:font-weight=\"bold\" fo:font-family=\"Sans\"/></style:style>"; + QTest::newRow("italic") << text1 << 14 << + "<style:style style:name=\"c4\" style:family=\"text\"><style:text-properties fo:font-style=\"italic\" fo:font-family=\"Sans\"/></style:style>"; + QTest::newRow("bold+italic") << text1 << 25 << + "<style:style style:name=\"c4\" style:family=\"text\"><style:text-properties fo:font-style=\"italic\" fo:font-weight=\"bold\" fo:font-family=\"Sans\"/></style:style>"; + QString colorText = "<span style=\"color: #00FF00; background-color: #FF0000;\"> Color Text </span>"; + QTest::newRow("green/red") << colorText << 3 << + "<style:style style:name=\"c4\" style:family=\"text\"><style:text-properties fo:font-family=\"Sans\" fo:color=\"#00ff00\" fo:background-color=\"#ff0000\"/></style:style>"; + +} + +void tst_QTextOdfWriter::testWriteStyle1() +{ + QFETCH(QString, htmlInput); + QFETCH(int, cursorPosition); + QFETCH(QString, xml); + document->setHtml(htmlInput); + + QTextCursor cursor(document); + cursor.setPosition(cursorPosition); + odfWriter->writeCharacterFormat(*xmlWriter, cursor.charFormat(), 4); + QCOMPARE( getContentFromXml(), xml); +} + +void tst_QTextOdfWriter::testWriteStyle2() +{ + QTextBlockFormat bf; // = cursor.blockFormat(); + QList<QTextOption::Tab> tabs; + QTextOption::Tab tab1(40, QTextOption::RightTab); + tabs << tab1; + QTextOption::Tab tab2(80, QTextOption::DelimiterTab, 'o'); + tabs << tab2; + bf.setTabPositions(tabs); + + odfWriter->writeBlockFormat(*xmlWriter, bf, 1); + QString xml = QString::fromLatin1( + "<style:style style:name=\"p1\" style:family=\"paragraph\">" + "<style:paragraph-properties>" + "<style:tab-stops>" + "<style:tab-stop style:position=\"30pt\" style:type=\"right\"/>" + "<style:tab-stop style:position=\"60pt\" style:type=\"char\" style:char=\"o\"/>" + "</style:tab-stops>" + "</style:paragraph-properties>" + "</style:style>"); + QCOMPARE(getContentFromXml(), xml); +} + +void tst_QTextOdfWriter::testWriteList() +{ + QTextCursor cursor(document); + QTextList *list = cursor.createList(QTextListFormat::ListDisc); + cursor.insertText("ListItem 1"); + list->add(cursor.block()); + cursor.insertBlock(); + cursor.insertText("ListItem 2"); + list->add(cursor.block()); + + odfWriter->writeBlock(*xmlWriter, cursor.block()); + QString xml = QString::fromLatin1( + "<text:list text:style-name=\"L2\">" + "<text:list-item>" + //"<text:numbered-paragraph text:style-name=\"L2\" text:level=\"1\">" + //"<text:number>")+ QChar(0x25cf) + QString::fromLatin1("</text:number>" // 0x25cf is a bullet + "<text:p text:style-name=\"p3\"><text:span text:style-name=\"c0\">ListItem 2</text:span></text:p>" + "</text:list-item>" + "</text:list>"); + + QCOMPARE(getContentFromXml(), xml); +} + +void tst_QTextOdfWriter::testWriteList2() +{ + QTextCursor cursor(document); + QTextList *list = cursor.createList(QTextListFormat::ListDisc); + cursor.insertText("Cars"); + list->add(cursor.block()); + cursor.insertBlock(); + QTextListFormat level2; + level2.setStyle(QTextListFormat::ListSquare); + level2.setIndent(2); + QTextList *list2 = cursor.createList(level2); + cursor.insertText("Model T"); + list2->add(cursor.block()); + cursor.insertBlock(); + cursor.insertText("Kitt"); + list2->add(cursor.block()); + cursor.insertBlock(); + cursor.insertText("Animals"); + list->add(cursor.block()); + + cursor.insertBlock(QTextBlockFormat(), QTextCharFormat()); // start a new completely unrelated list. + QTextList *list3 = cursor.createList(QTextListFormat::ListDecimal); + cursor.insertText("Foo"); + list3->add(cursor.block()); + + // and another block thats NOT in a list. + cursor.insertBlock(QTextBlockFormat(), QTextCharFormat()); + cursor.insertText("Bar"); + + odfWriter->writeFrame(*xmlWriter, document->rootFrame()); + QString xml = QString::fromLatin1( + "<text:list text:style-name=\"L2\">" + "<text:list-item>" + //"<text:numbered-paragraph text:style-name=\"L2\" text:level=\"1\">" + //"<text:number>")+ QChar(0x25cf) + QString::fromLatin1("</text:number>" // 0x25cf is a bullet + "<text:p text:style-name=\"p3\"><text:span text:style-name=\"c0\">Cars</text:span></text:p>" + "</text:list-item>" + "<text:list-item>" + "<text:list text:style-name=\"L4\">" + "<text:list-item>" + "<text:p text:style-name=\"p5\"><text:span text:style-name=\"c0\">Model T</text:span></text:p>" + "</text:list-item>" + "<text:list-item>" + "<text:p text:style-name=\"p5\"><text:span text:style-name=\"c0\">Kitt</text:span></text:p>" + "</text:list-item>" + "</text:list>" + "</text:list-item>" + "<text:list-item>" + "<text:p text:style-name=\"p3\"><text:span text:style-name=\"c0\">Animals</text:span></text:p>" + "</text:list-item>" + "</text:list>" + "<text:list text:style-name=\"L6\">" + "<text:list-item>" + "<text:p text:style-name=\"p7\"><text:span text:style-name=\"c0\">Foo</text:span></text:p>" + "</text:list-item>" + "</text:list>" + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">Bar</text:span></text:p>"); + + // QString x = getContentFromXml(); + // for (int i=0; i < x.length(); i+=150) qDebug() << x.mid(i, 150); + QCOMPARE(getContentFromXml(), xml); +} + + +void tst_QTextOdfWriter::createArchive() +{ + document->setPlainText("a"); // simple doc is enough ;) + QTextOdfWriter writer(*document, buffer); + QCOMPARE(writer.createArchive(), true); // default + writer.writeAll(); +/* +QFile file("createArchive-odt"); +file.open(QIODevice::WriteOnly); +file.write(buffer->data()); +file.close(); +*/ + QVERIFY(buffer->data().length() > 80); + QCOMPARE(buffer->data()[0], 'P'); // its a zip :) + QCOMPARE(buffer->data()[1], 'K'); + QString mimetype(buffer->data().mid(38, 39)); + QCOMPARE(mimetype, QString::fromLatin1("application/vnd.oasis.opendocument.text")); +} + +void tst_QTextOdfWriter::testWriteAll() +{ + document->setPlainText("a"); // simple doc is enough ;) + QTextOdfWriter writer(*document, buffer); + QCOMPARE(writer.createArchive(), true); + writer.setCreateArchive(false); + writer.writeAll(); + QString result = QString(buffer->data()); + // details we check elsewhere, all we have to do is check availability. + QVERIFY(result.indexOf("office:automatic-styles") >= 0); + QVERIFY(result.indexOf("<style:style style:name=\"p1\"") >= 0); + QVERIFY(result.indexOf("<style:style style:name=\"c0\"") >= 0); + QVERIFY(result.indexOf("office:body") >= 0); + QVERIFY(result.indexOf("office:text") >= 0); + QVERIFY(result.indexOf("style:style") >= 0); +} + +void tst_QTextOdfWriter::testWriteSection() +{ + QTextCursor cursor(document); + cursor.insertText("foo\nBar"); + QTextFrameFormat ff; + cursor.insertFrame(ff); + cursor.insertText("baz"); + + odfWriter->writeFrame(*xmlWriter, document->rootFrame()); + QString xml = QString::fromLatin1( + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">foo</text:span></text:p>" + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">Bar</text:span></text:p>" + "<text:section>" + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">baz</text:span></text:p>" + "</text:section>" + "<text:p text:style-name=\"p1\"/>"); + + QCOMPARE(getContentFromXml(), xml); +} + +void tst_QTextOdfWriter::testWriteTable() +{ + // create table with merged cells + QTextCursor cursor(document); + QTextTable * table = cursor.insertTable(3, 3); + table->mergeCells(1, 0, 2, 2); + table->mergeCells(0, 1, 1, 2); + cursor = table->cellAt(0, 0).firstCursorPosition(); + cursor.insertText("a"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("b"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("c"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("d"); + cursor.movePosition(QTextCursor::NextCell); + cursor.insertText("e"); + /* + +-+---+ + |a|b | + +-+-+-+ + |c |d| + + +-+ + | |e| + +-+-+-+ + */ + + odfWriter->writeFrame(*xmlWriter, document->rootFrame()); + QString xml = QString::fromLatin1( + "<text:p text:style-name=\"p1\"/>" + "<table:table>" + "<table:table-column table:number-columns-repeated=\"3\"/>" + "<table:table-row>" + "<table:table-cell table:style-name=\"T3\">" + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">a</text:span></text:p>" + "</table:table-cell>" + "<table:table-cell table:number-columns-spanned=\"2\" table:style-name=\"T6\">" + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c7\">b</text:span></text:p>" + "</table:table-cell>" + "</table:table-row>" + "<table:table-row>" + "<table:table-cell table:number-columns-spanned=\"2\" table:number-rows-spanned=\"2\" table:style-name=\"T5\">" + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c8\">c</text:span></text:p>" + "</table:table-cell>" + "<table:table-cell table:style-name=\"T3\">" + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">d</text:span></text:p>" + "</table:table-cell>" + "</table:table-row>" + "<table:table-row>" + "<table:table-cell table:style-name=\"T3\">" + "<text:p text:style-name=\"p1\"><text:span text:style-name=\"c0\">e</text:span></text:p>" + "</table:table-cell>" + "</table:table-row>" + "</table:table>" + "<text:p text:style-name=\"p1\"/>"); + + QCOMPARE(getContentFromXml(), xml); +} + +QTEST_MAIN(tst_QTextOdfWriter) +#include "tst_qtextodfwriter.moc" diff --git a/tests/auto/gui/text/qtextpiecetable/.gitignore b/tests/auto/gui/text/qtextpiecetable/.gitignore new file mode 100644 index 0000000000..720b01f79f --- /dev/null +++ b/tests/auto/gui/text/qtextpiecetable/.gitignore @@ -0,0 +1 @@ +tst_qtextpiecetable diff --git a/tests/auto/gui/text/qtextpiecetable/qtextpiecetable.pro b/tests/auto/gui/text/qtextpiecetable/qtextpiecetable.pro new file mode 100644 index 0000000000..cfbbe2bca5 --- /dev/null +++ b/tests/auto/gui/text/qtextpiecetable/qtextpiecetable.pro @@ -0,0 +1,9 @@ +load(qttest_p4) +QT += widgets widgets-private +QT += core-private gui-private +SOURCES += tst_qtextpiecetable.cpp +HEADERS += ../qtextdocument/common.h + +requires(!win32) +requires(contains(QT_CONFIG,private_tests)) + diff --git a/tests/auto/gui/text/qtextpiecetable/tst_qtextpiecetable.cpp b/tests/auto/gui/text/qtextpiecetable/tst_qtextpiecetable.cpp new file mode 100644 index 0000000000..ddaf84134d --- /dev/null +++ b/tests/auto/gui/text/qtextpiecetable/tst_qtextpiecetable.cpp @@ -0,0 +1,1155 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + +#define protected public + +#include <qtextdocument.h> +#undef protected +#include <private/qtextdocument_p.h> +#include <qabstracttextdocumentlayout.h> +#include <qtextobject.h> +#include <qdebug.h> +#include <stdlib.h> +#include <qtextcursor.h> +#include "../qtextdocument/common.h" + +//TESTED_FILES=gui/text/qtextdocument_p.cpp gui/text/qtextdocument_p.h + +class tst_QTextPieceTable : public QObject +{ + Q_OBJECT + +public: + tst_QTextPieceTable(); + + +public slots: + void init(); + void cleanup(); +private slots: + void insertion1(); + void insertion2(); + void insertion3(); + void insertion4(); + void insertion5(); + + void removal1(); + void removal2(); + void removal3(); + void removal4(); + + void undoRedo1(); + void undoRedo2(); + void undoRedo3(); + void undoRedo4(); + void undoRedo5(); + void undoRedo6(); + void undoRedo7(); + void undoRedo8(); + void undoRedo9(); + void undoRedo10(); + void undoRedo11(); + + void checkDocumentChanged(); + void checkDocumentChanged2(); + void setBlockFormat(); + + void blockInsertion(); + void blockInsertion2(); + + void blockRemoval1(); + void blockRemoval2(); + void blockRemoval3(); + void blockRemoval4(); + void blockRemoval5(); + + void checkBlockSeparation(); + + void checkFrames1(); + void removeFrameDirect(); + void removeWithChildFrame(); + void clearWithFrames(); + +private: + QTextDocument *doc; + QTextDocumentPrivate *table; + int blockFormatIndex; + int charFormatIndex; +}; + +tst_QTextPieceTable::tst_QTextPieceTable() +{ doc = 0; table = 0; } + + +void tst_QTextPieceTable::init() +{ + doc = new QTextDocument(0); + table = doc->docHandle(); + blockFormatIndex = table->formatCollection()->indexForFormat(QTextBlockFormat()); + charFormatIndex = table->formatCollection()->indexForFormat(QTextCharFormat()); +} + +void tst_QTextPieceTable::cleanup() +{ + delete doc; + doc = 0; +} + +void tst_QTextPieceTable::insertion1() +{ + table->insert(0, "aacc", charFormatIndex); + QCOMPARE(table->plainText(), QString("aacc")); + table->insert(2, "bb", charFormatIndex); + QCOMPARE(table->plainText(), QString("aabbcc")); + table->insert(1, "1", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1abbcc")); + table->insert(6, "d", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1abbcdc")); + table->insert(8, "z", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1abbcdcz")); +} + +void tst_QTextPieceTable::insertion2() +{ + table->insert(0, "bb", charFormatIndex); + QCOMPARE(table->plainText(), QString("bb")); +} + +void tst_QTextPieceTable::insertion3() +{ + QString compare; + for (int i = 0; i < 20000; ++i) { + int pos = rand() % (i+1); + QChar c((unsigned short)(i & 0xff) + 1); + QString str; + str += c; + table->insert(pos, str, charFormatIndex); + compare.insert(pos, str); + } + QVERIFY(table->plainText() == compare); +} + +void tst_QTextPieceTable::insertion4() +{ + QString compare; + for (int i = 0; i < 20000; ++i) { + int pos = rand() % (i+1); + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + str += c; + str += c; + table->insert(pos, str, charFormatIndex); + compare.insert(pos, str); + // if (table->text() != compare) { + // qDebug("compare failed: i=%d (current char=%c) insert at %d\nexpected '%s'\ngot '%s'", i, (i % 26) + (i>25?'A':'a'), pos, compare.latin1(), table->text().latin1()); + // exit(12); + // } + } + QVERIFY(table->plainText() == compare); +} + +void tst_QTextPieceTable::insertion5() +{ + QString compare; + for (int i = 0; i < 20000; ++i) { + int pos = rand() % (i+1); + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + str += c; + str += c; + if (c == 'a') { + table->insertBlock(pos, blockFormatIndex, charFormatIndex); + str = QChar(QChar::ParagraphSeparator); + } else { + table->insert(pos, str, charFormatIndex); + } + compare.insert(pos, str); + } + QVERIFY(table->plainText() == compare); + for (QTextBlock it = table->blocksBegin(); it != table->blocksEnd(); it = it.next()) { + QTextDocumentPrivate::FragmentIterator fit = table->find(it.position()); + QVERIFY(fit.position() == it.position()); + } +} + +void tst_QTextPieceTable::removal1() +{ + table->insert(0, "abbccc", charFormatIndex); + QCOMPARE(table->plainText(), QString("abbccc")); + table->remove(1, 2); + QCOMPARE(table->plainText(), QString("accc")); + table->insert(1, "1", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1ccc")); + table->remove(4, 1); + QCOMPARE(table->plainText(), QString("a1cc")); + table->insert(4, "z", charFormatIndex); + QCOMPARE(table->plainText(), QString("a1ccz")); +} + +void tst_QTextPieceTable::removal2() +{ + table->insert(0, "bb", charFormatIndex); + QCOMPARE(table->plainText(), QString("bb")); + table->remove(0, 2); + QCOMPARE(table->plainText(), QString("")); + table->insertBlock(0, blockFormatIndex, charFormatIndex); + QCOMPARE(table->plainText(), QString(QChar(QChar::ParagraphSeparator))); + table->remove(0, 1); + QCOMPARE(table->plainText(), QString("")); + + table->insert(0, "bb", charFormatIndex); + QCOMPARE(table->plainText(), QString("bb")); + table->insertBlock(1, blockFormatIndex, charFormatIndex); + QCOMPARE(table->plainText(), QString("b") + QString(QChar(QChar::ParagraphSeparator)) + QString("b")); + table->remove(1, 1); + QCOMPARE(table->plainText(), QString("bb")); +} + +void tst_QTextPieceTable::removal3() +{ + QString compare; + int l = 0; + for (int i = 0; i < 20000; ++i) { + bool remove = l && (rand() % 2); + int pos = rand() % (remove ? l : (l+1)); + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + str += c; + str += c; + if (remove && pos < table->length()) { + compare.remove(pos, 1); + table->remove(pos, 1); + } else { + compare.insert(pos, str); + table->insert(pos, str, charFormatIndex); + } + l += remove ? -1 : 2; + // if (table->text() != compare) { + // qDebug("compare failed: i=%d (current char=%c) insert at %d\nexpected '%s'\ngot '%s'", i, (i % 26) + (i>25?'A':'a'), pos, compare.latin1(), table->text().latin1()); + // exit(12); + // } + } + QVERIFY(table->plainText() == compare); +} + +void tst_QTextPieceTable::removal4() +{ + QString compare; + int l = 0; + for (int i = 0; i < 20000; ++i) { + bool remove = l && (rand() % 2); + int pos = (l > 1) ? rand() % (remove ? l-1 : l) : 0; + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + if (c != 'a') { + str += c; + str += c; + } else { + str = QChar(QChar::ParagraphSeparator); + } + if (remove && pos < table->length() - 1) { + compare.remove(pos, 1); + table->remove(pos, 1); + } else { + if (str[0] == QChar(QChar::ParagraphSeparator)) + table->insertBlock(pos, blockFormatIndex, charFormatIndex); + else + table->insert(pos, str, charFormatIndex); + compare.insert(pos, str); + } + l += remove ? -1 : 2; +// if (table->plainText() != compare) { +// qDebug("compare failed: i=%d (current char=%c) insert at %d\nexpected '%s'\ngot '%s'", i, (i % 26) + (i>25?'A':'a'), pos, compare.latin1(), table->plainText().latin1()); +// exit(12); +// } + } + QVERIFY(table->plainText() == compare); +} + +void tst_QTextPieceTable::undoRedo1() +{ + table->insert(0, "01234567", charFormatIndex); + table->insert(0, "a", charFormatIndex); + table->insert(1, "b", charFormatIndex); + QCOMPARE(table->plainText(), QString("ab01234567")); + table->undo(); + QCOMPARE(table->plainText(), QString("01234567")); + table->redo(); + QCOMPARE(table->plainText(), QString("ab01234567")); + table->undo(); + table->insert(1, "c", charFormatIndex); + QCOMPARE(table->plainText(), QString("0c1234567")); + table->undo(); + QCOMPARE(table->plainText(), QString("01234567")); + table->undo(); + QVERIFY(table->plainText().isEmpty()); +} + +void tst_QTextPieceTable::undoRedo2() +{ + table->insert(0, "01", charFormatIndex); + table->insert(1, "a", charFormatIndex); + QCOMPARE(table->plainText(), QString("0a1")); + table->undo(); + QCOMPARE(table->plainText(), QString("01")); + table->undo(); + QCOMPARE(table->plainText(), QString("")); + table->redo(); + QCOMPARE(table->plainText(), QString("01")); + table->redo(); + QCOMPARE(table->plainText(), QString("0a1")); +} + +void tst_QTextPieceTable::undoRedo3() +{ + table->insert(0, "01", charFormatIndex); + table->insert(2, "ab", charFormatIndex); + table->remove(2, 1); + QCOMPARE(table->plainText(), QString("01b")); + table->undo(); + QCOMPARE(table->plainText(), QString("01ab")); + table->undo(); + QVERIFY(table->plainText().isEmpty()); + table->redo(); + QCOMPARE(table->plainText(), QString("01ab")); + table->redo(); + QCOMPARE(table->plainText(), QString("01b")); +} + +void tst_QTextPieceTable::undoRedo4() +{ + table->insert(0, "01", charFormatIndex); + table->insert(0, "ab", charFormatIndex); + table->remove(0, 1); + QCOMPARE(table->plainText(), QString("b01")); + table->undo(); + QCOMPARE(table->plainText(), QString("ab01")); + table->undo(); + QCOMPARE(table->plainText(), QString("01")); + table->undo(); + QCOMPARE(table->plainText(), QString("")); + table->redo(); + QCOMPARE(table->plainText(), QString("01")); + table->redo(); + QCOMPARE(table->plainText(), QString("ab01")); + table->redo(); + QCOMPARE(table->plainText(), QString("b01")); +} + +void tst_QTextPieceTable::undoRedo5() +{ + table->beginEditBlock(); + table->insert(0, "01", charFormatIndex); + table->remove(1, 1); + table->endEditBlock(); + QCOMPARE(table->plainText(), QString("0")); + table->undo(); + QCOMPARE(table->plainText(), QString("")); +} + +void tst_QTextPieceTable::undoRedo6() +{ + // this is essentially a test for the undoStack[undoPosition - 1].block = false in PieceTable::endUndoBlock() + QTextDocument doc; + QTextCursor cursor(&doc); + cursor.insertText("Hello World"); + + cursor.insertBlock(); + cursor.insertText("Hello World2"); + + cursor.movePosition(QTextCursor::Start); + QTextBlockFormat bfmt; + bfmt.setAlignment(Qt::AlignHCenter); + cursor.setBlockFormat(bfmt); + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); + + QTextCursor range = cursor; + range.clearSelection(); + range.movePosition(QTextCursor::Start); + range.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + + QTextCharFormat modifier; + modifier.setFontItalic(true); + range.mergeCharFormat(modifier); + + cursor.movePosition(QTextCursor::Start); + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); + + doc.undo(); + + QVERIFY(cursor.blockFormat().alignment() == Qt::AlignHCenter); +} + +void tst_QTextPieceTable::undoRedo7() +{ + table->insert(0, "a", charFormatIndex); + table->insert(1, "b", charFormatIndex); + QCOMPARE(table->plainText(), QString("ab")); + + table->undo(); + QVERIFY(table->plainText().isEmpty()); +} + +void tst_QTextPieceTable::undoRedo8() +{ + table->insert(0, "a", charFormatIndex); + table->insert(1, "b", charFormatIndex); + QCOMPARE(table->plainText(), QString("ab")); + + table->remove(0, 1); + table->remove(0, 1); + + QVERIFY(table->plainText().isEmpty()); + table->undo(); + QCOMPARE(table->plainText(), QString("ab")); +} + +void tst_QTextPieceTable::undoRedo9() +{ + table->insert(0, "a", charFormatIndex); + table->insert(1, "b", charFormatIndex); + QCOMPARE(table->plainText(), QString("ab")); + + table->remove(1, 1); + table->remove(0, 1); + + QVERIFY(table->plainText().isEmpty()); + table->undo(); + QCOMPARE(table->plainText(), QString("ab")); +} + +void tst_QTextPieceTable::undoRedo10() +{ + // testcase for the beginUndoBlock/endUndoBlock calls being surrounded by an if (undoEnabled) + QTextCharFormat cf; + cf.setForeground(Qt::blue); + int cfIdx = table->formatCollection()->indexForFormat(cf); + + QTextBlockFormat f; + int idx = table->formatCollection()->indexForFormat(f); + + table->insert(0, "a", cfIdx); + table->insertBlock(1, idx, cfIdx); + table->insert(1, "b", cfIdx); + + cf.setForeground(Qt::red); + int newCfIdx = table->formatCollection()->indexForFormat(cf); + + table->setCharFormat(0, 3, cf, QTextDocumentPrivate::MergeFormat); + + QCOMPARE(table->find(0).value()->format, newCfIdx); + + table->undo(); + + QCOMPARE(table->find(0).value()->format, cfIdx); +} + +void tst_QTextPieceTable::undoRedo11() +{ + srand(3); + const int loops = 20; + QString compare; + int l = 0; + for (int i = 0; i < loops; ++i) { + bool remove = l && (rand() % 2); + int pos = (l > 1) ? rand() % (remove ? l-1 : l) : 0; + QChar c((unsigned short)((i % 26) + (i>25?'A':'a'))); + QString str; + str += c; + str += c; + if (remove) { + compare.remove(pos, 1); + table->remove(pos, 1); + } else { + compare.insert(pos, str); + table->insert(pos, str, charFormatIndex); + } + l += remove ? -1 : 2; + } + QVERIFY(table->plainText() == compare); + for (int i = 0; i < loops; ++i) + table->undo(); + QVERIFY(table->plainText() == QString("")); + for (int i = 0; i < loops; ++i) + table->redo(); + QVERIFY(table->plainText() == compare); +} + + +void tst_QTextPieceTable::checkDocumentChanged() +{ + table->enableUndoRedo(false); + QTestDocumentLayout *layout = new QTestDocumentLayout(doc); + doc->setDocumentLayout(layout); + + // single insert + layout->expect(0, 0, 15); + table->insert(0, "012345678901234", charFormatIndex); + QVERIFY(!layout->error); + + // single remove + layout->expect(0, 5, 0); + table->remove(0, 5); + QVERIFY(!layout->error); + + // symmetric insert/remove + layout->expect(0, 0, 0); + table->beginEditBlock(); + table->insert(0, "01234", charFormatIndex); + table->remove(0, 5); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 5, 5); + table->beginEditBlock(); + table->remove(0, 5); + table->insert(0, "01234", charFormatIndex); + table->endEditBlock(); + QVERIFY(!layout->error); + + // replace + layout->expect(0, 3, 5); + table->beginEditBlock(); + table->remove(0, 3); + table->insert(0, "01234", charFormatIndex); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 0, 2); + table->beginEditBlock(); + table->insert(0, "01234", charFormatIndex); + table->remove(0, 3); + table->endEditBlock(); + QVERIFY(!layout->error); + + // insert + remove inside insert block + layout->expect(0, 0, 2); + table->beginEditBlock(); + table->insert(0, "01234", charFormatIndex); + table->remove(1, 3); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 0, 2); + table->beginEditBlock(); + table->insert(0, "01234", charFormatIndex); + table->remove(2, 3); + table->endEditBlock(); + QVERIFY(!layout->error); + + // insert + remove partly outside + layout->expect(0, 1, 0); + table->beginEditBlock(); + table->insert(1, "0", charFormatIndex); + table->remove(0, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 1, 1); + table->beginEditBlock(); + table->insert(1, "01", charFormatIndex); + table->remove(0, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 1, 2); + table->beginEditBlock(); + table->insert(1, "012", charFormatIndex); + table->remove(0, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(1, 1, 0); + table->beginEditBlock(); + table->insert(1, "0", charFormatIndex); + table->remove(1, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(1, 1, 1); + table->beginEditBlock(); + table->insert(1, "01", charFormatIndex); + table->remove(2, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(1, 1, 2); + table->beginEditBlock(); + table->insert(1, "012", charFormatIndex); + table->remove(3, 2); + table->endEditBlock(); + QVERIFY(!layout->error); + + // insert + remove non overlapping + layout->expect(0, 1, 1); + table->beginEditBlock(); + table->insert(1, "0", charFormatIndex); + table->remove(0, 1); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 2, 2); + table->beginEditBlock(); + table->insert(2, "1", charFormatIndex); + table->remove(0, 1); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 2, 2); + table->beginEditBlock(); + table->remove(0, 1); + table->insert(1, "0", charFormatIndex); + table->endEditBlock(); + QVERIFY(!layout->error); + + layout->expect(0, 3, 3); + table->beginEditBlock(); + table->remove(0, 1); + table->insert(2, "1", charFormatIndex); + table->endEditBlock(); + + + layout->expect(0, 3, 3); + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + table->beginEditBlock(); + table->setCharFormat(0, 1, fmt); + table->setCharFormat(2, 1, fmt); + table->endEditBlock(); + QVERIFY(!layout->error); +} + +void tst_QTextPieceTable::checkDocumentChanged2() +{ + QTestDocumentLayout *layout = new QTestDocumentLayout(doc); + doc->setDocumentLayout(layout); + + QTextCharFormat fmt; + fmt.setForeground(Qt::blue); + int anotherCharFormatIndex = table->formatCollection()->indexForFormat(fmt); + + layout->expect(0, 0, 12); + table->beginEditBlock(); + table->insert(0, "0123", charFormatIndex); + table->insert(4, "4567", anotherCharFormatIndex); + table->insert(8, "8901", charFormatIndex); + table->endEditBlock(); + QVERIFY(!layout->error); + + fmt.setFontItalic(true); + + layout->expect(1, 10, 10); + table->beginEditBlock(); + table->setCharFormat(8, 3, fmt); + table->setCharFormat(4, 4, fmt); + table->setCharFormat(1, 3, fmt); + table->endEditBlock(); + QVERIFY(!layout->error); +} + +void tst_QTextPieceTable::setBlockFormat() +{ + QTextBlockFormat bfmt; + int index = table->formatCollection()->indexForFormat(bfmt); + + table->insertBlock(0, index, charFormatIndex); + table->insertBlock(0, index, charFormatIndex); + table->insertBlock(0, index, charFormatIndex); + + QTextBlockFormat newbfmt = bfmt; + newbfmt.setAlignment(Qt::AlignRight); + index = table->formatCollection()->indexForFormat(bfmt); + QTextBlock b = table->blocksFind(1); + table->setBlockFormat(b, b, newbfmt); + + QVERIFY(table->blocksFind(0).blockFormat() == bfmt); + QVERIFY(table->blocksFind(1).blockFormat() == newbfmt); + QVERIFY(table->blocksFind(2).blockFormat() == bfmt); +} + + +void tst_QTextPieceTable::blockInsertion() +{ + QTextBlockFormat fmt; + fmt.setTopMargin(100); + int idx = table->formatCollection()->indexForFormat(fmt); + int charFormat = table->formatCollection()->indexForFormat(QTextCharFormat()); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + + table->insertBlock(0, idx, charFormat); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).blockFormat() == fmt); + + table->undo(); + QVERIFY(table->blockMap().length() == 1); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + + table->redo(); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).blockFormat() == fmt); +} + +void tst_QTextPieceTable::blockInsertion2() +{ + // caused evil failing assertion in fragmentmap + int pos = 0; + table->insertBlock(pos, blockFormatIndex, charFormatIndex); + pos += 1; + table->insert(pos, "a", charFormatIndex); + pos += 1; + + pos -= 1; + table->insertBlock(pos, blockFormatIndex, charFormatIndex); + QCOMPARE(table->blocksFind(0).position(), 0); + QCOMPARE(table->blocksFind(1).position(), 1); + QCOMPARE(table->blocksFind(2).position(), 2); +} + +/* + Tests correct removal behaviour when deleting over block boundaries or complete blocks. +*/ + +void tst_QTextPieceTable::blockRemoval1() +{ + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->beginEditBlock(); + table->remove(5, 5); + table->endEditBlock(); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt2); + QVERIFY(table->blocksFind(4).position() == 0); + QVERIFY(table->blocksFind(5).position() == 5); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt2); + QVERIFY(table->blocksFind(4).position() == 0); + QVERIFY(table->blocksFind(5).position() == 5); +} + +void tst_QTextPieceTable::blockRemoval2() +{ + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->remove(4, 1); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(6).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).position() == 0); + QVERIFY(table->blocksFind(6).position() == 0); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(6).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).position() == 0); + QVERIFY(table->blocksFind(6).position() == 0); +} + +void tst_QTextPieceTable::blockRemoval3() +{ + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->beginEditBlock(); + table->remove(3, 4); + table->endEditBlock(); + + QVERIFY(table->blocksFind(1).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(1).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); +} + +void tst_QTextPieceTable::blockRemoval4() +{ +#if 0 + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->remove(3, 7); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); + QVERIFY(table->blocksFind(1).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); + QVERIFY(table->blocksFind(1).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); +#endif +} + +void tst_QTextPieceTable::blockRemoval5() +{ + QTextBlockFormat fmt1; + fmt1.setTopMargin(100); + QTextBlockFormat fmt2; + fmt2.setAlignment(Qt::AlignRight); + int idx1 = table->formatCollection()->indexForFormat(fmt1); + int idx2 = table->formatCollection()->indexForFormat(fmt2); + + table->insert(0, "0123", charFormatIndex); + table->insertBlock(4, idx1, charFormatIndex); + table->insert(5, "5678", charFormatIndex); + table->insertBlock(9, idx2, charFormatIndex); + table->insert(10, "0123", charFormatIndex); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->beginEditBlock(); + table->remove(3, 8); + table->endEditBlock(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); + + table->undo(); + + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(4).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == fmt1); + QVERIFY(table->blocksFind(10).blockFormat() == fmt2); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(6).position() == 5); + QVERIFY(table->blocksFind(11).position() == 10); + + table->redo(); + QVERIFY(table->blocksFind(0).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(5).blockFormat() == QTextBlockFormat()); + QVERIFY(table->blocksFind(1).position() == 0); + QVERIFY(table->blocksFind(5).position() == 0); +} + + +void tst_QTextPieceTable::checkBlockSeparation() +{ + table->insertBlock(0, blockFormatIndex, charFormatIndex); + table->insertBlock(1, blockFormatIndex, charFormatIndex); + + QVERIFY(table->find(0) != table->find(1)); +} + +void tst_QTextPieceTable::checkFrames1() +{ + QTextFrameFormat ffmt; + table->insert(0, "Hello", charFormatIndex); + QPointer<QTextFrame> frame = table->insertFrame(1, 3, ffmt); + QTextFrame *root = table->rootFrame(); + + QVERIFY(root == frame->parentFrame()); + + QVERIFY(root); + QVERIFY(root->parentFrame() == 0); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(frame->format() == ffmt); + QVERIFY(frame->firstPosition() == 2); + QVERIFY(frame->lastPosition() == 4); + + + QPointer<QTextFrame> frame2 = table->insertFrame(2, 3, ffmt); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(root->childFrames().at(0) == frame); + QVERIFY(frame->childFrames().count() == 1); + QVERIFY(frame2->childFrames().count() == 0); + QVERIFY(frame2->parentFrame() == frame); + QVERIFY(frame2->firstPosition() == 3); + QVERIFY(frame2->lastPosition() == 4); + + QVERIFY(frame->format() == ffmt); + QVERIFY(frame->firstPosition() == 2); + QVERIFY(frame->lastPosition() == 6); + + table->removeFrame(frame); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(root->childFrames().at(0) == frame2); + QVERIFY(!frame); + QVERIFY(frame2->childFrames().count() == 0); + QVERIFY(frame2->parentFrame() == root); + QVERIFY(frame2->firstPosition() == 2); + QVERIFY(frame2->lastPosition() == 3); + + table->undo(); + + frame = table->frameAt(2); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(root->childFrames().at(0) == frame); + QVERIFY(frame->childFrames().count() == 1); + QVERIFY(frame->childFrames().at(0) == frame2); + QVERIFY(frame2->childFrames().count() == 0); + QVERIFY(frame2->parentFrame() == frame); + QVERIFY(frame2->firstPosition() == 3); + QVERIFY(frame2->lastPosition() == 4); + + QVERIFY(frame->firstPosition() == 2); + QVERIFY(frame->lastPosition() == 6); + + table->undo(); + + QVERIFY(root->childFrames().count() == 1); + QVERIFY(root->childFrames().at(0) == frame); + QVERIFY(frame->childFrames().count() == 0); + QVERIFY(!frame2); + + QVERIFY(frame->firstPosition() == 2); + QVERIFY(frame->lastPosition() == 4); +} + +void tst_QTextPieceTable::removeFrameDirect() +{ + QTextFrameFormat ffmt; + table->insert(0, "Hello", charFormatIndex); + + QTextFrame *frame = table->insertFrame(1, 5, ffmt); + + QVERIFY(frame->parentFrame() == table->rootFrame()); + + const int start = frame->firstPosition() - 1; + const int end = frame->lastPosition(); + const int length = end - start + 1; + + table->remove(start, length); +} + +void tst_QTextPieceTable::removeWithChildFrame() +{ + /* + The piecetable layout is: + + ... + 1 BeginningOfFrame(first frame) + 2 text + 3 BeginningOfFrame(second frame) + 4 text + 5 text + 6 EndOfFrame(second frame) + 7 text + 8 text + 9 EndOfFrame(first frame) + ... + + The idea is to remove from [2] until [6], basically some trailing text and the second frame. + In this case frameAt(2) != frameAt(6), so the assertion in remove() needed an adjustement. + */ + QTextFrameFormat ffmt; + table->insert(0, "Hello World", charFormatIndex); + + QTextFrame *frame = table->insertFrame(1, 6, ffmt); + QTextFrame *childFrame = table->insertFrame(3, 5, ffmt); + Q_UNUSED(frame); + Q_UNUSED(childFrame); + + // used to give a failing assertion + table->remove(2, 5); + QVERIFY(true); +} + +void tst_QTextPieceTable::clearWithFrames() +{ + /* + The piecetable layout is: + + ... + 1 BeginningOfFrame(first frame) + 2 text + 3 EndOfFrame(first frame) + 4 BeginningOfFrame(second frame) + 5 text + 6 text + 7 EndOfFrame(second frame) + ... + + The idea is to remove from [1] until [7]. + */ + QTextFrameFormat ffmt; + table->insert(0, "Hello World", charFormatIndex); + + QTextFrame *firstFrame = table->insertFrame(1, 2, ffmt); + QTextFrame *secondFrame = table->insertFrame(4, 6, ffmt); + + const int start = firstFrame->firstPosition() - 1; + const int end = secondFrame->lastPosition(); + const int length = end - start + 1; + // used to give a failing assertion + table->remove(start, length); + QVERIFY(true); +} + +QTEST_MAIN(tst_QTextPieceTable) + + +#include "tst_qtextpiecetable.moc" + diff --git a/tests/auto/gui/text/qtextscriptengine/.gitignore b/tests/auto/gui/text/qtextscriptengine/.gitignore new file mode 100644 index 0000000000..e51a335099 --- /dev/null +++ b/tests/auto/gui/text/qtextscriptengine/.gitignore @@ -0,0 +1 @@ +tst_qtextscriptengine diff --git a/tests/auto/gui/text/qtextscriptengine/generate/generate.pro b/tests/auto/gui/text/qtextscriptengine/generate/generate.pro new file mode 100644 index 0000000000..354e0e5cdf --- /dev/null +++ b/tests/auto/gui/text/qtextscriptengine/generate/generate.pro @@ -0,0 +1,14 @@ +###################################################################### +# Automatically generated by qmake (1.07a) Fri Sep 30 15:20:45 2005 +###################################################################### + +TEMPLATE = app +CONFIG -= moc +INCLUDEPATH += . /usr/include/freetype2 +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src + +# Input +SOURCES += main.cpp +CONFIG += qt warn_on debug thread create_prl link_prl + + diff --git a/tests/auto/gui/text/qtextscriptengine/generate/main.cpp b/tests/auto/gui/text/qtextscriptengine/generate/main.cpp new file mode 100644 index 0000000000..06caa34b4d --- /dev/null +++ b/tests/auto/gui/text/qtextscriptengine/generate/main.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QApplication> +#include <QTextEdit> +#include <QLineEdit> +#include <QVBoxLayout> +#include <QFontDialog> +#include <QPushButton> + +#define private public +#include <qfont.h> +#include <private/qtextengine_p.h> +#include <private/qfontengine_p.h> +#include <qtextlayout.h> +#undef private + + +class MyEdit : public QTextEdit { + Q_OBJECT +public: + MyEdit(QWidget *p) : QTextEdit(p) { setReadOnly(true); } +public slots: + void setText(const QString &str); + void changeFont(); +public: + QLineEdit *lineEdit; +}; + +void MyEdit::setText(const QString &str) +{ + if (str.isEmpty()) { + clear(); + return; + } + QTextLayout layout(str, lineEdit->font()); + QTextEngine *e = layout.d; + e->itemize(); + e->shape(0); + + QString result; + result = "Using font '" + e->fontEngine(e->layoutData->items[0])->fontDef.family + "'\n\n"; + + result += "{ { "; + for (int i = 0; i < str.length(); ++i) + result += "0x" + QString::number(str.at(i).unicode(), 16) + ", "; + result += "0x0 },\n { "; + for (int i = 0; i < e->layoutData->items[0].num_glyphs; ++i) + result += "0x" + QString::number(e->layoutData->glyphLayout.glyphs[i], 16) + ", "; + result += "0x0 } }"; + + setPlainText(result); +} + +void MyEdit::changeFont() +{ + bool ok; + QFont f = QFontDialog::getFont(&ok, lineEdit->font(), topLevelWidget()); + if (ok) + lineEdit->setFont(f); +} + +int main(int argc, char **argv) +{ + QApplication a(argc, argv); + + QWidget *mw = new QWidget(0); + QVBoxLayout *l = new QVBoxLayout(mw); + + QLineEdit *le = new QLineEdit(mw); + l->addWidget(le); + + MyEdit *view = new MyEdit(mw); + view->lineEdit = le; + l->addWidget(view); + + QPushButton *button = new QPushButton("Change Font", mw); + l->addWidget(button); + + QObject::connect(le, SIGNAL(textChanged(QString)), view, SLOT(setText(QString))); + QObject::connect(button, SIGNAL(clicked()), view, SLOT(changeFont())); + + mw->resize(500, 300); + mw->show(); + + return a.exec(); +} + + +#include <main.moc> diff --git a/tests/auto/gui/text/qtextscriptengine/qtextscriptengine.pro b/tests/auto/gui/text/qtextscriptengine/qtextscriptengine.pro new file mode 100644 index 0000000000..0f5076e2ed --- /dev/null +++ b/tests/auto/gui/text/qtextscriptengine/qtextscriptengine.pro @@ -0,0 +1,7 @@ +load(qttest_p4) + +QT += core-private gui-private + +HEADERS += +SOURCES += tst_qtextscriptengine.cpp +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src diff --git a/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp b/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp new file mode 100644 index 0000000000..cbed675cb7 --- /dev/null +++ b/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp @@ -0,0 +1,1304 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + + +#ifdef Q_WS_X11 +#define private public +#endif + +// cannot do private -> public on windows since it seems to mess up some stl headers +#include <qfont.h> + +#ifdef Q_WS_X11 +#undef private +#endif + +#include <QtTest/QtTest> + + + +#if defined(Q_WS_X11) || defined(Q_WS_MAC) +#define private public +#include <private/qtextengine_p.h> +#include <qtextlayout.h> +#undef private +#else +#include <private/qtextengine_p.h> +#include <qtextlayout.h> +#endif + +#include <qfontdatabase.h> +#include <qfontinfo.h> + + + + + +//TESTED_CLASS= +//TESTED_FILES= gui/text/qscriptengine.cpp + +class tst_QTextScriptEngine : public QObject +{ +Q_OBJECT + +public: + tst_QTextScriptEngine(); + virtual ~tst_QTextScriptEngine(); + + +public slots: + void initTestCase(); + void init(); + void cleanup(); +private slots: + void devanagari(); + void bengali(); + void gurmukhi(); + // gujarati missing + void oriya(); + void tamil(); + void telugu(); + void kannada(); + void malayalam(); + void sinhala(); + void greek(); + + void khmer(); + void linearB(); + void controlInSyllable_qtbug14204(); + void combiningMarks_qtbug15675(); + + void mirroredChars_data(); + void mirroredChars(); + +private: + bool haveTestFonts; +}; + +tst_QTextScriptEngine::tst_QTextScriptEngine() + : haveTestFonts(qgetenv("QT_HAVE_TEST_FONTS") == QByteArray("1")) +{ +} + +tst_QTextScriptEngine::~tst_QTextScriptEngine() +{ +} + +void tst_QTextScriptEngine::initTestCase() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + qWarning( + "Some of these tests depend on the internals of some test fonts which are not freely " + "distributable.\n" + "These tests will be skipped.\n" + "If you have the fonts available, set QT_HAVE_TEST_FONTS=1 in your environment and " + "run the test again." + ); + } +#endif +} + +void tst_QTextScriptEngine::init() +{ +} + +void tst_QTextScriptEngine::cleanup() +{ +} + +struct ShapeTable { + unsigned short unicode[16]; + unsigned short glyphs[16]; +}; + +#if defined(Q_WS_X11) +static bool shaping( const QFont &f, const ShapeTable *s) +{ + QString str = QString::fromUtf16( s->unicode ); + QTextLayout layout(str, f); + QTextEngine *e = layout.d; + e->itemize(); + e->shape(0); + + int nglyphs = 0; + const unsigned short *g = s->glyphs; + while ( *g ) { + nglyphs++; + g++; + } + + if( nglyphs != e->layoutData->items[0].num_glyphs ) + goto error; + + for (int i = 0; i < nglyphs; ++i) { + if ((e->layoutData->glyphLayout.glyphs[i] & 0xffffff) != s->glyphs[i]) + goto error; + } + return true; + error: + str = ""; + const unsigned short *uc = s->unicode; + while (*uc) { + str += QString("%1 ").arg(*uc, 4, 16); + ++uc; + } + qDebug("%s: shaping of string %s failed, nglyphs=%d, expected %d", + f.family().toLatin1().constData(), + str.toLatin1().constData(), + e->layoutData->items[0].num_glyphs, nglyphs); + + str = ""; + int i = 0; + while (i < e->layoutData->items[0].num_glyphs) { + str += QString("%1 ").arg(e->layoutData->glyphLayout.glyphs[i], 4, 16); + ++i; + } + qDebug(" glyph result = %s", str.toLatin1().constData()); + return false; +} +#endif + +void tst_QTextScriptEngine::devanagari() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Devanagari).contains("Raghindi")) { + QFont f("Raghindi"); + const ShapeTable shape_table [] = { + // Ka + { { 0x0915, 0x0 }, + { 0x0080, 0x0 } }, + // Ka Halant + { { 0x0915, 0x094d, 0x0 }, + { 0x0080, 0x0051, 0x0 } }, + // Ka Halant Ka + { { 0x0915, 0x094d, 0x0915, 0x0 }, + { 0x00c8, 0x0080, 0x0 } }, + // Ka MatraI + { { 0x0915, 0x093f, 0x0 }, + { 0x01d1, 0x0080, 0x0 } }, + // Ra Halant Ka + { { 0x0930, 0x094d, 0x0915, 0x0 }, + { 0x0080, 0x005b, 0x0 } }, + // Ra Halant Ka MatraI + { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 }, + { 0x01d1, 0x0080, 0x005b, 0x0 } }, + // MatraI + { { 0x093f, 0x0 }, + { 0x01d4, 0x029c, 0x0 } }, + // Ka Nukta + { { 0x0915, 0x093c, 0x0 }, + { 0x00a4, 0x0 } }, + // Ka Halant Ra + { { 0x0915, 0x094d, 0x0930, 0x0 }, + { 0x0110, 0x0 } }, + // Ka Halant Ra Halant Ka + { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 }, + { 0x0158, 0x0080, 0x0 } }, + { { 0x0930, 0x094d, 0x200d, 0x0 }, + { 0x00e2, 0x0 } }, + { { 0x0915, 0x094d, 0x0930, 0x094d, 0x200d, 0x0 }, + { 0x0158, 0x0 } }, + + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Raghindi", SkipAll); + } + } + + { + if (QFontDatabase().families(QFontDatabase::Devanagari).contains("Mangal")) { + QFont f("Mangal"); + const ShapeTable shape_table [] = { + // Ka + { { 0x0915, 0x0 }, + { 0x0080, 0x0 } }, + // Ka Halant + { { 0x0915, 0x094d, 0x0 }, + { 0x0080, 0x0051, 0x0 } }, + // Ka Halant Ka + { { 0x0915, 0x094d, 0x0915, 0x0 }, + { 0x00c8, 0x0080, 0x0 } }, + // Ka MatraI + { { 0x0915, 0x093f, 0x0 }, + { 0x01d1, 0x0080, 0x0 } }, + // Ra Halant Ka + { { 0x0930, 0x094d, 0x0915, 0x0 }, + { 0x0080, 0x005b, 0x0 } }, + // Ra Halant Ka MatraI + { { 0x0930, 0x094d, 0x0915, 0x093f, 0x0 }, + { 0x01d1, 0x0080, 0x005b, 0x0 } }, + // MatraI + { { 0x093f, 0x0 }, + { 0x01d4, 0x029c, 0x0 } }, + // Ka Nukta + { { 0x0915, 0x093c, 0x0 }, + { 0x00a4, 0x0 } }, + // Ka Halant Ra + { { 0x0915, 0x094d, 0x0930, 0x0 }, + { 0x0110, 0x0 } }, + // Ka Halant Ra Halant Ka + { { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0x0 }, + { 0x0158, 0x0080, 0x0 } }, + + { { 0x92b, 0x94d, 0x930, 0x0 }, + { 0x125, 0x0 } }, + { { 0x92b, 0x93c, 0x94d, 0x930, 0x0 }, + { 0x149, 0x0 } }, + { {0}, {0} } + }; + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find mangal", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + +void tst_QTextScriptEngine::bengali() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Bengali).contains("Akaash")) { + QFont f("Akaash"); + const ShapeTable shape_table [] = { + // Ka + { { 0x0995, 0x0 }, + { 0x0151, 0x0 } }, + // Ka Halant + { { 0x0995, 0x09cd, 0x0 }, + { 0x0151, 0x017d, 0x0 } }, + // Ka Halant Ka + { { 0x0995, 0x09cd, 0x0995, 0x0 }, + { 0x019b, 0x0 } }, + // Ka MatraI + { { 0x0995, 0x09bf, 0x0 }, + { 0x0173, 0x0151, 0x0 } }, + // Ra Halant Ka + { { 0x09b0, 0x09cd, 0x0995, 0x0 }, + { 0x0151, 0x0276, 0x0 } }, + // Ra Halant Ka MatraI + { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 }, + { 0x0173, 0x0151, 0x0276, 0x0 } }, + // Ka Nukta + { { 0x0995, 0x09bc, 0x0 }, + { 0x0151, 0x0171, 0x0 } }, + // Ka Halant Ra + { { 0x0995, 0x09cd, 0x09b0, 0x0 }, + { 0x01f4, 0x0 } }, + // Ka Halant Ra Halant Ka + { { 0x0995, 0x09cd, 0x09b0, 0x09cd, 0x0995, 0x0 }, + { 0x025c, 0x0276, 0x0151, 0x0 } }, + // Ya + Halant + { { 0x09af, 0x09cd, 0x0 }, + { 0x016a, 0x017d, 0x0 } }, + // Da Halant Ya -> Da Ya-Phala + { { 0x09a6, 0x09cd, 0x09af, 0x0 }, + { 0x01e5, 0x0 } }, + // A Halant Ya -> A Ya-phala + { { 0x0985, 0x09cd, 0x09af, 0x0 }, + { 0x0145, 0x01cf, 0x0 } }, + // Na Halant Ka + { { 0x09a8, 0x09cd, 0x0995, 0x0 }, + { 0x026f, 0x0151, 0x0 } }, + // Na Halant ZWNJ Ka + { { 0x09a8, 0x09cd, 0x200c, 0x0995, 0x0 }, + { 0x0164, 0x017d, 0x0151, 0x0 } }, + // Na Halant ZWJ Ka + { { 0x09a8, 0x09cd, 0x200d, 0x0995, 0x0 }, + { 0x026f, 0x0151, 0x0 } }, + // Ka Halant ZWNJ Ka + { { 0x0995, 0x09cd, 0x200c, 0x0995, 0x0 }, + { 0x0151, 0x017d, 0x0151, 0x0 } }, + // Ka Halant ZWJ Ka + { { 0x0995, 0x09cd, 0x200d, 0x0995, 0x0 }, + { 0x025c, 0x0151, 0x0 } }, + // Na Halant Ra + { { 0x09a8, 0x09cd, 0x09b0, 0x0 }, + { 0x0207, 0x0 } }, + // Na Halant ZWNJ Ra + { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 }, + { 0x0164, 0x017d, 0x016b, 0x0 } }, + // Na Halant ZWJ Ra + { { 0x09a8, 0x09cd, 0x200d, 0x09b0, 0x0 }, + { 0x026f, 0x016b, 0x0 } }, + // Na Halant Ba + { { 0x09a8, 0x09cd, 0x09ac, 0x0 }, + { 0x022f, 0x0 } }, + // Na Halant ZWNJ Ba + { { 0x09a8, 0x09cd, 0x200c, 0x09ac, 0x0 }, + { 0x0164, 0x017d, 0x0167, 0x0 } }, + // Na Halant ZWJ Ba + { { 0x09a8, 0x09cd, 0x200d, 0x09ac, 0x0 }, + { 0x026f, 0x0167, 0x0 } }, + // Na Halant Dha + { { 0x09a8, 0x09cd, 0x09a7, 0x0 }, + { 0x01d3, 0x0 } }, + // Na Halant ZWNJ Dha + { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 }, + { 0x0164, 0x017d, 0x0163, 0x0 } }, + // Na Halant ZWJ Dha + { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 }, + { 0x026f, 0x0163, 0x0 } }, + // Ra Halant Ka MatraAU + { { 0x09b0, 0x09cd, 0x0995, 0x09cc, 0x0 }, + { 0x0179, 0x0151, 0x0276, 0x017e, 0x0 } }, + // Ra Halant Ba Halant Ba + { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 }, + { 0x0232, 0x0276, 0x0 } }, + { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x982, 0x0 }, + { 0x151, 0x276, 0x172, 0x143, 0x0 } }, + { { 0x9b0, 0x9cd, 0x995, 0x9be, 0x983, 0x0 }, + { 0x151, 0x276, 0x172, 0x144, 0x0 } }, + // test decomposed two parts matras + { { 0x995, 0x9c7, 0x9be, 0x0 }, + { 0x179, 0x151, 0x172, 0x0 } }, + { { 0x995, 0x9c7, 0x9d7, 0x0 }, + { 0x179, 0x151, 0x17e, 0x0 } }, + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Akaash", SkipAll); + } + } + { + if (QFontDatabase().families(QFontDatabase::Bengali).contains("Mukti Narrow")) { + QFont f("Mukti Narrow"); + const ShapeTable shape_table [] = { + // Ka + { { 0x0995, 0x0 }, + { 0x0073, 0x0 } }, + // Ka Halant + { { 0x0995, 0x09cd, 0x0 }, + { 0x00b9, 0x0 } }, + // Ka Halant Ka + { { 0x0995, 0x09cd, 0x0995, 0x0 }, + { 0x0109, 0x0 } }, + // Ka MatraI + { { 0x0995, 0x09bf, 0x0 }, + { 0x0095, 0x0073, 0x0 } }, + // Ra Halant Ka + { { 0x09b0, 0x09cd, 0x0995, 0x0 }, + { 0x0073, 0x00e1, 0x0 } }, + // Ra Halant Ka MatraI + { { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0x0 }, + { 0x0095, 0x0073, 0x00e1, 0x0 } }, + // MatraI + { { 0x09bf, 0x0 }, + { 0x0095, 0x01c8, 0x0 } }, + // Ka Nukta + { { 0x0995, 0x09bc, 0x0 }, + { 0x0073, 0x0093, 0x0 } }, + // Ka Halant Ra + { { 0x0995, 0x09cd, 0x09b0, 0x0 }, + { 0x00e5, 0x0 } }, + // Ka Halant Ra Halant Ka + { { 0x995, 0x9cd, 0x9b0, 0x9cd, 0x995, 0x0 }, + { 0x234, 0x24e, 0x73, 0x0 } }, + // Ya + Halant + { { 0x09af, 0x09cd, 0x0 }, + { 0x00d2, 0x0 } }, + // Da Halant Ya -> Da Ya-Phala + { { 0x09a6, 0x09cd, 0x09af, 0x0 }, + { 0x0084, 0x00e2, 0x0 } }, + // A Halant Ya -> A Ya-phala + { { 0x0985, 0x09cd, 0x09af, 0x0 }, + { 0x0067, 0x00e2, 0x0 } }, + // Na Halant Ka + { { 0x09a8, 0x09cd, 0x0995, 0x0 }, + { 0x0188, 0x0 } }, + // Na Halant ZWNJ Ka + { { 0x9a8, 0x9cd, 0x200c, 0x995, 0x0 }, + { 0xcc, 0x73, 0x0 } }, + // Na Halant ZWJ Ka + { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, + { 0x247, 0x73, 0x0 } }, + // Ka Halant ZWNJ Ka + { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, + { 0x247, 0x73, 0x0 } }, + // Ka Halant ZWJ Ka + { { 0x9a8, 0x9cd, 0x200d, 0x995, 0x0 }, + { 0x247, 0x73, 0x0 } }, + // Na Halant Ra + { { 0x09a8, 0x09cd, 0x09b0, 0x0 }, + { 0x00f8, 0x0 } }, + // Na Halant ZWNJ Ra + { { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0x0 }, + { 0xcc, 0x8d, 0x0 } }, + // Na Halant ZWJ Ra + { { 0x9a8, 0x9cd, 0x200d, 0x9b0, 0x0 }, + { 0x247, 0x8d, 0x0 } }, + // Na Halant Ba + { { 0x09a8, 0x09cd, 0x09ac, 0x0 }, + { 0x0139, 0x0 } }, + // Na Halant ZWNJ Ba + { { 0x9a8, 0x9cd, 0x200c, 0x9ac, 0x0 }, + { 0xcc, 0x89, 0x0 } }, + // Na Halant ZWJ Ba + { { 0x9a8, 0x9cd, 0x200d, 0x9ac, 0x0 }, + { 0x247, 0x89, 0x0 } }, + // Na Halant Dha + { { 0x09a8, 0x09cd, 0x09a7, 0x0 }, + { 0x0145, 0x0 } }, + // Na Halant ZWNJ Dha + { { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0x0 }, + { 0xcc, 0x85, 0x0 } }, + // Na Halant ZWJ Dha + { { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0x0 }, + { 0x247, 0x85, 0x0 } }, + // Ra Halant Ka MatraAU + { { 0x9b0, 0x9cd, 0x995, 0x9cc, 0x0 }, + { 0x232, 0x73, 0xe1, 0xa0, 0x0 } }, + // Ra Halant Ba Halant Ba + { { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0x0 }, + { 0x013b, 0x00e1, 0x0 } }, + + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Mukti", SkipAll); + } + } + { + if (QFontDatabase().families(QFontDatabase::Bengali).contains("Likhan")) { + QFont f("Likhan"); + const ShapeTable shape_table [] = { + { { 0x9a8, 0x9cd, 0x9af, 0x0 }, + { 0x1ca, 0x0 } }, + { { 0x09b8, 0x09cd, 0x09af, 0x0 }, + { 0x020e, 0x0 } }, + { { 0x09b6, 0x09cd, 0x09af, 0x0 }, + { 0x01f4, 0x0 } }, + { { 0x09b7, 0x09cd, 0x09af, 0x0 }, + { 0x01fe, 0x0 } }, + { { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 }, + { 0x10b, 0x167, 0x0 } }, + + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Likhan", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + +void tst_QTextScriptEngine::gurmukhi() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Gurmukhi).contains("Lohit Punjabi")) { + QFont f("Lohit Punjabi"); + const ShapeTable shape_table [] = { + { { 0xA15, 0xA4D, 0xa39, 0x0 }, + { 0x3b, 0x8b, 0x0 } }, + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Lohit Punjabi", SkipAll); + } + } +#endif +} + +void tst_QTextScriptEngine::oriya() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Oriya).contains("utkal")) { + QFont f("utkal"); + const ShapeTable shape_table [] = { + { { 0xb15, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 }, + { 0x150, 0x125, 0x0 } }, + { { 0xb24, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 }, + { 0x151, 0x120, 0x0 } }, + { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 }, + { 0x152, 0x120, 0x0 } }, + { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0x0 }, + { 0x152, 0x120, 0x0 } }, + { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 }, + { 0x176, 0x0 } }, + { { 0xb38, 0xb4d, 0xb24, 0xb4d, 0xb30, 0x0 }, + { 0x177, 0x0 } }, + { { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0xb4d, 0xb2f, 0x0 }, + { 0x176, 0x124, 0x0 } }, + { {0}, {0} } + + }; + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find utkal", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + + +void tst_QTextScriptEngine::tamil() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Tamil).contains("AkrutiTml1")) { + QFont f("AkrutiTml1"); + const ShapeTable shape_table [] = { + { { 0x0b95, 0x0bc2, 0x0 }, + { 0x004e, 0x0 } }, + { { 0x0bae, 0x0bc2, 0x0 }, + { 0x009e, 0x0 } }, + { { 0x0b9a, 0x0bc2, 0x0 }, + { 0x0058, 0x0 } }, + { { 0x0b99, 0x0bc2, 0x0 }, + { 0x0053, 0x0 } }, + { { 0x0bb0, 0x0bc2, 0x0 }, + { 0x00a8, 0x0 } }, + { { 0x0ba4, 0x0bc2, 0x0 }, + { 0x008e, 0x0 } }, + { { 0x0b9f, 0x0bc2, 0x0 }, + { 0x0062, 0x0 } }, + { { 0x0b95, 0x0bc6, 0x0 }, + { 0x000a, 0x0031, 0x0 } }, + { { 0x0b95, 0x0bca, 0x0 }, + { 0x000a, 0x0031, 0x0007, 0x0 } }, + { { 0x0b95, 0x0bc6, 0x0bbe, 0x0 }, + { 0x000a, 0x0031, 0x007, 0x0 } }, + { { 0x0b95, 0x0bcd, 0x0bb7, 0x0 }, + { 0x0049, 0x0 } }, + { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bca, 0x0 }, + { 0x000a, 0x0049, 0x007, 0x0 } }, + { { 0x0b95, 0x0bcd, 0x0bb7, 0x0bc6, 0x0bbe, 0x0 }, + { 0x000a, 0x0049, 0x007, 0x0 } }, + { { 0x0b9f, 0x0bbf, 0x0 }, + { 0x005f, 0x0 } }, + { { 0x0b9f, 0x0bc0, 0x0 }, + { 0x0060, 0x0 } }, + { { 0x0bb2, 0x0bc0, 0x0 }, + { 0x00ab, 0x0 } }, + { { 0x0bb2, 0x0bbf, 0x0 }, + { 0x00aa, 0x0 } }, + { { 0x0bb0, 0x0bcd, 0x0 }, + { 0x00a4, 0x0 } }, + { { 0x0bb0, 0x0bbf, 0x0 }, + { 0x00a5, 0x0 } }, + { { 0x0bb0, 0x0bc0, 0x0 }, + { 0x00a6, 0x0 } }, + { { 0x0b83, 0x0 }, + { 0x0025, 0x0 } }, + { { 0x0b83, 0x0b95, 0x0 }, + { 0x0025, 0x0031, 0x0 } }, + { { 0xb95, 0xbc6, 0xbbe, 0x0 }, + { 0xa, 0x31, 0x7, 0x0 } }, + { { 0xb95, 0xbc7, 0xbbe, 0x0 }, + { 0xb, 0x31, 0x7, 0x0 } }, + { { 0xb95, 0xbc6, 0xbd7, 0x0 }, + { 0xa, 0x31, 0x40, 0x0 } }, + + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find AkrutiTml1", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + + +void tst_QTextScriptEngine::telugu() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Telugu).contains("Pothana2000")) { + QFont f("Pothana2000"); + const ShapeTable shape_table [] = { + { { 0xc15, 0xc4d, 0x0 }, + { 0xbb, 0x0 } }, + { { 0xc15, 0xc4d, 0xc37, 0x0 }, + { 0x4b, 0x0 } }, + { { 0xc15, 0xc4d, 0xc37, 0xc4d, 0x0 }, + { 0xe0, 0x0 } }, + { { 0xc15, 0xc4d, 0xc37, 0xc4d, 0xc23, 0x0 }, + { 0x4b, 0x91, 0x0 } }, + { { 0xc15, 0xc4d, 0xc30, 0x0 }, + { 0x5a, 0xb2, 0x0 } }, + { { 0xc15, 0xc4d, 0xc30, 0xc4d, 0x0 }, + { 0xbb, 0xb2, 0x0 } }, + { { 0xc15, 0xc4d, 0xc30, 0xc4d, 0xc15, 0x0 }, + { 0x5a, 0xb2, 0x83, 0x0 } }, + { { 0xc15, 0xc4d, 0xc30, 0xc3f, 0x0 }, + { 0xe2, 0xb2, 0x0 } }, + { { 0xc15, 0xc4d, 0xc15, 0xc48, 0x0 }, + { 0xe6, 0xb3, 0x83, 0x0 } }, + { { 0xc15, 0xc4d, 0xc30, 0xc48, 0x0 }, + { 0xe6, 0xb3, 0x9f, 0x0 } }, + { { 0xc15, 0xc46, 0xc56, 0x0 }, + { 0xe6, 0xb3, 0x0 } }, + { {0}, {0} } + + }; + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Pothana2000", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + + +void tst_QTextScriptEngine::kannada() +{ +#if defined(Q_WS_X11) + { + if (QFontDatabase().families(QFontDatabase::Kannada).contains("Sampige")) { + QFont f("Sampige"); + const ShapeTable shape_table [] = { + { { 0x0ca8, 0x0ccd, 0x0ca8, 0x0 }, + { 0x0049, 0x00ba, 0x0 } }, + { { 0x0ca8, 0x0ccd, 0x0ca1, 0x0 }, + { 0x0049, 0x00b3, 0x0 } }, + { { 0x0caf, 0x0cc2, 0x0 }, + { 0x004f, 0x005d, 0x0 } }, + { { 0x0ce0, 0x0 }, + { 0x006a, 0x0 } }, + { { 0x0ce6, 0x0ce7, 0x0ce8, 0x0 }, + { 0x006b, 0x006c, 0x006d, 0x0 } }, + { { 0x0cb5, 0x0ccb, 0x0 }, + { 0x015f, 0x0067, 0x0 } }, + { { 0x0cb0, 0x0ccd, 0x0cae, 0x0 }, + { 0x004e, 0x0082, 0x0 } }, + { { 0x0cb0, 0x0ccd, 0x0c95, 0x0 }, + { 0x0036, 0x0082, 0x0 } }, + { { 0x0c95, 0x0ccd, 0x0cb0, 0x0 }, + { 0x0036, 0x00c1, 0x0 } }, + { { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0x0 }, + { 0x0050, 0x00a7, 0x0 } }, + + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Sampige", SkipAll); + } + } + { + if (QFontDatabase().families(QFontDatabase::Kannada).contains("Tunga")) { + QFont f("Tunga"); + const ShapeTable shape_table [] = { + { { 0x0cb7, 0x0cc6, 0x0 }, + { 0x00b0, 0x006c, 0x0 } }, + { { 0x0cb7, 0x0ccd, 0x0 }, + { 0x0163, 0x0 } }, + { { 0xc95, 0xcbf, 0xcd5, 0x0 }, + { 0x114, 0x73, 0x0 } }, + { { 0xc95, 0xcc6, 0xcd5, 0x0 }, + { 0x90, 0x6c, 0x73, 0x0 } }, + { { 0xc95, 0xcc6, 0xcd6, 0x0 }, + { 0x90, 0x6c, 0x74, 0x0 } }, + { { 0xc95, 0xcc6, 0xcc2, 0x0 }, + { 0x90, 0x6c, 0x69, 0x0 } }, + { { 0xc95, 0xcca, 0xcd5, 0x0 }, + { 0x90, 0x6c, 0x69, 0x73, 0x0 } }, + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Tunga", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + + + +void tst_QTextScriptEngine::malayalam() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Malayalam).contains("AkrutiMal2")) { + QFont f("AkrutiMal2"); + const ShapeTable shape_table [] = { + { { 0x0d15, 0x0d46, 0x0 }, + { 0x005e, 0x0034, 0x0 } }, + { { 0x0d15, 0x0d47, 0x0 }, + { 0x005f, 0x0034, 0x0 } }, + { { 0x0d15, 0x0d4b, 0x0 }, + { 0x005f, 0x0034, 0x0058, 0x0 } }, + { { 0x0d15, 0x0d48, 0x0 }, + { 0x0060, 0x0034, 0x0 } }, + { { 0x0d15, 0x0d4a, 0x0 }, + { 0x005e, 0x0034, 0x0058, 0x0 } }, + { { 0x0d30, 0x0d4d, 0x0d15, 0x0 }, + { 0x009e, 0x0034, 0x0 } }, + { { 0x0d15, 0x0d4d, 0x0d35, 0x0 }, + { 0x0034, 0x007a, 0x0 } }, + { { 0x0d15, 0x0d4d, 0x0d2f, 0x0 }, + { 0x0034, 0x00a2, 0x0 } }, + { { 0x0d1f, 0x0d4d, 0x0d1f, 0x0 }, + { 0x0069, 0x0 } }, + { { 0x0d26, 0x0d4d, 0x0d26, 0x0 }, + { 0x0074, 0x0 } }, + { { 0x0d30, 0x0d4d, 0x0 }, + { 0x009e, 0x0 } }, + { { 0x0d30, 0x0d4d, 0x200c, 0x0 }, + { 0x009e, 0x0 } }, + { { 0x0d30, 0x0d4d, 0x200d, 0x0 }, + { 0x009e, 0x0 } }, + { { 0xd15, 0xd46, 0xd3e, 0x0 }, + { 0x5e, 0x34, 0x58, 0x0 } }, + { { 0xd15, 0xd47, 0xd3e, 0x0 }, + { 0x5f, 0x34, 0x58, 0x0 } }, + { { 0xd15, 0xd46, 0xd57, 0x0 }, + { 0x5e, 0x34, 0x65, 0x0 } }, + { { 0xd15, 0xd57, 0x0 }, + { 0x34, 0x65, 0x0 } }, + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find AkrutiMal2", SkipAll); + } + } + { + if (QFontDatabase().families(QFontDatabase::Malayalam).contains("Rachana")) { + QFont f("Rachana"); + const ShapeTable shape_table [] = { + { { 0xd37, 0xd4d, 0xd1f, 0xd4d, 0xd30, 0xd40, 0x0 }, + { 0x385, 0xa3, 0x0 } }, + { { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 }, + { 0x2ff, 0x0 } }, + { { 0xd33, 0xd4d, 0xd33, 0x0 }, + { 0x3f8, 0x0 } }, + { { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0x0 }, + { 0x2ff, 0x0 } }, + { { 0xd30, 0xd4d, 0x200d, 0xd35, 0xd4d, 0xd35, 0x0 }, + { 0xf3, 0x350, 0x0 } }, + + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Rachana", SkipAll); + } + } + +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + +void tst_QTextScriptEngine::sinhala() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Sinhala).contains("Malithi Web")) { + QFont f("Malithi Web"); + const ShapeTable shape_table [] = { + { { 0xd9a, 0xdd9, 0xdcf, 0x0 }, + { 0x4a, 0x61, 0x42, 0x0 } }, + { { 0xd9a, 0xdd9, 0xddf, 0x0 }, + { 0x4a, 0x61, 0x50, 0x0 } }, + { { 0xd9a, 0xdd9, 0xdca, 0x0 }, + { 0x4a, 0x62, 0x0 } }, + { { 0xd9a, 0xddc, 0xdca, 0x0 }, + { 0x4a, 0x61, 0x42, 0x41, 0x0 } }, + { { 0xd9a, 0xdda, 0x0 }, + { 0x4a, 0x62, 0x0 } }, + { { 0xd9a, 0xddd, 0x0 }, + { 0x4a, 0x61, 0x42, 0x41, 0x0 } }, + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Malithi Web", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + + +void tst_QTextScriptEngine::khmer() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Khmer).contains("Khmer OS")) { + QFont f("Khmer OS"); + const ShapeTable shape_table [] = { + { { 0x179a, 0x17cd, 0x0 }, + { 0x24c, 0x27f, 0x0 } }, + { { 0x179f, 0x17c5, 0x0 }, + { 0x273, 0x203, 0x0 } }, + { { 0x1790, 0x17d2, 0x1784, 0x17c3, 0x0 }, + { 0x275, 0x242, 0x182, 0x0 } }, + { { 0x179a, 0x0 }, + { 0x24c, 0x0 } }, + { { 0x1781, 0x17d2, 0x1798, 0x17c2, 0x0 }, + { 0x274, 0x233, 0x197, 0x0 } }, + { { 0x1798, 0x17b6, 0x0 }, + { 0x1cb, 0x0 } }, + { { 0x179a, 0x17b8, 0x0 }, + { 0x24c, 0x26a, 0x0 } }, + { { 0x1787, 0x17b6, 0x0 }, + { 0x1ba, 0x0 } }, + { { 0x1798, 0x17d2, 0x1796, 0x17bb, 0x0 }, + { 0x24a, 0x195, 0x26d, 0x0 } }, + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Khmer OS", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + +void tst_QTextScriptEngine::linearB() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Any).contains("Penuturesu")) { + QFont f("Penuturesu"); + const ShapeTable shape_table [] = { + { { 0xd800, 0xdc01, 0xd800, 0xdc02, 0xd800, 0xdc03, 0 }, + { 0x5, 0x6, 0x7, 0 } }, + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find Penuturesu", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + +#if defined(Q_WS_X11) +static bool decomposedShaping( const QFont &f, const QChar &ch) +{ + QString str = QString().append(ch); + QTextLayout layout(str, f); + QTextEngine *e = layout.d; + e->itemize(); + e->shape(0); + + QTextLayout decomposed(str.normalized(QString::NormalizationForm_D), f); + QTextEngine *de = decomposed.d; + de->itemize(); + de->shape(0); + + if( e->layoutData->items[0].num_glyphs != de->layoutData->items[0].num_glyphs ) + goto error; + + for (int i = 0; i < e->layoutData->items[0].num_glyphs; ++i) { + if ((e->layoutData->glyphLayout.glyphs[i] & 0xffffff) != (de->layoutData->glyphLayout.glyphs[i] & 0xffffff)) + goto error; + } + return true; + error: + qDebug("%s: decomposedShaping of char %4x failed, nglyphs=%d, decomposed nglyphs %d", + f.family().toLatin1().constData(), + ch.unicode(), + e->layoutData->items[0].num_glyphs, + de->layoutData->items[0].num_glyphs); + + str = ""; + int i = 0; + while (i < e->layoutData->items[0].num_glyphs) { + str += QString("%1 ").arg(e->layoutData->glyphLayout.glyphs[i], 4, 16); + ++i; + } + qDebug(" composed glyph result = %s", str.toLatin1().constData()); + str = ""; + i = 0; + while (i < de->layoutData->items[0].num_glyphs) { + str += QString("%1 ").arg(de->layoutData->glyphLayout.glyphs[i], 4, 16); + ++i; + } + qDebug(" decomposed glyph result = %s", str.toLatin1().constData()); + return false; +} +#endif + + +void tst_QTextScriptEngine::greek() +{ +#if defined(Q_WS_X11) + if (!haveTestFonts) { + QSKIP("Test fonts are not available", SkipAll); + } + + { + if (QFontDatabase().families(QFontDatabase::Any).contains("DejaVu Sans")) { + QFont f("DejaVu Sans"); + for (int uc = 0x1f00; uc <= 0x1fff; ++uc) { + QString str; + str.append(uc); + if (str.normalized(QString::NormalizationForm_D).normalized(QString::NormalizationForm_C) != str) { + //qDebug() << "skipping" << hex << uc; + continue; + } + if (uc == 0x1fc1 || uc == 0x1fed) + continue; + QVERIFY( decomposedShaping(f, QChar(uc)) ); + } + } else { + QSKIP("couldn't find DejaVu Sans", SkipAll); + } + } + + { + if (QFontDatabase().families(QFontDatabase::Any).contains("SBL Greek")) { + QFont f("SBL Greek"); + for (int uc = 0x1f00; uc <= 0x1fff; ++uc) { + QString str; + str.append(uc); + if (str.normalized(QString::NormalizationForm_D).normalized(QString::NormalizationForm_C) != str) { + //qDebug() << "skipping" << hex << uc; + continue; + } + if (uc == 0x1fc1 || uc == 0x1fed) + continue; + QVERIFY( decomposedShaping(f, QChar(uc) ) ); + + } + + const ShapeTable shape_table [] = { + { { 0x3b1, 0x300, 0x313, 0x0 }, + { 0xb8, 0x3d3, 0x3c7, 0x0 } }, + { { 0x3b1, 0x313, 0x300, 0x0 }, + { 0xd4, 0x0 } }, + + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(f, s) ); + ++s; + } + } else { + QSKIP("couldn't find SBL_grk", SkipAll); + } + } +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + +void tst_QTextScriptEngine::controlInSyllable_qtbug14204() +{ +#if defined(Q_WS_X11) + QString s; + s.append(QChar(0x0915)); + s.append(QChar(0x094d)); + s.append(QChar(0x200d)); + s.append(QChar(0x0915)); + + QTextLayout layout(s); + QTextEngine *e = layout.d; + e->itemize(); + e->shape(0); + + QVERIFY(e->layoutData->items[0].num_glyphs == 2); + QVERIFY(e->layoutData->glyphLayout.advances_x[1] != 0); +#else + QSKIP("X11 specific test", SkipAll); +#endif +} + +void tst_QTextScriptEngine::combiningMarks_qtbug15675() +{ +#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + QString s; + s.append(QChar(0x0061)); + s.append(QChar(0x0062)); + s.append(QChar(0x0300)); + s.append(QChar(0x0063)); + + QFont font("Monaco"); + QTextLayout layout(s, font); + QTextEngine *e = layout.d; + e->itemize(); + e->shape(0); + + QVERIFY(e->layoutData->items[0].num_glyphs == 4); + QVERIFY(e->layoutData->glyphLayout.advances_y[2] > 0); +#elif defined(Q_WS_X11) + QFontDatabase db; + + if (!db.families().contains("DejaVu Sans Mono")) { + QSKIP("Required font (DejaVu Sans Mono) doesn't exist, skip test.", SkipAll); + return; + } + + QString s; + s.append(QChar(0x0062)); + s.append(QChar(0x0332)); + s.append(QChar(0x0063)); + + QTextLayout layout(s, QFont("DejaVu Sans Mono")); + QTextEngine *e = layout.d; + e->itemize(); + e->shape(0); + + QVERIFY(e->layoutData->items[0].num_glyphs == 3); + QVERIFY(e->layoutData->glyphLayout.advances_x[1] == 0); +#else + QSKIP("X11/Mac specific test", SkipAll); +#endif +} + +void tst_QTextScriptEngine::mirroredChars_data() +{ + QTest::addColumn<int>("hintingPreference"); + + QTest::newRow("Default hinting") << int(QFont::PreferDefaultHinting); + QTest::newRow("No hinting") << int(QFont::PreferNoHinting); + QTest::newRow("Vertical hinting") << int(QFont::PreferVerticalHinting); + QTest::newRow("Full hinting") << int(QFont::PreferFullHinting); +} + +void tst_QTextScriptEngine::mirroredChars() +{ +#if defined(Q_WS_MAC) + QSKIP("Not supported on Mac", SkipAll); +#endif + QFETCH(int, hintingPreference); + + QFont font; + font.setHintingPreference(QFont::HintingPreference(hintingPreference)); + + QString s; + s.append(QLatin1Char('(')); + s.append(QLatin1Char(')')); + + HB_Glyph leftParenthesis; + HB_Glyph rightParenthesis; + { + QTextLayout layout(s); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QTextEngine *e = layout.engine(); + e->itemize(); + e->shape(0); + QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2)); + + const QGlyphLayout &glyphLayout = e->layoutData->glyphLayout; + leftParenthesis = glyphLayout.glyphs[0]; + rightParenthesis = glyphLayout.glyphs[1]; + } + + { + QTextLayout layout(s); + layout.setFlags(Qt::TextForceRightToLeft); + + QTextEngine *e = layout.engine(); + e->itemize(); + e->shape(0); + QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2)); + + const QGlyphLayout &glyphLayout = e->layoutData->glyphLayout; + QCOMPARE(glyphLayout.glyphs[0], rightParenthesis); + QCOMPARE(glyphLayout.glyphs[1], leftParenthesis); + } +} + +QTEST_MAIN(tst_QTextScriptEngine) +#include "tst_qtextscriptengine.moc" diff --git a/tests/auto/gui/text/qtexttable/.gitignore b/tests/auto/gui/text/qtexttable/.gitignore new file mode 100644 index 0000000000..876aa75c0a --- /dev/null +++ b/tests/auto/gui/text/qtexttable/.gitignore @@ -0,0 +1 @@ +tst_qtexttable diff --git a/tests/auto/gui/text/qtexttable/qtexttable.pro b/tests/auto/gui/text/qtexttable/qtexttable.pro new file mode 100644 index 0000000000..611b706fc4 --- /dev/null +++ b/tests/auto/gui/text/qtexttable/qtexttable.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +QT += widgets +SOURCES += tst_qtexttable.cpp + + + diff --git a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp new file mode 100644 index 0000000000..83343811d8 --- /dev/null +++ b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp @@ -0,0 +1,1004 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> + + +#include <qtextdocument.h> +#include <qtextdocumentfragment.h> +#include <qtexttable.h> +#include <qdebug.h> +#include <qtextcursor.h> +#include <qtextdocument.h> +#include <qtextedit.h> + +//TESTED_FILES= + +typedef QList<int> IntList; +Q_DECLARE_METATYPE(IntList) + +QT_FORWARD_DECLARE_CLASS(QTextDocument) + +class tst_QTextTable : public QObject +{ + Q_OBJECT + +public: + tst_QTextTable(); + + +public slots: + void init(); + void cleanup(); +private slots: + void cursorPositioning(); + void variousTableModifications(); + void tableShrinking(); + void spans(); + void variousModifications2(); + void tableManager_undo(); + void tableManager_removeCell(); + void rowAt(); + void rowAtWithSpans(); + void multiBlockCells(); + void insertRows(); + void deleteInTable(); + void mergeCells(); + void mergeAndInsert(); + void splitCells(); + void blocksForTableShouldHaveEmptyFormat(); + void removeTableByRemoveRows(); + void removeTableByRemoveColumns(); + void setCellFormat(); + void removeRows1(); + void removeRows2(); + void removeRows3(); + void removeRows4(); + void removeRows5(); + void removeColumns1(); + void removeColumns2(); + void removeColumns3(); + void removeColumns4(); + void removeColumns5(); + void removeColumnsInTableWithMergedRows(); + void QTBUG11282_insertBeforeMergedEnding_data(); + void QTBUG11282_insertBeforeMergedEnding(); + +private: + QTextTable *create2x2Table(); + QTextTable *create4x4Table(); + + QTextTable *createTable(int rows, int cols); + + QTextDocument *doc; + QTextCursor cursor; +}; + +tst_QTextTable::tst_QTextTable() +{} + +void tst_QTextTable::init() +{ + doc = new QTextDocument; + cursor = QTextCursor(doc); +} + +void tst_QTextTable::cleanup() +{ + cursor = QTextCursor(); + delete doc; + doc = 0; +} + +void tst_QTextTable::cursorPositioning() +{ + // ensure the cursor is placed at the beginning of the first cell upon + // table creation + QTextTable *table = cursor.insertTable(2, 2); + + QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition()); + QVERIFY(table->cellAt(0, 0).firstPosition() == table->firstPosition()); +} + +void tst_QTextTable::variousTableModifications() +{ + QTextTableFormat tableFmt; + + QTextTable *tab = cursor.insertTable(2, 2, tableFmt); + QVERIFY(doc->toPlainText().length() == 5); + QVERIFY(tab == cursor.currentTable()); + QVERIFY(tab->columns() == 2); + QVERIFY(tab->rows() == 2); + + QVERIFY(cursor.position() == 1); + QTextCharFormat fmt = cursor.charFormat(); + QVERIFY(fmt.objectIndex() == -1); + QTextTableCell cell = tab->cellAt(cursor); + QVERIFY(cell.isValid()); + QVERIFY(cell.row() == 0); + QVERIFY(cell.column() == 0); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.position() == 2); + fmt = cursor.charFormat(); + QVERIFY(fmt.objectIndex() == -1); + cell = tab->cellAt(cursor); + QVERIFY(cell.isValid()); + QVERIFY(cell.row() == 0); + QVERIFY(cell.column() == 1); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.position() == 3); + fmt = cursor.charFormat(); + QVERIFY(fmt.objectIndex() == -1); + cell = tab->cellAt(cursor); + QVERIFY(cell.isValid()); + QVERIFY(cell.row() == 1); + QVERIFY(cell.column() == 0); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.position() == 4); + fmt = cursor.charFormat(); + QVERIFY(fmt.objectIndex() == -1); + cell = tab->cellAt(cursor); + QVERIFY(cell.isValid()); + QVERIFY(cell.row() == 1); + QVERIFY(cell.column() == 1); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.position() == 5); + fmt = cursor.charFormat(); + QVERIFY(fmt.objectIndex() == -1); + cell = tab->cellAt(cursor); + QVERIFY(!cell.isValid()); + + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.position() == 5); + + // check we can't delete the cells with the cursor + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.position() == 1); + cursor.deleteChar(); + QVERIFY(doc->toPlainText().length() == 5); + cursor.movePosition(QTextCursor::NextBlock); + QVERIFY(cursor.position() == 2); + cursor.deleteChar(); + QVERIFY(doc->toPlainText().length() == 5); + cursor.deletePreviousChar(); + QVERIFY(cursor.position() == 2); + QVERIFY(doc->toPlainText().length() == 5); + + QTextTable *table = cursor.currentTable(); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 2); + + table->insertRows(2, 1); + QVERIFY(table->rows() == 3); + QVERIFY(table->columns() == 2); + QVERIFY(doc->toPlainText().length() == 7); + table->insertColumns(2, 2); + QVERIFY(table->rows() == 3); + QVERIFY(table->columns() == 4); + QVERIFY(doc->toPlainText().length() == 13); + + table->resize(4, 5); + QVERIFY(table->rows() == 4); + QVERIFY(table->columns() == 5); + QVERIFY(doc->toPlainText().length() == 21); +} + +void tst_QTextTable::tableShrinking() +{ + QTextTableFormat tableFmt; + + cursor.insertTable(3, 4, tableFmt); + QVERIFY(doc->toPlainText().length() == 13); + + QTextTable *table = cursor.currentTable(); + QVERIFY(table->rows() == 3); + QVERIFY(table->columns() == 4); + + table->removeRows(1, 1); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 4); + QVERIFY(doc->toPlainText().length() == 9); + table->removeColumns(1, 2); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 2); + QVERIFY(doc->toPlainText().length() == 5); + + table->resize(1, 1); + QVERIFY(table->rows() == 1); + QVERIFY(table->columns() == 1); + QVERIFY(doc->toPlainText().length() == 2); +} + +void tst_QTextTable::spans() +{ + QTextTableFormat tableFmt; + + cursor.insertTable(2, 2, tableFmt); + + QTextTable *table = cursor.currentTable(); + QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1)); + table->mergeCells(0, 0, 1, 2); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 2); + QVERIFY(table->cellAt(0, 0) == table->cellAt(0, 1)); + table->mergeCells(0, 0, 2, 2); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 2); +} + +void tst_QTextTable::variousModifications2() +{ + QTextTableFormat tableFmt; + + cursor.insertTable(2, 5, tableFmt); + QVERIFY(doc->toPlainText().length() == 11); + QTextTable *table = cursor.currentTable(); + QVERIFY(cursor.position() == 1); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 5); + + table->insertColumns(0, 1); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 6); + table->insertColumns(6, 1); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 7); + + table->insertRows(0, 1); + QVERIFY(table->rows() == 3); + QVERIFY(table->columns() == 7); + table->insertRows(3, 1); + QVERIFY(table->rows() == 4); + QVERIFY(table->columns() == 7); + + table->removeRows(0, 1); + QVERIFY(table->rows() == 3); + QVERIFY(table->columns() == 7); + table->removeRows(2, 1); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 7); + + table->removeColumns(0, 1); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 6); + table->removeColumns(5, 1); + QVERIFY(table->rows() == 2); + QVERIFY(table->columns() == 5); + + tableFmt = table->format(); + table->insertColumns(2, 1); + table->setFormat(tableFmt); + table->insertColumns(2, 1); + QVERIFY(table->columns() == 7); +} + +void tst_QTextTable::tableManager_undo() +{ + QTextTableFormat fmt; + fmt.setBorder(10); + QTextTable *table = cursor.insertTable(2, 2, fmt); + QVERIFY(table); + + QVERIFY(table->format().border() == 10); + + fmt.setBorder(20); + table->setFormat(fmt); + + QVERIFY(table->format().border() == 20); + + doc->undo(); + + QVERIFY(table->format().border() == 10); +} + +void tst_QTextTable::tableManager_removeCell() +{ + // essentially a test for TableManager::removeCell, in particular to remove empty items from the rowlist. + // If it fails it'll triger assertions inside TableManager. Yeah, not pretty, should VERIFY here ;( + cursor.insertTable(2, 2, QTextTableFormat()); + doc->undo(); + // ### + QVERIFY(true); +} + +void tst_QTextTable::rowAt() +{ + // test TablePrivate::rowAt + QTextTable *table = cursor.insertTable(4, 2); + + QCOMPARE(table->rows(), 4); + QCOMPARE(table->columns(), 2); + + QTextCursor cell00Cursor = table->cellAt(0, 0).firstCursorPosition(); + QTextCursor cell10Cursor = table->cellAt(1, 0).firstCursorPosition(); + QTextCursor cell20Cursor = table->cellAt(2, 0).firstCursorPosition(); + QTextCursor cell21Cursor = table->cellAt(2, 1).firstCursorPosition(); + QTextCursor cell30Cursor = table->cellAt(3, 0).firstCursorPosition(); + QVERIFY(table->cellAt(cell00Cursor).firstCursorPosition() == cell00Cursor); + QVERIFY(table->cellAt(cell10Cursor).firstCursorPosition() == cell10Cursor); + QVERIFY(table->cellAt(cell20Cursor).firstCursorPosition() == cell20Cursor); + QVERIFY(table->cellAt(cell30Cursor).firstCursorPosition() == cell30Cursor); + + table->mergeCells(1, 0, 2, 1); + + QCOMPARE(table->rows(), 4); + QCOMPARE(table->columns(), 2); + + QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition()); + QVERIFY(cell10Cursor == table->cellAt(1, 0).firstCursorPosition()); + QVERIFY(cell10Cursor == table->cellAt(2, 0).firstCursorPosition()); + QVERIFY(cell21Cursor == table->cellAt(2, 1).firstCursorPosition()); + QVERIFY(cell30Cursor == table->cellAt(3, 0).firstCursorPosition()); + + table->mergeCells(1, 0, 2, 2); + + QCOMPARE(table->rows(), 4); + QCOMPARE(table->columns(), 2); + + QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition()); + QVERIFY(cell00Cursor == table->cellAt(0, 0).firstCursorPosition()); + QVERIFY(cell10Cursor == table->cellAt(1, 0).firstCursorPosition()); + QVERIFY(cell10Cursor == table->cellAt(1, 1).firstCursorPosition()); + QVERIFY(cell10Cursor == table->cellAt(2, 0).firstCursorPosition()); + QVERIFY(cell10Cursor == table->cellAt(2, 1).firstCursorPosition()); + QVERIFY(cell30Cursor == table->cellAt(3, 0).firstCursorPosition()); +} + +void tst_QTextTable::rowAtWithSpans() +{ + QTextTable *table = cursor.insertTable(2, 2); + + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); + + table->mergeCells(0, 0, 2, 1); + QVERIFY(table->cellAt(0, 0).rowSpan() == 2); + + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); + + table->mergeCells(0, 0, 2, 2); + QVERIFY(table->cellAt(0, 0).columnSpan() == 2); + + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); +} + +void tst_QTextTable::multiBlockCells() +{ + // little testcase for multi-block cells + QTextTable *table = cursor.insertTable(2, 2); + + QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition()); + + cursor.insertText("Hello"); + cursor.insertBlock(QTextBlockFormat()); + cursor.insertText("World"); + + cursor.movePosition(QTextCursor::Left); + QVERIFY(table->cellAt(0, 0) == table->cellAt(cursor)); +} + +void tst_QTextTable::insertRows() +{ + // little testcase for multi-block cells + QTextTable *table = cursor.insertTable(2, 2); + + QVERIFY(cursor == table->cellAt(0, 0).firstCursorPosition()); + + table->insertRows(0, 1); + QVERIFY(table->rows() == 3); + + table->insertRows(1, 1); + QVERIFY(table->rows() == 4); + + table->insertRows(-1, 1); + QVERIFY(table->rows() == 5); + + table->insertRows(5, 2); + QVERIFY(table->rows() == 7); + +} + +void tst_QTextTable::deleteInTable() +{ + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); + table->cellAt(0, 1).firstCursorPosition().insertText("Foo"); + table->cellAt(1, 0).firstCursorPosition().insertText("Bar"); + table->cellAt(1, 1).firstCursorPosition().insertText("Hah"); + + cursor = table->cellAt(1, 1).firstCursorPosition(); + cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::KeepAnchor); + + QCOMPARE(table->cellAt(cursor.position()).row(), 1); + QCOMPARE(table->cellAt(cursor.position()).column(), 0); + + cursor.removeSelectedText(); + + QCOMPARE(table->columns(), 2); + QCOMPARE(table->rows(), 2); + + // verify table is still all in shape. Only the text inside should get deleted + for (int row = 0; row < table->rows(); ++row) + for (int col = 0; col < table->columns(); ++col) { + const QTextTableCell cell = table->cellAt(row, col); + QVERIFY(cell.isValid()); + QCOMPARE(cell.rowSpan(), 1); + QCOMPARE(cell.columnSpan(), 1); + } +} + +QTextTable *tst_QTextTable::create2x2Table() +{ + cleanup(); + init(); + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); + table->cellAt(0, 1).firstCursorPosition().insertText("Foo"); + table->cellAt(1, 0).firstCursorPosition().insertText("Bar"); + table->cellAt(1, 1).firstCursorPosition().insertText("Hah"); + return table; +} + +QTextTable *tst_QTextTable::create4x4Table() +{ + cleanup(); + init(); + QTextTable *table = cursor.insertTable(4, 4); + table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); + table->cellAt(0, 1).firstCursorPosition().insertText("Foo"); + table->cellAt(1, 0).firstCursorPosition().insertText("Bar"); + table->cellAt(1, 1).firstCursorPosition().insertText("Hah"); + return table; +} + +QTextTable *tst_QTextTable::createTable(int rows, int cols) +{ + cleanup(); + init(); + QTextTable *table = cursor.insertTable(rows, cols); + return table; +} + +void tst_QTextTable::mergeCells() +{ + QTextTable *table = create4x4Table(); + + table->mergeCells(1, 1, 1, 2); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + + table->mergeCells(1, 1, 2, 2); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2)); + + table = create4x4Table(); + + table->mergeCells(1, 1, 2, 1); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + + table->mergeCells(1, 1, 2, 2); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2)); + + table = create4x4Table(); + + table->mergeCells(1, 1, 2, 2); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2)); + + // should do nothing + table->mergeCells(1, 1, 1, 1); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2)); + + table = create2x2Table(); + + table->mergeCells(0, 1, 2, 1); + table->mergeCells(0, 0, 2, 2); + QVERIFY(table->cellAt(0, 0) == table->cellAt(0, 1)); + QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 0)); + QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 1)); + + QTextBlock block = table->cellAt(0, 0).firstCursorPosition().block(); + + QVERIFY(block.text() == "Blah Foo"); + QVERIFY(block.next().text() == "Hah"); + QVERIFY(block.next().next().text() == "Bar"); + + table = create4x4Table(); + + QTextCursor cursor = table->cellAt(3, 3).firstCursorPosition(); + QTextTable *t2 = cursor.insertTable(2, 2); + t2->cellAt(0, 0).firstCursorPosition().insertText("Test"); + + table->mergeCells(2, 2, 2, 2); + cursor = table->cellAt(2, 2).firstCursorPosition(); + + QTextFrame *frame = cursor.currentFrame(); + + QTextFrame::iterator it = frame->begin(); + + // find the embedded table + while (it != frame->end() && !it.currentFrame()) + ++it; + + table = qobject_cast<QTextTable *>(it.currentFrame()); + + QVERIFY(table); + + if (table) { + cursor = table->cellAt(0, 0).firstCursorPosition(); + + QVERIFY(cursor.block().text() == "Test"); + } + + table = create2x2Table(); + + table->mergeCells(0, 1, 2, 1); + + QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1)); + QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1)); + + // should do nothing + table->mergeCells(0, 0, 1, 2); + + QVERIFY(table->cellAt(0, 0) != table->cellAt(0, 1)); + QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1)); +} + +void tst_QTextTable::mergeAndInsert() +{ + QTextTable *table = cursor.insertTable(4,3); + table->mergeCells(0,1,3,2); + table->mergeCells(3,0,1,3); + //Don't crash ! + table->insertColumns(1,2); + QCOMPARE(table->columns(), 5); +} + +void tst_QTextTable::splitCells() +{ + QTextTable *table = create4x4Table(); + table->mergeCells(1, 1, 2, 2); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2)); + + table->splitCell(1, 1, 1, 2); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2)); + + table->splitCell(1, 1, 1, 1); + QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2)); + + + table = create4x4Table(); + table->mergeCells(1, 1, 2, 2); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2)); + + table->splitCell(1, 1, 2, 1); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2)); + + table->splitCell(1, 1, 1, 1); + QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2)); + + + table = create4x4Table(); + table->mergeCells(1, 1, 2, 2); + QVERIFY(table->cellAt(1, 1) == table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) == table->cellAt(2, 2)); + + table->splitCell(1, 1, 1, 1); + QVERIFY(table->cellAt(1, 1) != table->cellAt(1, 2)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 1)); + QVERIFY(table->cellAt(1, 1) != table->cellAt(2, 2)); + + table = createTable(2, 5); + table->mergeCells(0, 0, 2, 1); + table->mergeCells(0, 1, 2, 1); + QVERIFY(table->cellAt(0, 0) == table->cellAt(1, 0)); + QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1)); + table->splitCell(0, 0, 1, 1); + QVERIFY(table->cellAt(0, 0) != table->cellAt(1, 0)); + QVERIFY(table->cellAt(0, 1) == table->cellAt(1, 1)); + + table = createTable(2, 5); + table->mergeCells(0, 4, 2, 1); + QVERIFY(table->cellAt(0, 4) == table->cellAt(1, 4)); + + table->splitCell(0, 4, 1, 1); + QVERIFY(table->cellAt(0, 4) != table->cellAt(1, 4)); +} + +void tst_QTextTable::blocksForTableShouldHaveEmptyFormat() +{ + QTextBlockFormat fmt; + fmt.setProperty(QTextFormat::UserProperty, true); + cursor.insertBlock(fmt); + QVERIFY(cursor.blockFormat().hasProperty(QTextFormat::UserProperty)); + + QTextTable *table = cursor.insertTable(1, 1); + QVERIFY(!table->cellAt(0, 0).firstCursorPosition().blockFormat().hasProperty(QTextFormat::UserProperty)); + + int userPropCount = 0; + for (QTextBlock block = doc->begin(); + block.isValid(); block = block.next()) { + if (block.blockFormat().hasProperty(QTextFormat::UserProperty)) + userPropCount++; + } + QCOMPARE(userPropCount, 1); +} + +void tst_QTextTable::removeTableByRemoveRows() +{ + QPointer<QTextTable> table1 = QTextCursor(cursor).insertTable(4, 4); + QPointer<QTextTable> table2 = QTextCursor(cursor).insertTable(4, 4); + QPointer<QTextTable> table3 = QTextCursor(cursor).insertTable(4, 4); + + QVERIFY(table1); + QVERIFY(table2); + QVERIFY(table3); + + table2->removeRows(1, 1); + + QVERIFY(table1); + QVERIFY(table2); + QVERIFY(table3); + + table2->removeRows(0, table2->rows()); + + QVERIFY(table1); + QVERIFY(!table2); + QVERIFY(table3); +} + +void tst_QTextTable::removeTableByRemoveColumns() +{ + QPointer<QTextTable> table1 = QTextCursor(cursor).insertTable(4, 4); + QPointer<QTextTable> table2 = QTextCursor(cursor).insertTable(4, 4); + QPointer<QTextTable> table3 = QTextCursor(cursor).insertTable(4, 4); + + QVERIFY(table1); + QVERIFY(table2); + QVERIFY(table3); + + table2->removeColumns(1, 1); + + QVERIFY(table1); + QVERIFY(table2); + QVERIFY(table3); + + table2->removeColumns(0, table2->columns()); + + QVERIFY(table1); + QVERIFY(!table2); + QVERIFY(table3); +} + +void tst_QTextTable::setCellFormat() +{ + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + QTextTableCell cell = table->cellAt(0, 0); + QTextCharFormat fmt; + fmt.setObjectIndex(23); + fmt.setBackground(Qt::blue); + fmt.setTableCellColumnSpan(25); + fmt.setTableCellRowSpan(42); + cell.setFormat(fmt); + QVERIFY(cell.format().background().color() == QColor(Qt::blue)); + QCOMPARE(cell.format().tableCellColumnSpan(), 1); + QCOMPARE(cell.format().tableCellRowSpan(), 1); +} + +void tst_QTextTable::removeRows1() +{ + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + table->removeRows(0, 1); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Third")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Fourth")); +} + +void tst_QTextTable::removeRows2() +{ + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + table->removeRows(1, 1); + QCOMPARE(table->rows(), 1); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second")); +} + +void tst_QTextTable::removeRows3() +{ + QTextTable *table = cursor.insertTable(3, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + table->cellAt(2, 0).firstCursorPosition().insertText("Fifth"); + table->cellAt(2, 1).firstCursorPosition().insertText("Sixth"); + table->removeRows(1, 1); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fifth")); + QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Sixth")); +} + +void tst_QTextTable::removeRows4() +{ + QTextTable *table = cursor.insertTable(4, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + table->cellAt(2, 0).firstCursorPosition().insertText("Fifth"); + table->cellAt(2, 1).firstCursorPosition().insertText("Sixth"); + table->cellAt(3, 0).firstCursorPosition().insertText("Seventh"); + table->cellAt(3, 1).firstCursorPosition().insertText("Eighth"); + table->removeRows(1, 2); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Seventh")); + QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Eighth")); +} + +void tst_QTextTable::removeRows5() +{ + QTextTable *table = cursor.insertTable(2,2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + table->insertRows(1,1); + table->mergeCells(1,0,1,2); + table->removeRows(1,1); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Third")); + QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Fourth")); +} + +void tst_QTextTable::removeColumns1() +{ + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + table->removeColumns(0, 1); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Second")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fourth")); +} + +void tst_QTextTable::removeColumns2() +{ + QTextTable *table = cursor.insertTable(2, 2); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(1, 0).firstCursorPosition().insertText("Third"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fourth"); + table->removeColumns(1, 1); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 1); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Third")); +} + +void tst_QTextTable::removeColumns3() +{ + QTextTable *table = cursor.insertTable(2, 3); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(0, 2).firstCursorPosition().insertText("Third"); + table->cellAt(1, 0).firstCursorPosition().insertText("Fourth"); + table->cellAt(1, 1).firstCursorPosition().insertText("Fifth"); + table->cellAt(1, 2).firstCursorPosition().insertText("Sixth"); + table->removeColumns(1, 1); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Third")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fourth")); + QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Sixth")); +} + +void tst_QTextTable::removeColumns4() +{ + QTextTable *table = cursor.insertTable(2, 4); + table->cellAt(0, 0).firstCursorPosition().insertText("First"); + table->cellAt(0, 1).firstCursorPosition().insertText("Second"); + table->cellAt(0, 2).firstCursorPosition().insertText("Third"); + table->cellAt(0, 3).firstCursorPosition().insertText("Fourth"); + table->cellAt(1, 0).firstCursorPosition().insertText("Fifth"); + table->cellAt(1, 1).firstCursorPosition().insertText("Sixth"); + table->cellAt(1, 2).firstCursorPosition().insertText("Seventh"); + table->cellAt(1, 3).firstCursorPosition().insertText("Eighth"); + table->removeColumns(1, 2); + QCOMPARE(table->rows(), 2); + QCOMPARE(table->columns(), 2); + QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First")); + QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Fourth")); + QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Fifth")); + QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Eighth")); +} + +void tst_QTextTable::removeColumns5() +{ + QTextTable *table = cursor.insertTable(4, 4); + QTextCursor tc (doc); + tc.setPosition(table->cellAt(2,0).firstPosition()); + tc.setPosition(table->cellAt(3,1).firstPosition(), QTextCursor::KeepAnchor); + table->mergeCells(tc); + QCOMPARE(table->rows(), 4); + QCOMPARE(table->columns(), 4); + QCOMPARE(table->cellAt(0, 0).firstPosition(), 1); + QCOMPARE(table->cellAt(0, 1).firstPosition(), 2); + QCOMPARE(table->cellAt(0, 2).firstPosition(), 3); + QCOMPARE(table->cellAt(0, 3).firstPosition(), 4); + QCOMPARE(table->cellAt(1, 0).firstPosition(), 5); + QCOMPARE(table->cellAt(1, 1).firstPosition(), 6); + QCOMPARE(table->cellAt(1, 2).firstPosition(), 7); + QCOMPARE(table->cellAt(1, 3).firstPosition(), 8); + QCOMPARE(table->cellAt(2, 0).firstPosition(), 9); + QCOMPARE(table->cellAt(2, 0).rowSpan(), 2); + QCOMPARE(table->cellAt(2, 0).columnSpan(), 2); + QCOMPARE(table->cellAt(2, 1).firstPosition(), 9); + QCOMPARE(table->cellAt(2, 2).firstPosition(), 10); + QCOMPARE(table->cellAt(2, 3).firstPosition(), 11); + QCOMPARE(table->cellAt(3, 0).firstPosition(), 9); + QCOMPARE(table->cellAt(3, 1).firstPosition(), 9); + QCOMPARE(table->cellAt(3, 2).firstPosition(), 12); + QCOMPARE(table->cellAt(3, 3).firstPosition(), 13); + + table->removeColumns(1, 1); + QCOMPARE(table->rows(), 4); + QCOMPARE(table->columns(), 3); + QCOMPARE(table->cellAt(0, 0).firstPosition(), 1); + QCOMPARE(table->cellAt(0, 1).firstPosition(), 2); + QCOMPARE(table->cellAt(0, 2).firstPosition(), 3); + QCOMPARE(table->cellAt(1, 0).firstPosition(), 4); + QCOMPARE(table->cellAt(1, 1).firstPosition(), 5); + QCOMPARE(table->cellAt(1, 2).firstPosition(), 6); + QCOMPARE(table->cellAt(2, 0).firstPosition(), 7); + QCOMPARE(table->cellAt(2, 0).rowSpan(), 2); + QCOMPARE(table->cellAt(2, 0).columnSpan(), 1); + QCOMPARE(table->cellAt(2, 1).firstPosition(), 8); + QCOMPARE(table->cellAt(2, 2).firstPosition(), 9); + QCOMPARE(table->cellAt(3, 0).firstPosition(), 7); + QCOMPARE(table->cellAt(3, 1).firstPosition(), 10); + QCOMPARE(table->cellAt(3, 2).firstPosition(), 11); +} + +void tst_QTextTable::removeColumnsInTableWithMergedRows() +{ + QTextTable *table = cursor.insertTable(3, 4); + table->mergeCells(0, 0, 1, 4); + QCOMPARE(table->rows(), 3); + QCOMPARE(table->columns(), 4); + + table->removeColumns(0, table->columns() - 1); + + QCOMPARE(table->rows(), 3); + QCOMPARE(table->columns(), 1); +} + +void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding_data() +{ + QTest::addColumn<int>("rows"); + QTest::addColumn<int>("columns"); + QTest::addColumn<QList<int> >("merge"); + QTest::addColumn<QList<int> >("insert"); + + QTest::newRow("2x3, merge two, insert one") << 2 << 3 << (QList<int>() << 1 << 2 << 2) + << (QList<int>() << 1 << 1) ; + QTest::newRow("3x4, merge three, insert one") << 3 << 4 << (QList<int>() << 1 << 3 << 3) + << (QList<int>() << 1 << 1) ; + QTest::newRow("4x3, merge two, insert two") << 4 << 3 << (QList<int>() << 1 << 4 << 2) + << (QList<int>() << 1 << 2) ; + QTest::newRow("4x4, merge middle two, insert one") << 4 << 4 << (QList<int>() << 1 << 4 << 2) + << (QList<int>() << 1 << 1) ; +} + +void tst_QTextTable::QTBUG11282_insertBeforeMergedEnding() +{ + QFETCH(int, rows); + QFETCH(int, columns); + QFETCH(QList<int>, merge); + QFETCH(QList<int>, insert); + QTextTable *table = cursor.insertTable(rows, columns); + QTextEdit *textEdit = new QTextEdit; + textEdit->setDocument(doc); + textEdit->show(); + QTest::qWaitForWindowShown(textEdit); + table->mergeCells(0,merge.at(0), merge.at(1), merge.at(2)); + //Don't crash ! + table->insertColumns(insert.at(0), insert.at(1)); + //Check that the final size is what we expected + QCOMPARE(table->rows(), rows); + QCOMPARE(table->columns(), columns + insert.at(1)); + delete textEdit; +} + +QTEST_MAIN(tst_QTextTable) +#include "tst_qtexttable.moc" diff --git a/tests/auto/gui/text/qzip/.gitignore b/tests/auto/gui/text/qzip/.gitignore new file mode 100644 index 0000000000..2d7dfbe70c --- /dev/null +++ b/tests/auto/gui/text/qzip/.gitignore @@ -0,0 +1 @@ +tst_qzip diff --git a/tests/auto/gui/text/qzip/qzip.pro b/tests/auto/gui/text/qzip/qzip.pro new file mode 100644 index 0000000000..7631a3e93a --- /dev/null +++ b/tests/auto/gui/text/qzip/qzip.pro @@ -0,0 +1,12 @@ +load(qttest_p4) +QT += gui-private +SOURCES += tst_qzip.cpp + +wince*|symbian: { + addFiles.files = testdata + addFiles.path = . + DEPLOYMENT += addFiles + !symbian:DEFINES += SRCDIR=\\\".\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD\\\" +} diff --git a/tests/auto/gui/text/qzip/testdata/symlink.zip b/tests/auto/gui/text/qzip/testdata/symlink.zip Binary files differnew file mode 100644 index 0000000000..027f96477a --- /dev/null +++ b/tests/auto/gui/text/qzip/testdata/symlink.zip diff --git a/tests/auto/gui/text/qzip/testdata/test.zip b/tests/auto/gui/text/qzip/testdata/test.zip Binary files differnew file mode 100644 index 0000000000..a57ba4e2a9 --- /dev/null +++ b/tests/auto/gui/text/qzip/testdata/test.zip diff --git a/tests/auto/gui/text/qzip/tst_qzip.cpp b/tests/auto/gui/text/qzip/tst_qzip.cpp new file mode 100644 index 0000000000..0955ac069f --- /dev/null +++ b/tests/auto/gui/text/qzip/tst_qzip.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QDebug> +#include <private/qzipwriter_p.h> +#include <private/qzipreader_p.h> + +#ifdef Q_OS_SYMBIAN +#define SRCDIR "." +#endif + +class tst_QZip : public QObject +{ + Q_OBJECT +public slots: + void init(); + void cleanup(); + +private slots: + void basicUnpack(); + void symlinks(); + void readTest(); + void createArchive(); +}; + +void tst_QZip::init() +{ +} + +void tst_QZip::cleanup() +{ +} + +void tst_QZip::basicUnpack() +{ + QZipReader zip(QString(SRCDIR) + "/testdata/test.zip", QIODevice::ReadOnly); + QList<QZipReader::FileInfo> files = zip.fileInfoList(); + QCOMPARE(files.count(), 2); + + QZipReader::FileInfo fi = files.at(0); + QVERIFY(fi.isValid()); + QCOMPARE(fi.filePath, QString("test/")); + QCOMPARE(uint(fi.isDir), (uint) 1); + QCOMPARE(uint(fi.isFile), (uint) 0); + QCOMPARE(uint(fi.isSymLink), (uint) 0); + + QCOMPARE(fi.permissions,QFile::Permissions( QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner + | QFile::ReadUser | QFile::WriteUser | QFile::ExeUser )); + + QCOMPARE(fi.lastModified, QDateTime::fromString("2005.11.11 13:08:02", "yyyy.MM.dd HH:mm:ss")); + + fi = files.at(1); + QVERIFY(fi.isValid()); + QCOMPARE(fi.filePath, QString("test/test.txt")); + QCOMPARE(uint(fi.isDir), (uint) 0); + QCOMPARE(uint(fi.isFile), (uint) 1); + QCOMPARE(uint(fi.isSymLink), (uint) 0); + + QVERIFY(fi.permissions == QFile::Permissions( QFile::ReadOwner | QFile::WriteOwner + | QFile::ReadUser | QFile::WriteUser )); + + QCOMPARE(fi.lastModified, QDateTime::fromString("2005.11.11 13:08:02", "yyyy.MM.dd HH:mm:ss")); + + QCOMPARE(zip.fileData("test/test.txt"), QByteArray("content\n")); + + fi = files.at(-1); + QVERIFY(!fi.isValid()); +} + +void tst_QZip::symlinks() +{ + QZipReader zip(QString(SRCDIR) + "/testdata/symlink.zip", QIODevice::ReadOnly); + QList<QZipReader::FileInfo> files = zip.fileInfoList(); + QCOMPARE(files.count(), 2); + + QZipReader::FileInfo fi = files.at(0); + QVERIFY(fi.isValid()); + QCOMPARE(fi.filePath, QString("symlink")); + QVERIFY(!fi.isDir); + QVERIFY(!fi.isFile); + QVERIFY(fi.isSymLink); + + QCOMPARE(zip.fileData("symlink"), QByteArray("destination")); + + fi = files.at(1); + QVERIFY(fi.isValid()); + QCOMPARE(fi.filePath, QString("destination")); + QVERIFY(!fi.isDir); + QVERIFY(fi.isFile); + QVERIFY(!fi.isSymLink); +} + +void tst_QZip::readTest() +{ + QZipReader zip("foobar.zip", QIODevice::ReadOnly); // non existing file. + QList<QZipReader::FileInfo> files = zip.fileInfoList(); + QCOMPARE(files.count(), 0); + QByteArray b = zip.fileData("foobar"); + QCOMPARE(b.size(), 0); +} + +void tst_QZip::createArchive() +{ + QBuffer buffer; + QZipWriter zip(&buffer); + QByteArray fileContents("simple file contents\nline2\n"); + zip.addFile("My Filename", fileContents); + zip.close(); + QByteArray zipFile = buffer.buffer(); + + // QFile f("createArchiveTest.zip"); f.open(QIODevice::WriteOnly); f.write(zipFile); f.close(); + + QBuffer buffer2(&zipFile); + QZipReader zip2(&buffer2); + QList<QZipReader::FileInfo> files = zip2.fileInfoList(); + QCOMPARE(files.count(), 1); + QZipReader::FileInfo file = files.at(0); + QCOMPARE(file.filePath, QString("My Filename")); + QCOMPARE(uint(file.isDir), (uint) 0); + QCOMPARE(uint(file.isFile), (uint) 1); + QCOMPARE(uint(file.isSymLink), (uint) 0); + QCOMPARE(file.permissions, QFile::Permissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::WriteUser) ); + QCOMPARE(file.size, (long long) 27); + QCOMPARE(zip2.fileData("My Filename"), fileContents); +} + +QTEST_MAIN(tst_QZip) +#include "tst_qzip.moc" diff --git a/tests/auto/gui/text/text.pro b/tests/auto/gui/text/text.pro new file mode 100644 index 0000000000..5055ab61a3 --- /dev/null +++ b/tests/auto/gui/text/text.pro @@ -0,0 +1,33 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qabstracttextdocumentlayout \ + qcssparser \ + qfont \ + qfontdatabase \ + qfontmetrics \ + qglyphrun \ + qrawfont \ + qstatictext \ + qsyntaxhighlighter \ + qtextblock \ + qtextcursor \ + qtextdocument \ + qtextdocumentfragment \ + qtextdocumentlayout \ + qtextformat \ + qtextlayout \ + qtextlist \ + qtextobject \ + qtextpiecetable \ + qtextscriptengine \ + qtexttable \ + +contains(QT_CONFIG, OdfWriter):SUBDIRS += qzip qtextodfwriter + +win32:SUBDIRS -= qtextpiecetable + +!contains(QT_CONFIG, private_tests): SUBDIRS -= \ + qcssparser \ + qstatictext \ + qtextlayout \ + qtextpiecetable \ diff --git a/tests/auto/gui/util/qdesktopservices/.gitignore b/tests/auto/gui/util/qdesktopservices/.gitignore new file mode 100644 index 0000000000..c7ce852ccd --- /dev/null +++ b/tests/auto/gui/util/qdesktopservices/.gitignore @@ -0,0 +1 @@ +tst_qdesktopservices diff --git a/tests/auto/gui/util/qdesktopservices/qdesktopservices.pro b/tests/auto/gui/util/qdesktopservices/qdesktopservices.pro new file mode 100644 index 0000000000..0e51ed0459 --- /dev/null +++ b/tests/auto/gui/util/qdesktopservices/qdesktopservices.pro @@ -0,0 +1,30 @@ +CONFIG += qttest_p4 +QT += widgets + +SOURCES += tst_qdesktopservices.cpp +TARGET = tst_qdesktopservices +symbian: { + dummy.files = text\\testfile.txt + dummy.path = . + + text.files = text\\* + text.path = \\data\\others + + image.files = image\\* + image.path = \\data\\images + + audio.files = audio\\* + audio.path = \\data\\sounds + + video.files = video\\* + video.path = \\data\\videos + + install.files = install\\* + install.path = \\data\\installs + + DEPLOYMENT += image audio video install + + # These are only needed for manual tests + #DEPLOYMENT += dummy text + } + diff --git a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp new file mode 100644 index 0000000000..8bea0a245b --- /dev/null +++ b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp @@ -0,0 +1,388 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QStandardItemModel> +#include <qdebug.h> +#include <qdesktopservices.h> + +//#define RUN_MANUAL_TESTS +//TESTED_CLASS= +//TESTED_FILES= + +class tst_qdesktopservices : public QObject { + Q_OBJECT + +public: + tst_qdesktopservices(); + virtual ~tst_qdesktopservices(); + +private slots: + void init(); + void cleanup(); + void openUrl(); +#ifdef Q_OS_SYMBIAN + // These test are manual ones, you need to check from device that + // correct system application is started with correct content + // When you want to run these test, uncomment //#define RUN_MANUAL_TESTS + void openHttpUrl_data(); + void openHttpUrl(); + void openMailtoUrl_data(); + void openMailtoUrl(); + void openFileUrl_data(); + void openFileUrl(); + void openMultipleFileUrls(); +#endif + void handlers(); + void storageLocation_data(); + void storageLocation(); + + void storageLocationDoesNotEndWithSlash_data(); + void storageLocationDoesNotEndWithSlash(); + +protected: +}; + +tst_qdesktopservices::tst_qdesktopservices() +{ + QCoreApplication::setOrganizationName("Nokia"); + QCoreApplication::setApplicationName("tst_qdesktopservices"); +} + +tst_qdesktopservices::~tst_qdesktopservices() +{ +} + +void tst_qdesktopservices::init() +{ +} + +void tst_qdesktopservices::cleanup() +{ +} + +void tst_qdesktopservices::openUrl() +{ + // At the bare minimum check that they return false for invalid url's + QCOMPARE(QDesktopServices::openUrl(QUrl()), false); +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + // this test is only valid on windows on other systems it might mean open a new document in the application handling .file + QCOMPARE(QDesktopServices::openUrl(QUrl("file://invalid.file")), false); +#endif +} + +#ifdef Q_OS_SYMBIAN +void tst_qdesktopservices::openHttpUrl_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<bool>("result"); + QTest::newRow("BasicWithHttp") << QUrl("http://www.google.fi") << true; + QTest::newRow("BasicWithoutHttp") << QUrl("www.nokia.fi") << true; + QTest::newRow("BasicWithUserAndPw") << QUrl("http://s60prereleases:oslofjord@pepper.troll.no/s60prereleases/patches/") << true; + QTest::newRow("URL with space") << QUrl("http://www.manataka.org/Contents Page.html") << true; + +} + +void tst_qdesktopservices::openHttpUrl() +{ +#ifndef RUN_MANUAL_TESTS + QSKIP("Test disabled -- only for manual purposes", SkipAll); +#endif + + QFETCH(QUrl, url); + QFETCH(bool, result); + QCOMPARE(QDesktopServices::openUrl(url), result); + QTest::qWait(30000); +} + +void tst_qdesktopservices::openMailtoUrl_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<bool>("result"); + + // http://en.wikipedia.org/wiki/E-mail_address + // RFC Valid e-mail addresses + QTest::newRow("Wiki valid email 1") << QUrl("mailto:abc@example.com") << true; + QTest::newRow("Wiki valid email 2") << QUrl("mailto:Abc@example.com") << true; + QTest::newRow("Wiki valid email 3") << QUrl("mailto:aBC@example.com") << true; + QTest::newRow("Wiki valid email 4") << QUrl("mailto:abc.123@example.com") << true; + QTest::newRow("Wiki valid email 5") << QUrl("mailto:1234567890@example.com") << true; + QTest::newRow("Wiki valid email 6") << QUrl("mailto:_______@example.com") << true; + QTest::newRow("Wiki valid email 7") << QUrl("mailto:abc+mailbox/department=shipping@example.com") << true; + // S60 email client considers the next URL invalid, even ity should be valid + QTest::newRow("Wiki valid email 8") << QUrl("mailto:!#$%&'*+-/=?^_`.{|}~@example.com") << true; // all of these characters are allowed + QTest::newRow("Wiki valid email 9") << QUrl("mailto:\"abc@def\"@example.com") << true; // anything goes inside quotation marks + QTest::newRow("Wiki valid email 10") << QUrl("mailto:\"Fred \\\"quota\\\" Bloggs\"@example.com") << true; // however, quotes need escaping + + // RFC invalid e-mail addresses + // These return true even though they are invalid, but check that user is notified about invalid URL in mail application + QTest::newRow("Wiki invalid email 1") << QUrl("mailto:Abc.example.com") << true; // character @ is missing + QTest::newRow("Wiki invalid email 2") << QUrl("mailto:Abc.@example.com") << true; // character dot(.) is last in local part + QTest::newRow("Wiki invalid email 3") << QUrl("mailto:Abc..123@example.com") << true; // character dot(.) is double + QTest::newRow("Wiki invalid email 4") << QUrl("mailto:A@b@c@example.com") << true; // only one @ is allowed outside quotations marks + QTest::newRow("Wiki invalid email 5") << QUrl("mailto:()[]\\;:,<>@example.com") << true; // none of the characters before the @ is allowed outside quotation marks + + QTest::newRow("Basic") << QUrl("mailto:test@nokia.com") << true; + QTest::newRow("BasicSeveralAddr") << QUrl("mailto:test@nokia.com,test2@nokia.com,test3@nokia.com") << true; + QTest::newRow("BasicAndSubject") << QUrl("mailto:test@nokia.com?subject=hello nokia") << true; + QTest::newRow("BasicAndTo") << QUrl("mailto:test@nokia.com?to=test2@nokia.com") << true; + + QTest::newRow("BasicAndCc") << QUrl("mailto:test@nokia.com?cc=mycc@address.com") << true; + QTest::newRow("BasicAndBcc") << QUrl("mailto:test@nokia.com?bcc=mybcc@address.com") << true; + QTest::newRow("BasicAndBody") << QUrl("mailto:test@nokia.com?body=Test email message body") << true; + + // RFC examples, these are actually invalid because there is not host defined + // Check that user is notified about invalid URL in mail application + QTest::newRow("RFC2368 Example 1") << QUrl::fromEncoded("mailto:addr1%2C%20addr2") << true; + QTest::newRow("RFC2368 Example 2") << QUrl::fromEncoded("mailto:?to=addr1%2C%20addr2") << true; + QTest::newRow("RFC2368 Example 3") << QUrl("mailto:addr1?to=addr2") << true; + + QTest::newRow("RFC2368 Example 4") << QUrl("mailto:joe@example.com?cc=bob@example.com&body=hello") << true; + QTest::newRow("RFC2368 Example 5") << QUrl("mailto:?to=joe@example.com&cc=bob@example.com&body=hello") << true; + QTest::newRow("RFC2368 Example 6") << QUrl("mailto:foobar@example.com?In-Reply-To=%3c3469A91.D10AF4C@example.com") << true; // OpaqueData + QTest::newRow("RFC2368 Example 7") << QUrl::fromEncoded("mailto:infobot@example.com?body=send%20current-issue%0D%0Asend%20index") << true; + QTest::newRow("RFC2368 Example 8") << QUrl::fromEncoded("mailto:infobot@example.com?body=send%20current-issue") << true; + QTest::newRow("RFC2368 Example 9") << QUrl("mailto:infobot@example.com?subject=current-issue") << true; + QTest::newRow("RFC2368 Example 10") << QUrl("mailto:chris@example.com") << true; + + //QTest::newRow("RFC2368 Example 11 - illegal chars") << QUrl("mailto:joe@example.com?cc=bob@example.com?body=hello") << false; + QTest::newRow("RFC2368 Example 12") << QUrl::fromEncoded("mailto:gorby%25kremvax@example.com") << true; // encoded reserved chars '%' + QTest::newRow("RFC2368 Example 13") << QUrl::fromEncoded("mailto:unlikely%3Faddress@example.com?blat=foop") << true; // encoded reserved chars `?' +} + +void tst_qdesktopservices::openMailtoUrl() +{ +#ifndef RUN_MANUAL_TESTS + QSKIP("Test disabled -- only for manual purposes", SkipAll); +#endif + + QFETCH(QUrl, url); + QFETCH(bool, result); + QCOMPARE(QDesktopServices::openUrl(url), result); + QTest::qWait(5000); +} + +void tst_qdesktopservices::openFileUrl_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<bool>("result"); + + // Text files + QTest::newRow("DOS text file") << QUrl("file:///c:/data/others/dosfile.txt") << true; + QTest::newRow("No EOF text file") << QUrl("file:///c:/data/others/noendofline.txt") << true; + QTest::newRow("text file") << QUrl("file:///c:/data/others/testfile.txt") << true; + QTest::newRow("text file with space") << QUrl("file:///c:/data/others/test file.txt") << true; + + // Images + QTest::newRow("BMP image") << QUrl("file:///c:/data/images/image.bmp") << true; + QTest::newRow("GIF image") << QUrl("file:///c:/data/images/image.gif") << true; + QTest::newRow("JPG image") << QUrl("file:///c:/data/images/image.jpg") << true; + QTest::newRow("PNG image") << QUrl("file:///c:/data/images/image.png") << true; + + // Audio + QTest::newRow("MP4 audio") << QUrl("file:///c:/data/sounds/aac-only.mp4") << true; + QTest::newRow("3GP audio") << QUrl("file:///c:/data/sounds/audio_3gpp.3gp") << true; + + // Video + QTest::newRow("MP4 video") << QUrl("file:///c:/data/videos/vid-mpeg4-22k.mp4") << true; + + // Installs + QTest::newRow("SISX") << QUrl("file:///c:/data/installs/ErrRd.sisx") << true; + + // Errors + QTest::newRow("File does not exist") << QUrl("file:///c:/thisfileneverexists.txt") << false; +} + +void tst_qdesktopservices::openFileUrl() +{ +#ifndef RUN_MANUAL_TESTS + QSKIP("Test disabled -- only for manual purposes", SkipAll); +#endif + + QFETCH(QUrl, url); + QFETCH(bool, result); + QCOMPARE(QDesktopServices::openUrl(url), result); + QTest::qWait(5000); +} + +void tst_qdesktopservices::openMultipleFileUrls() +{ +#ifndef RUN_MANUAL_TESTS + QSKIP("Test disabled -- only for manual purposes", SkipAll); +#endif + + QCOMPARE(QDesktopServices::openUrl(QUrl("file:///c:/data/images/image.bmp")), true); + QCOMPARE(QDesktopServices::openUrl(QUrl("file:///c:/data/images/image.png")), true); + QCOMPARE(QDesktopServices::openUrl(QUrl("file:///c:/data/others/noendofline.txt")), true); + QCOMPARE(QDesktopServices::openUrl(QUrl("file:///c:/data/installs/ErrRd.sisx")), true); +} +#endif + + +class MyUrlHandler : public QObject +{ + Q_OBJECT +public: + QUrl lastHandledUrl; + +public slots: + inline void handle(const QUrl &url) { + lastHandledUrl = url; + } +}; + +void tst_qdesktopservices::handlers() +{ + MyUrlHandler fooHandler; + MyUrlHandler barHandler; + + QDesktopServices::setUrlHandler(QString("foo"), &fooHandler, "handle"); + QDesktopServices::setUrlHandler(QString("bar"), &barHandler, "handle"); + + QUrl fooUrl("foo://blub/meh"); + QUrl barUrl("bar://hmm/hmmmm"); + + QVERIFY(QDesktopServices::openUrl(fooUrl)); + QVERIFY(QDesktopServices::openUrl(barUrl)); + + QCOMPARE(fooHandler.lastHandledUrl.toString(), fooUrl.toString()); + QCOMPARE(barHandler.lastHandledUrl.toString(), barUrl.toString()); +} + +Q_DECLARE_METATYPE(QDesktopServices::StandardLocation) +void tst_qdesktopservices::storageLocation_data() +{ + QTest::addColumn<QDesktopServices::StandardLocation>("location"); + QTest::newRow("DesktopLocation") << QDesktopServices::DesktopLocation; + QTest::newRow("DocumentsLocation") << QDesktopServices::DocumentsLocation; + QTest::newRow("FontsLocation") << QDesktopServices::FontsLocation; + QTest::newRow("ApplicationsLocation") << QDesktopServices::ApplicationsLocation; + QTest::newRow("MusicLocation") << QDesktopServices::MusicLocation; + QTest::newRow("MoviesLocation") << QDesktopServices::MoviesLocation; + QTest::newRow("PicturesLocation") << QDesktopServices::PicturesLocation; + QTest::newRow("TempLocation") << QDesktopServices::TempLocation; + QTest::newRow("HomeLocation") << QDesktopServices::HomeLocation; + QTest::newRow("DataLocation") << QDesktopServices::DataLocation; +} + +void tst_qdesktopservices::storageLocation() +{ + QFETCH(QDesktopServices::StandardLocation, location); +#ifdef Q_OS_SYMBIAN + QString storageLocation = QDesktopServices::storageLocation(location); + QString displayName = QDesktopServices::displayName(location); + //qDebug( "displayName: %s", displayName ); + + storageLocation = storageLocation.toLower(); + displayName = displayName.toLower(); + + QString drive = QDir::currentPath().left(2).toLower(); + if( drive == "z:" ) + drive = "c:"; + + switch(location) { + case QDesktopServices::DesktopLocation: + QCOMPARE( storageLocation, drive + QString("/data") ); + break; + case QDesktopServices::DocumentsLocation: + QCOMPARE( storageLocation, drive + QString("/data") ); + break; + case QDesktopServices::FontsLocation: + // Currently point always to ROM + QCOMPARE( storageLocation, QString("z:/resource/fonts") ); + break; + case QDesktopServices::ApplicationsLocation: +#ifdef Q_CC_NOKIAX86 + QCOMPARE( storageLocation, QString("z:/sys/bin") ); +#else + QCOMPARE( storageLocation, drive + QString("/sys/bin") ); +#endif + break; + case QDesktopServices::MusicLocation: + QCOMPARE( storageLocation, drive + QString("/data/sounds") ); + break; + case QDesktopServices::MoviesLocation: + QCOMPARE( storageLocation, drive + QString("/data/videos") ); + break; + case QDesktopServices::PicturesLocation: + QCOMPARE( storageLocation, drive + QString("/data/images") ); + break; + case QDesktopServices::TempLocation: + QCOMPARE( storageLocation, QDir::tempPath().toLower()); + break; + case QDesktopServices::HomeLocation: + QCOMPARE( storageLocation, QDir::homePath().toLower()); + break; + case QDesktopServices::DataLocation: + // Just check the folder not the drive + QCOMPARE( storageLocation.mid(2), QDir::currentPath().mid(2).toLower()); + break; + default: + QCOMPARE( storageLocation, QString() ); + break; + } + +#else + QDesktopServices::storageLocation(location); + QDesktopServices::displayName(location); +#endif +} + + +void tst_qdesktopservices::storageLocationDoesNotEndWithSlash_data() +{ + storageLocation_data(); +} + +void tst_qdesktopservices::storageLocationDoesNotEndWithSlash() +{ + // Currently all desktop locations return their storage location + // with "Unix-style" paths (i.e. they use a slash, not backslash). + QFETCH(QDesktopServices::StandardLocation, location); + QString loc = QDesktopServices::storageLocation(location); + if (loc.size() > 1) // workaround for unlikely case of locations that return '/' + QCOMPARE(loc.endsWith(QLatin1Char('/')), false); +} + + +QTEST_MAIN(tst_qdesktopservices) +#include "tst_qdesktopservices.moc" diff --git a/tests/auto/gui/util/util.pro b/tests/auto/gui/util/util.pro new file mode 100644 index 0000000000..91313ab85e --- /dev/null +++ b/tests/auto/gui/util/util.pro @@ -0,0 +1,4 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qdesktopservices \ + |