| 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 | #if 0 |
| 33 | #include <private/qpaintengine_svg_p.h> |
| 34 | #endif |
| 35 | |
| 36 | #include <qapplication.h> |
| 37 | #include <qpainter.h> |
| 38 | #include <qbuffer.h> |
| 39 | #include <qimage.h> |
| 40 | #include <qpicture.h> |
| 41 | #include <qdrawutil.h> |
| 42 | #include <qpaintdevice.h> |
| 43 | |
| 44 | class tst_QSvgDevice : public QObject |
| 45 | { |
| 46 | Q_OBJECT |
| 47 | public: |
| 48 | tst_QSvgDevice(); |
| 49 | |
| 50 | private slots: |
| 51 | void play_data(); |
| 52 | void play(); |
| 53 | void boundingRect(); |
| 54 | |
| 55 | private: |
| 56 | void playPaint( QPainter *p, const QString &type ); |
| 57 | }; |
| 58 | |
| 59 | tst_QSvgDevice::tst_QSvgDevice() |
| 60 | { |
| 61 | } |
| 62 | |
| 63 | void tst_QSvgDevice::play_data() |
| 64 | { |
| 65 | QTest::addColumn<QString>(name: "tag name" ); |
| 66 | // we only use the tag name |
| 67 | QTest::newRow( dataTag: "lines" ); |
| 68 | QTest::newRow( dataTag: "font" ); |
| 69 | QTest::newRow( dataTag: "polyline" ); |
| 70 | QTest::newRow( dataTag: "translate" ); |
| 71 | QTest::newRow( dataTag: "scaleRect" ); |
| 72 | QTest::newRow( dataTag: "ellipseOdd" ); |
| 73 | QTest::newRow( dataTag: "ellipseEven" ); |
| 74 | QTest::newRow( dataTag: "ellipseRandom" ); |
| 75 | QTest::newRow( dataTag: "scaleText" ); |
| 76 | QTest::newRow( dataTag: "scaleTextWithFont" ); |
| 77 | QTest::newRow( dataTag: "scaleTextSaveRestore" ); |
| 78 | QTest::newRow( dataTag: "scaleLineWithPen" ); |
| 79 | QTest::newRow( dataTag: "task-17637" ); |
| 80 | QTest::newRow( dataTag: "dashed-lines" ); |
| 81 | QTest::newRow( dataTag: "dot-lines" ); |
| 82 | QTest::newRow( dataTag: "dashed-dot-lines" ); |
| 83 | QTest::newRow( dataTag: "dashed-dot-dot-lines" ); |
| 84 | QTest::newRow( dataTag: "scaleDashed-lines" ); |
| 85 | QTest::newRow( dataTag: "thick-dashed-lines" ); |
| 86 | QTest::newRow( dataTag: "negative-rect" ); |
| 87 | QTest::newRow( dataTag: "lightText" ); |
| 88 | QTest::newRow( dataTag: "boldText" ); |
| 89 | QTest::newRow( dataTag: "demiBoldText" ); |
| 90 | QTest::newRow( dataTag: "blackText" ); |
| 91 | QTest::newRow( dataTag: "task-20239" ); |
| 92 | QTest::newRow( dataTag: "clipRect" ); |
| 93 | QTest::newRow( dataTag: "multipleClipRects" ); |
| 94 | QTest::newRow(dataTag: "qsimplerichtext" ); |
| 95 | } |
| 96 | |
| 97 | #if 0 |
| 98 | |
| 99 | class SVGDummyDevice : public QPaintDevice |
| 100 | { |
| 101 | public: |
| 102 | SVGDummyDevice() |
| 103 | : QPaintDevice(QInternal::ExternalDevice), eng(0) { } |
| 104 | ~SVGDummyDevice() { |
| 105 | delete eng; |
| 106 | } |
| 107 | QPaintEngine *engine() const { |
| 108 | if (!eng) |
| 109 | const_cast<SVGDummyDevice *>(this)->eng = new QSVGPaintEngine; |
| 110 | return eng; |
| 111 | } |
| 112 | |
| 113 | private: |
| 114 | QPaintEngine *eng; |
| 115 | }; |
| 116 | |
| 117 | void tst_QSvgDevice::play() |
| 118 | { |
| 119 | // current tag name |
| 120 | QString type = data()->dataTag(); |
| 121 | |
| 122 | // reference pixmap |
| 123 | QPixmap ref( 100, 100 ); |
| 124 | ref.fill( Qt::white ); |
| 125 | QPainter pref( &ref ); |
| 126 | playPaint( &pref, type ); |
| 127 | pref.end(); |
| 128 | |
| 129 | // draw the same into the SVG device |
| 130 | SVGDummyDevice dev; |
| 131 | QPainter pdev( &dev ); |
| 132 | playPaint( &pdev, type ); |
| 133 | pdev.end(); |
| 134 | |
| 135 | |
| 136 | //dev.setBoundingRect( QRect( 0, 0, 100, 100 ) ); |
| 137 | //dev.save( type + "-res.svg" ); // ### sets bounding rect to 0 ! |
| 138 | |
| 139 | // replay on a result pixmap and compare |
| 140 | QPixmap res( 100, 100 ); |
| 141 | res.fill( Qt::white ); |
| 142 | QPainter pres( &res ); |
| 143 | static_cast<QSVGPaintEngine *>(dev.engine())->play( &pres ); |
| 144 | |
| 145 | #if 0 |
| 146 | // for visual inspection |
| 147 | ref.save( type + "-ref.xpm" , "XPM" ); |
| 148 | res.save( type + "-res.xpm" , "XPM" ); |
| 149 | #endif |
| 150 | |
| 151 | QVERIFY( res.convertToImage() == ref.convertToImage() ); |
| 152 | } |
| 153 | |
| 154 | // helper function for play() |
| 155 | void tst_QSvgDevice::playPaint( QPainter *p, const QString &type ) |
| 156 | { |
| 157 | if ( type == "lines" ) { |
| 158 | // line with pen width 0 |
| 159 | p->setPen( QPen( Qt::black, 0, Qt::SolidLine ) ); |
| 160 | p->drawLine( 10, 0, 20, 3 ); |
| 161 | |
| 162 | // line with pen width 1 |
| 163 | p->setPen( QPen( Qt::black, 1, Qt::SolidLine ) ); |
| 164 | p->drawLine( 2, 0, 10, 3 ); |
| 165 | |
| 166 | // rect without outline (qt-bugs/arc-17/35556) |
| 167 | p->setPen( Qt::NoPen ); |
| 168 | p->setBrush( Qt::red ); |
| 169 | p->drawRect( 5, 10, 20, 30 ); |
| 170 | } else if ( type == "text" ) { |
| 171 | QFont f = p->font(); |
| 172 | f.setItalic( TRUE ); |
| 173 | f.setBold( TRUE ); |
| 174 | p->setFont( f ); |
| 175 | p->drawText( 5, 55, "Text" ); |
| 176 | } else if ( type == "polyline" ) { |
| 177 | // we'll draw 4 triangular polylines. Only two will show up |
| 178 | // as the QPainter::drawPolyline() doesn't respect the brush |
| 179 | // just the pen setting |
| 180 | QPolygon pa( 3 ); |
| 181 | pa.setPoint( 0, 0, 0 ); |
| 182 | pa.setPoint( 1, 10, 0 ); |
| 183 | pa.setPoint( 2, 0, 10 ); |
| 184 | |
| 185 | // frame around the following 4 polylines |
| 186 | p->setBrush( Qt::NoBrush ); |
| 187 | p->setPen( Qt::SolidLine ); |
| 188 | p->drawRect( 46, 3, 19, 60 ); |
| 189 | |
| 190 | // polyline with blue brush, no pen |
| 191 | p->setPen( Qt::NoPen ); |
| 192 | p->setBrush( Qt::blue ); |
| 193 | p->translate( 50, 5 ); |
| 194 | p->drawPolyline( pa ); |
| 195 | |
| 196 | // polyline without brush, no pen |
| 197 | p->setBrush( Qt::NoBrush ); |
| 198 | p->translate( 0, 15 ); |
| 199 | p->drawPolyline( pa ); |
| 200 | |
| 201 | // polyline with green brush, solid pen |
| 202 | p->setBrush( Qt::green ); |
| 203 | p->setPen( Qt::SolidLine ); |
| 204 | p->translate( 0, 15 ); |
| 205 | p->drawPolyline( pa ); |
| 206 | |
| 207 | // polyline without brush, solid pen |
| 208 | p->setBrush( Qt::NoBrush ); |
| 209 | p->setPen( Qt::SolidLine ); |
| 210 | p->translate( 0, 15 ); |
| 211 | p->drawPolyline( pa ); |
| 212 | } else if ( type == "translate" ) { |
| 213 | p->translate(-10,-10); |
| 214 | p->save(); |
| 215 | p->setBrush( Qt::blue ); |
| 216 | p->drawRect( 20, 30, 50, 20 ); |
| 217 | p->restore(); |
| 218 | p->setBrush( Qt::green ); |
| 219 | p->drawRect( 70, 50, 10, 10 ); |
| 220 | } else if ( type == "scaleRect" ) { |
| 221 | p->scale( 1, 2 ); |
| 222 | p->setBrush( Qt::blue ); |
| 223 | p->drawRect( 20, 20, 60, 60 ); |
| 224 | } else if ( type == "ellipseEven" ) { |
| 225 | p->setBrush( Qt::blue ); |
| 226 | p->drawEllipse( 20, 20, 60, 60 ); |
| 227 | } else if ( type == "ellipseOdd" ) { |
| 228 | p->setBrush( Qt::blue ); |
| 229 | p->drawEllipse( 20, 20, 59, 59 ); |
| 230 | } else if ( type == "ellipseRandom" ) { |
| 231 | p->setBrush( Qt::blue ); |
| 232 | p->drawEllipse( 20, 34, 89, 123 ); |
| 233 | } else if ( type == "scaleText" ) { |
| 234 | p->scale(0.25,0.25); |
| 235 | p->drawText(200,200,"Hello!" ); |
| 236 | } else if ( type == "scaleTextWithFont" ) { |
| 237 | p->setFont(QFont("Helvetica" ,12)); |
| 238 | p->scale(0.25,0.25); |
| 239 | p->drawText(200,200,"Hello!" ); |
| 240 | #ifdef Q_WS_WIN |
| 241 | // Only test on Windows for now, visually it looks fine, but |
| 242 | // it's failing for some reason on Linux |
| 243 | } else if ( type == "scaleTextSaveRestore" ) { |
| 244 | p->scale(1,-1); |
| 245 | p->save(); |
| 246 | p->setFont(QFont("Helvetica" ,12)); |
| 247 | p->scale(0.5,0.5); |
| 248 | p->drawText(0,0,"Hello!" ); |
| 249 | p->restore(); |
| 250 | #endif |
| 251 | } else if ( type == "scaleLineWithPen" ) { |
| 252 | p->scale(0.1,0.1); |
| 253 | p->setPen(QPen(Qt::red,100)); |
| 254 | p->drawLine(3,3,500,500); |
| 255 | } else if ( type == "task-17637" ) { |
| 256 | p->translate(0,200); |
| 257 | p->scale(0.01,-0.01); |
| 258 | p->setBrush(Qt::blue); |
| 259 | p->drawEllipse(2000,2000,6000,6000); |
| 260 | p->setPen(QPen(Qt::red,100)); |
| 261 | p->setFont(QFont("Helvetica" ,12)); |
| 262 | p->save(); |
| 263 | p->scale(1,-1); |
| 264 | p->drawText(4000,4000,"Hello!" ); |
| 265 | p->restore(); |
| 266 | p->drawLine(3000,3000,5000,5000); |
| 267 | } else if ( type == "dashed-lines" ) { |
| 268 | p->setPen(QPen(Qt::red, 1, Qt::DashLine)); |
| 269 | p->drawLine(10,10,50,50); |
| 270 | } else if ( type == "dot-lines" ) { |
| 271 | p->setPen(QPen(Qt::red, 1, Qt::DotLine)); |
| 272 | p->drawLine(10,10,50,50); |
| 273 | } else if ( type == "dashed-dot-lines" ) { |
| 274 | p->setPen(QPen(Qt::red, 1, Qt::DashDotLine)); |
| 275 | p->drawLine(10,10,50,50); |
| 276 | } else if ( type == "dashed-dot-dot-lines" ) { |
| 277 | p->setPen(QPen(Qt::red, 1, Qt::DashDotDotLine)); |
| 278 | p->drawLine(10,10,50,50); |
| 279 | } else if ( type == "scaleDashed-lines" ) { |
| 280 | p->scale(0.1,0.1); |
| 281 | p->setPen(QPen(Qt::red, 10, Qt::DashLine)); |
| 282 | p->drawLine(10,10,500,500); |
| 283 | } else if ( type == "thick-dashed-lines" ) { |
| 284 | p->setPen(QPen(Qt::red, 10, Qt::DashLine)); |
| 285 | p->drawLine(10,10,50,50); |
| 286 | } else if ( type == "negative-rect" ) { |
| 287 | p->drawRect(70, 0,-30,30); |
| 288 | } else if ( type == "lightText" ) { |
| 289 | QFont f("Helvetica" ,12); |
| 290 | f.setWeight( QFont::Light ); |
| 291 | p->setFont(f); |
| 292 | p->drawText(0,0,"Hello!" ); |
| 293 | } else if ( type == "boldText" ) { |
| 294 | QFont f("Helvetica" ,12); |
| 295 | f.setWeight( QFont::Bold ); |
| 296 | p->setFont(f); |
| 297 | p->drawText(0,0,"Hello!" ); |
| 298 | } else if ( type == "demiBoldText" ) { |
| 299 | QFont f("Helvetica" ,12); |
| 300 | f.setWeight( QFont::DemiBold ); |
| 301 | p->setFont(f); |
| 302 | p->drawText(0,0,"Hello!" ); |
| 303 | } else if ( type == "blackText" ) { |
| 304 | QFont f("Helvetica" ,12); |
| 305 | f.setWeight( QFont::Black ); |
| 306 | p->setFont(f); |
| 307 | p->drawText(0,0,"Hello!" ); |
| 308 | } else if ( type == "task-20239" ) { |
| 309 | p->translate(0,200); |
| 310 | p->scale(0.02,-0.02); |
| 311 | p->scale(1,-1); |
| 312 | for(int y = 1000; y <=10000; y += 2000) { |
| 313 | QBrush br(Qt::green); |
| 314 | QPalette palette(Qt::green,Qt::blue); |
| 315 | qDrawShadePanel(p,4000,5000,4000,2000,palette.active(),false,200,&br); |
| 316 | qDrawShadeRect(p,2000,2000,4000,2000,palette.active(),true,100,0,&br); |
| 317 | } |
| 318 | } else if (type=="clipRect" ) { |
| 319 | p->setClipRect(15,25,10,10); |
| 320 | p->drawEllipse(10,20,50,70); |
| 321 | } else if (type=="multipleClipRects" ) { |
| 322 | p->setClipRect(15,25,10,10); |
| 323 | p->drawEllipse(10,20,50,70); |
| 324 | p->setClipRect(100,200,20,20); |
| 325 | p->drawEllipse(110,220,50,70); |
| 326 | } else if (type == "qsimplerichtext" ) { |
| 327 | p->setPen(QColor(0,0,0)); |
| 328 | p->setBrush(Qt::NoBrush); |
| 329 | QRect rect1(10, 10, 100, 50); |
| 330 | QRect rect2(200, 20, 80, 50); |
| 331 | p->drawRect(10, 10, 100, 50); |
| 332 | p->drawRect(200, 20, 80, 50); |
| 333 | |
| 334 | QSimpleRichText text1("Text 1" , QApplication::font()); |
| 335 | QSimpleRichText text2("Text 2" , QApplication::font()); |
| 336 | |
| 337 | QColorGroup cg(Qt::black, Qt::red, Qt::gray, Qt::gray, Qt::gray, Qt::black, Qt::blue, Qt::black, Qt::white); |
| 338 | text1.draw(p, rect1.x(), rect1.y(), rect1, cg); |
| 339 | text2.draw(p, rect2.x(), rect2.y(), rect2, cg); |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | void tst_QSvgDevice::boundingRect() |
| 344 | { |
| 345 | // ### the bounding rect is only calculated/parsed |
| 346 | // ### when replaying. Therefore we go through QPicture. |
| 347 | QRect r( 10, 20, 30, 40 ); |
| 348 | // create document |
| 349 | QPicture pic; |
| 350 | QPainter p( &pic ); |
| 351 | p.drawRect( r ); |
| 352 | p.end(); |
| 353 | pic.save( "tmp.svg" , "svg" ); |
| 354 | // load it |
| 355 | QPicture pic2; |
| 356 | pic2.load( "tmp.svg" , "svg" ); |
| 357 | QCOMPARE( pic2.boundingRect(), r ); |
| 358 | } |
| 359 | |
| 360 | #else |
| 361 | |
| 362 | void tst_QSvgDevice::play() |
| 363 | { |
| 364 | QSKIP("This test needs some redoing, this is just a temp measure until I work it out" ); |
| 365 | } |
| 366 | |
| 367 | void tst_QSvgDevice::boundingRect() |
| 368 | { |
| 369 | QSKIP("This test needs some redoing, this is just a temp measure until I work it out" ); |
| 370 | } |
| 371 | |
| 372 | #endif |
| 373 | |
| 374 | QTEST_MAIN(tst_QSvgDevice) |
| 375 | #include "tst_qsvgdevice.moc" |
| 376 | |