| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 |  | 
| 30 | #include <QtTest/QtTest> | 
| 31 |  | 
| 32 | #include <qpicture.h> | 
| 33 | #include <qpainter.h> | 
| 34 | #include <qimage.h> | 
| 35 | #include <qpaintengine.h> | 
| 36 | #include <qguiapplication.h> | 
| 37 | #include <qscreen.h> | 
| 38 | #include <limits.h> | 
| 39 |  | 
| 40 | class tst_QPicture : public QObject | 
| 41 | { | 
| 42 |     Q_OBJECT | 
| 43 |  | 
| 44 | public: | 
| 45 |     tst_QPicture(); | 
| 46 |  | 
| 47 | private slots: | 
| 48 |     void getSetCheck(); | 
| 49 |     void devType(); | 
| 50 |     void paintingActive(); | 
| 51 |     void boundingRect(); | 
| 52 |     void swap(); | 
| 53 |     void serialization(); | 
| 54 |     void save_restore(); | 
| 55 |     void boundaryValues_data(); | 
| 56 |     void boundaryValues(); | 
| 57 | }; | 
| 58 |  | 
| 59 | // Testing get/set functions | 
| 60 | void tst_QPicture::getSetCheck() | 
| 61 | { | 
| 62 |     QPictureIO obj1; | 
| 63 |     // const QPicture & QPictureIO::picture() | 
| 64 |     // void QPictureIO::setPicture(const QPicture &) | 
| 65 |     // const char * QPictureIO::format() | 
| 66 |     // void QPictureIO::setFormat(const char *) | 
| 67 |     const char var2[] = "PNG" ; | 
| 68 |     obj1.setFormat(var2); | 
| 69 |     QCOMPARE(var2, obj1.format()); | 
| 70 |     obj1.setFormat((char *)0); | 
| 71 |     // The format is stored internally in a QString, so return is always a valid char * | 
| 72 |     QVERIFY(QString(obj1.format()).isEmpty()); | 
| 73 |  | 
| 74 |     // const char * QPictureIO::parameters() | 
| 75 |     // void QPictureIO::setParameters(const char *) | 
| 76 |     const char var3[] = "Bogus data" ; | 
| 77 |     obj1.setParameters(var3); | 
| 78 |     QCOMPARE(var3, obj1.parameters()); | 
| 79 |     obj1.setParameters((char *)0); | 
| 80 |     // The format is stored internally in a QString, so return is always a valid char * | 
| 81 |     QVERIFY(QString(obj1.parameters()).isEmpty()); | 
| 82 | } | 
| 83 |  | 
| 84 | tst_QPicture::tst_QPicture() | 
| 85 | { | 
| 86 | } | 
| 87 |  | 
| 88 | void tst_QPicture::devType() | 
| 89 | { | 
| 90 |     QPicture p; | 
| 91 |     QCOMPARE( p.devType(), (int)QInternal::Picture ); | 
| 92 | } | 
| 93 |  | 
| 94 | void tst_QPicture::paintingActive() | 
| 95 | { | 
| 96 |     // actually implemented in QPainter but QPicture is a good | 
| 97 |     // example of an external paint device | 
| 98 |     QPicture p; | 
| 99 |     QVERIFY( !p.paintingActive() ); | 
| 100 |     QPainter pt( &p ); | 
| 101 |     QVERIFY( p.paintingActive() ); | 
| 102 |     pt.end(); | 
| 103 |     QVERIFY( !p.paintingActive() ); | 
| 104 | } | 
| 105 |  | 
| 106 | void tst_QPicture::boundingRect() | 
| 107 | { | 
| 108 |     QPicture p1; | 
| 109 |     // default value | 
| 110 |     QVERIFY( !p1.boundingRect().isValid() ); | 
| 111 |  | 
| 112 |     QRect r1( 20, 30, 5, 15 ); | 
| 113 |     p1.setBoundingRect( r1 ); | 
| 114 |     QCOMPARE( p1.boundingRect(), r1 ); | 
| 115 |     p1.setBoundingRect(QRect()); | 
| 116 |  | 
| 117 |     QPainter pt( &p1 ); | 
| 118 |     pt.drawLine( x1: 10, y1: 20, x2: 110, y2: 80 ); | 
| 119 |     pt.end(); | 
| 120 |  | 
| 121 |     // assignment and copy constructor | 
| 122 |     QRect r2( 10, 20, 100, 60 ); | 
| 123 |     QCOMPARE( p1.boundingRect(), r2 ); | 
| 124 |     QPicture p2( p1 ); | 
| 125 |     QCOMPARE( p2.boundingRect(), r2 ); | 
| 126 |     QPicture p3; | 
| 127 |     p3 = p1; | 
| 128 |     QCOMPARE( p3.boundingRect(), r2 ); | 
| 129 |  | 
| 130 |     { | 
| 131 |         QPicture p4; | 
| 132 |         QPainter p(&p4); | 
| 133 |         p.drawLine(x1: 0, y1: 0, x2: 5, y2: 0); | 
| 134 |         p.drawLine(x1: 0, y1: 0, x2: 0, y2: 5); | 
| 135 |         p.end(); | 
| 136 |  | 
| 137 |         QRect r3(0, 0, 5, 5); | 
| 138 |         QCOMPARE(p4.boundingRect(), r3); | 
| 139 |     } | 
| 140 | } | 
| 141 |  | 
| 142 | void tst_QPicture::swap() | 
| 143 | { | 
| 144 |     QPicture p1, p2; | 
| 145 |     QPainter(&p1).drawLine(x1: 0, y1: 0, x2: 5, y2: 5); | 
| 146 |     QPainter(&p2).drawLine(x1: 0, y1: 3, x2: 3, y2: 0); | 
| 147 |     QCOMPARE(p1.boundingRect(), QRect(0,0,5,5)); | 
| 148 |     QCOMPARE(p2.boundingRect(), QRect(0,0,3,3)); | 
| 149 |     p1.swap(other&: p2); | 
| 150 |     QCOMPARE(p1.boundingRect(), QRect(0,0,3,3)); | 
| 151 |     QCOMPARE(p2.boundingRect(), QRect(0,0,5,5)); | 
| 152 | } | 
| 153 |  | 
| 154 | Q_DECLARE_METATYPE(QDataStream::Version) | 
| 155 | Q_DECLARE_METATYPE(QPicture) | 
| 156 |  | 
| 157 | void ensureSerializesCorrectly(const QPicture &picture, QDataStream::Version version) | 
| 158 |  { | 
| 159 |     QDataStream stream; | 
| 160 |  | 
| 161 |     QBuffer buffer; | 
| 162 |     buffer.open(openMode: QIODevice::WriteOnly); | 
| 163 |     stream.setDevice(&buffer); | 
| 164 |     stream.setVersion(version); | 
| 165 |     stream << picture; | 
| 166 |     buffer.close(); | 
| 167 |  | 
| 168 |     buffer.open(openMode: QIODevice::ReadOnly); | 
| 169 |     QPicture readpicture; | 
| 170 |     stream >> readpicture; | 
| 171 |     QVERIFY2(memcmp(picture.data(), readpicture.data(), picture.size()) == 0, | 
| 172 |         qPrintable(QString::fromLatin1("Picture data does not compare equal for QDataStream version %1" ).arg(version))); | 
| 173 | } | 
| 174 |  | 
| 175 | class PaintEngine : public QPaintEngine | 
| 176 | { | 
| 177 | public: | 
| 178 |     PaintEngine() : QPaintEngine() {} | 
| 179 |     bool begin(QPaintDevice *) { return true; } | 
| 180 |     bool end() { return true; } | 
| 181 |     void updateState(const QPaintEngineState &) {} | 
| 182 |     void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {} | 
| 183 |     Type type() const { return Raster; } | 
| 184 |  | 
| 185 |     QFont font() { return state->font(); } | 
| 186 | }; | 
| 187 |  | 
| 188 | class Picture : public QPicture | 
| 189 | { | 
| 190 | public: | 
| 191 |     Picture() : QPicture() {} | 
| 192 |     QPaintEngine *paintEngine() const { return (QPaintEngine*)&mPaintEngine; } | 
| 193 | private: | 
| 194 |     PaintEngine mPaintEngine; | 
| 195 | }; | 
| 196 |  | 
| 197 | void tst_QPicture::serialization() | 
| 198 | { | 
| 199 |     QDataStream stream; | 
| 200 |     const int thisVersion = stream.version(); | 
| 201 |  | 
| 202 |     for (int version = QDataStream::Qt_1_0; version <= thisVersion; ++version) { | 
| 203 |         const QDataStream::Version versionEnum = static_cast<QDataStream::Version>(version); | 
| 204 |  | 
| 205 |         { | 
| 206 |             // streaming of null pictures | 
| 207 |             ensureSerializesCorrectly(picture: QPicture(), version: versionEnum); | 
| 208 |         } | 
| 209 |         { | 
| 210 |             // picture with a simple line, checking bitwise equality | 
| 211 |             QPicture picture; | 
| 212 |             QPainter painter(&picture); | 
| 213 |             painter.drawLine(x1: 10, y1: 20, x2: 30, y2: 40); | 
| 214 |             ensureSerializesCorrectly(picture, version: versionEnum); | 
| 215 |         } | 
| 216 |     } | 
| 217 |  | 
| 218 |     { | 
| 219 |         // Test features that were added after Qt 4.5, as that was hard-coded as the major | 
| 220 |         // version for a while, which was incorrect. In this case, we'll test font hints. | 
| 221 |         QPicture picture; | 
| 222 |         QPainter painter; | 
| 223 |         QFont font; | 
| 224 |         font.setStyleName("Blah" ); | 
| 225 |         font.setHintingPreference(QFont::PreferFullHinting); | 
| 226 |         painter.begin(&picture); | 
| 227 |         painter.setFont(font); | 
| 228 |         painter.drawText(x: 20, y: 20, s: "Hello" ); | 
| 229 |         painter.end(); | 
| 230 |  | 
| 231 |         Picture customPicture; | 
| 232 |         painter.begin(&customPicture); | 
| 233 |         picture.play(p: &painter); | 
| 234 |         const QFont actualFont = ((PaintEngine*)customPicture.paintEngine())->font(); | 
| 235 |         painter.end(); | 
| 236 |         QCOMPARE(actualFont.styleName(), QStringLiteral("Blah" )); | 
| 237 |         QCOMPARE(actualFont.hintingPreference(), QFont::PreferFullHinting); | 
| 238 |     } | 
| 239 | } | 
| 240 |  | 
| 241 | static QRectF scaleRect(const QRectF &rect, qreal xf, qreal yf) | 
| 242 | { | 
| 243 |     return QRectF(rect.left() * xf, rect.top() * yf, rect.width() * xf, rect.height() * yf); | 
| 244 | } | 
| 245 |  | 
| 246 | static void paintStuff(QPainter *p) | 
| 247 | { | 
| 248 |     const QScreen *screen = QGuiApplication::primaryScreen(); | 
| 249 |     // Calculate factors from the screen resolution against QPicture's 96DPI | 
| 250 |     // (enforced by Qt::AA_Use96Dpi as set by QTEST_MAIN). | 
| 251 |     const qreal xf = qreal(p->device()->logicalDpiX()) / screen->logicalDotsPerInchX(); | 
| 252 |     const qreal yf = qreal(p->device()->logicalDpiY()) / screen->logicalDotsPerInchY(); | 
| 253 |     p->drawRect(rect: scaleRect(rect: QRectF(100, 100, 100, 100), xf, yf)); | 
| 254 |     p->save(); | 
| 255 |     p->translate(dx: 10 * xf, dy: 10 * yf); | 
| 256 |     p->restore(); | 
| 257 |     p->drawRect(rect: scaleRect(rect: QRectF(100, 100, 100, 100), xf, yf)); | 
| 258 | } | 
| 259 |  | 
| 260 | /* See task: 41469 | 
| 261 |    Problem is that the state is not properly restored if the basestate of | 
| 262 |    the painter is different when the picture data was created compared to | 
| 263 |    the base state of the painter when it is played back. | 
| 264 |  */ | 
| 265 | void tst_QPicture::save_restore() | 
| 266 | { | 
| 267 |     QPicture pic; | 
| 268 |     QPainter p; | 
| 269 |     p.begin(&pic); | 
| 270 |     paintStuff(p: &p); | 
| 271 |     p.end(); | 
| 272 |  | 
| 273 |     QPixmap pix1(300, 300); | 
| 274 |     pix1.fill(fillColor: Qt::white); | 
| 275 |     p.begin(&pix1); | 
| 276 |     p.drawPicture(x: 50, y: 50, p: pic); | 
| 277 |     p.end(); | 
| 278 |  | 
| 279 |     QPixmap pix2(300, 300); | 
| 280 |     pix2.fill(fillColor: Qt::white); | 
| 281 |     p.begin(&pix2); | 
| 282 |     p.translate(dx: 50, dy: 50); | 
| 283 |     paintStuff(p: &p); | 
| 284 |     p.end(); | 
| 285 |  | 
| 286 |     QVERIFY( pix1.toImage() == pix2.toImage() ); | 
| 287 | } | 
| 288 |  | 
| 289 | void tst_QPicture::boundaryValues_data() | 
| 290 | { | 
| 291 |     QTest::addColumn<int>(name: "x" ); | 
| 292 |     QTest::addColumn<int>(name: "y" ); | 
| 293 |     QTest::newRow(dataTag: "max x" ) << INT_MAX << 50; | 
| 294 |     QTest::newRow(dataTag: "max y" ) << 50 << INT_MAX; | 
| 295 |     QTest::newRow(dataTag: "max x and y" ) << INT_MAX << INT_MAX; | 
| 296 |  | 
| 297 |     QTest::newRow(dataTag: "min x" ) << INT_MIN << 50; | 
| 298 |     QTest::newRow(dataTag: "min y" ) << 50 << INT_MIN; | 
| 299 |     QTest::newRow(dataTag: "min x and y" ) << INT_MIN << INT_MIN; | 
| 300 |  | 
| 301 |     QTest::newRow(dataTag: "min x, max y" ) << INT_MIN << INT_MAX; | 
| 302 |     QTest::newRow(dataTag: "max x, min y" ) << INT_MAX << INT_MIN; | 
| 303 | } | 
| 304 |  | 
| 305 | void tst_QPicture::boundaryValues() | 
| 306 | { | 
| 307 |     QPicture picture; | 
| 308 |  | 
| 309 |     QPainter painter; | 
| 310 |     painter.begin(&picture); | 
| 311 |  | 
| 312 |     QFETCH(int, x); | 
| 313 |     QFETCH(int, y); | 
| 314 |     painter.drawPoint(p: QPoint(x, y)); | 
| 315 |  | 
| 316 |     painter.end(); | 
| 317 | } | 
| 318 |  | 
| 319 |  | 
| 320 | QTEST_MAIN(tst_QPicture) | 
| 321 | #include "tst_qpicture.moc" | 
| 322 |  |