13716940b10e5fe1bf9d0c731f3b291d47facb92
[profile/ivi/qtbase.git] / tests / auto / gui / painting / qpainter / tst_qpainter.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44 #include <qpainter.h>
45 #ifndef QT_NO_WIDGETS
46 #include <qdrawutil.h>
47 #include <qapplication.h>
48 #include <qwidget.h>
49 #endif
50 #include <qfontmetrics.h>
51 #include <qbitmap.h>
52 #include <qimage.h>
53 #include <qthread.h>
54 #include <limits.h>
55 #if !defined(Q_OS_WINCE)
56 #ifndef QT_NO_WIDGETS
57 #include <qprinter.h>
58 #endif
59 #include <math.h>
60 #endif
61 #include <qpaintengine.h>
62 #ifndef QT_NO_WIDGETS
63 #include <qdesktopwidget.h>
64 #endif
65 #include <qpixmap.h>
66
67 #include <qpainter.h>
68
69 #ifndef QT_NO_WIDGETS
70 #include <qlabel.h>
71 #endif
72
73 #include <qqueue.h>
74
75 #ifndef QT_NO_WIDGETS
76 #include <qgraphicsview.h>
77 #include <qgraphicsscene.h>
78 #include <qgraphicsproxywidget.h>
79 #include <qlayout.h>
80 #endif
81 #include <qfontdatabase.h>
82
83 Q_DECLARE_METATYPE(QGradientStops)
84 Q_DECLARE_METATYPE(QLine)
85 Q_DECLARE_METATYPE(QRect)
86 Q_DECLARE_METATYPE(QSize)
87 Q_DECLARE_METATYPE(QPoint)
88 Q_DECLARE_METATYPE(QPainterPath)
89
90 class tst_QPainter : public QObject
91 {
92 Q_OBJECT
93
94 public:
95     tst_QPainter();
96     virtual ~tst_QPainter();
97
98
99 public slots:
100     void init();
101     void cleanup();
102     void cleanupTestCase();
103 private slots:
104     void getSetCheck();
105 #ifndef QT_NO_WIDGETS
106     void drawPixmap_comp_data();
107     void drawPixmap_comp();
108 #endif
109     void saveAndRestore_data();
110     void saveAndRestore();
111
112 #ifndef QT_NO_WIDGETS
113     void drawBorderPixmap();
114 #endif
115     void drawPixmapFragments();
116
117     void drawLine_data();
118     void drawLine();
119     void drawLine_clipped();
120     void drawLine_task121143();
121     void drawLine_task216948();
122
123     void drawLine_task190634();
124     void drawLine_task229459();
125     void drawLine_task234891();
126
127     void drawRect_data() { fillData(); }
128     void drawRect();
129     void drawRect2();
130
131     void fillRect();
132     void fillRect2();
133     void fillRect3();
134     void fillRect4();
135
136     void drawEllipse_data();
137     void drawEllipse();
138     void drawClippedEllipse_data();
139     void drawClippedEllipse();
140
141     void drawPath_data();
142     void drawPath();
143     void drawPath2();
144     void drawPath3();
145
146     void drawRoundRect_data() { fillData(); }
147     void drawRoundRect();
148
149     void qimageFormats_data();
150     void qimageFormats();
151     void textOnTransparentImage();
152
153 #ifndef QT_NO_WIDGETS
154     void initFrom();
155 #endif
156
157     void setWindow();
158
159     void combinedMatrix();
160     void renderHints();
161
162     void disableEnableClipping();
163     void setClipRect();
164     void setEqualClipRegionAndPath_data();
165     void setEqualClipRegionAndPath();
166
167     void clipRectSaveRestore();
168
169     void clippedFillPath_data();
170     void clippedFillPath();
171     void clippedLines_data();
172     void clippedLines();
173     void clippedPolygon_data();
174     void clippedPolygon();
175
176     void clippedText();
177
178     void clipBoundingRect();
179
180     void setOpacity_data();
181     void setOpacity();
182
183     void drawhelper_blend_untransformed_data();
184     void drawhelper_blend_untransformed();
185     void drawhelper_blend_tiled_untransformed_data();
186     void drawhelper_blend_tiled_untransformed();
187
188     void porterDuff_warning();
189
190     void drawhelper_blend_color();
191
192 #ifndef QT_NO_WIDGETS
193     void childWidgetViewport();
194 #endif
195
196     void fillRect_objectBoundingModeGradient();
197     void fillRect_stretchToDeviceMode();
198     void monoImages();
199
200     void linearGradientSymmetry_data();
201     void linearGradientSymmetry();
202     void gradientInterpolation();
203
204     void fpe_pixmapTransform();
205     void fpe_zeroLengthLines();
206     void fpe_divByZero();
207
208     void fpe_steepSlopes_data();
209     void fpe_steepSlopes();
210     void fpe_rasterizeLine_task232012();
211
212     void fpe_radialGradients();
213
214     void rasterizer_asserts();
215     void rasterizer_negativeCoords();
216
217     void blendOverFlow_data();
218     void blendOverFlow();
219
220     void largeImagePainting_data();
221     void largeImagePainting();
222
223     void imageScaling_task206785();
224
225     void outlineFillConsistency();
226
227     void drawImage_task217400_data();
228     void drawImage_task217400();
229     void drawImage_1x1();
230     void drawImage_task258776();
231     void drawRect_task215378();
232     void drawRect_task247505();
233
234     void drawText_subPixelPositionsInRaster_qtbug5053();
235
236     void drawImage_data();
237     void drawImage();
238
239     void clippedImage();
240
241     void stateResetBetweenQPainters();
242
243     void imageCoordinateLimit();
244     void imageBlending_data();
245     void imageBlending();
246     void imageBlending_clipped();
247
248     void paintOnNullPixmap();
249     void checkCompositionMode();
250
251     void drawPolygon();
252
253     void inactivePainter();
254
255     void extendedBlendModes();
256
257     void zeroOpacity();
258     void clippingBug();
259     void emptyClip();
260
261     void taskQT4444_dontOverflowDashOffset();
262
263     void painterBegin();
264     void setPenColorOnImage();
265     void setPenColorOnPixmap();
266
267 #ifndef QT_NO_WIDGETS
268     void QTBUG5939_attachPainterPrivate();
269 #endif
270
271     void drawPointScaled();
272
273     void QTBUG14614_gradientCacheRaceCondition();
274     void drawTextOpacity();
275
276     void QTBUG17053_zeroDashPattern();
277
278     void drawTextOutsideGuiThread();
279
280     void drawTextWithComplexBrush();
281     void QTBUG26013_squareCapStroke();
282     void QTBUG25153_drawLine();
283
284 private:
285     void fillData();
286     void setPenColor(QPainter& p);
287     QColor baseColor( int k, int intensity=255 );
288     QImage getResImage( const QString &dir, const QString &addition, const QString &extension );
289     QBitmap getBitmap( const QString &dir, const QString &filename, bool mask );
290 };
291
292 // Testing get/set functions
293 void tst_QPainter::getSetCheck()
294 {
295     QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
296     QPainter obj1;
297     obj1.begin(&img);
298     // CompositionMode QPainter::compositionMode()
299     // void QPainter::setCompositionMode(CompositionMode)
300     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceOver));
301     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceOver), obj1.compositionMode());
302     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOver));
303     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOver), obj1.compositionMode());
304     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Clear));
305     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Clear), obj1.compositionMode());
306     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Source));
307     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Source), obj1.compositionMode());
308     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Destination));
309     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Destination), obj1.compositionMode());
310     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceIn));
311     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceIn), obj1.compositionMode());
312     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationIn));
313     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationIn), obj1.compositionMode());
314     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceOut));
315     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceOut), obj1.compositionMode());
316     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOut));
317     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOut), obj1.compositionMode());
318     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceAtop));
319     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceAtop), obj1.compositionMode());
320     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationAtop));
321     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationAtop), obj1.compositionMode());
322     obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Xor));
323     QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Xor), obj1.compositionMode());
324
325     // const QPen & QPainter::pen()
326     // void QPainter::setPen(const QPen &)
327     QPen var3(Qt::red);
328     obj1.setPen(var3);
329     QCOMPARE(var3, obj1.pen());
330     obj1.setPen(QPen());
331     QCOMPARE(QPen(), obj1.pen());
332
333     // const QBrush & QPainter::brush()
334     // void QPainter::setBrush(const QBrush &)
335     QBrush var4(Qt::red);
336     obj1.setBrush(var4);
337     QCOMPARE(var4, obj1.brush());
338     obj1.setBrush(QBrush());
339     QCOMPARE(QBrush(), obj1.brush());
340
341     // const QBrush & QPainter::background()
342     // void QPainter::setBackground(const QBrush &)
343     QBrush var5(Qt::yellow);
344     obj1.setBackground(var5);
345     QCOMPARE(var5, obj1.background());
346     obj1.setBackground(QBrush());
347     QCOMPARE(QBrush(), obj1.background());
348
349     // bool QPainter::matrixEnabled()
350     // void QPainter::setMatrixEnabled(bool)
351     obj1.setMatrixEnabled(false);
352     QCOMPARE(false, obj1.matrixEnabled());
353     obj1.setMatrixEnabled(true);
354     QCOMPARE(true, obj1.matrixEnabled());
355
356     // bool QPainter::viewTransformEnabled()
357     // void QPainter::setViewTransformEnabled(bool)
358     obj1.setViewTransformEnabled(false);
359     QCOMPARE(false, obj1.viewTransformEnabled());
360     obj1.setViewTransformEnabled(true);
361     QCOMPARE(true, obj1.viewTransformEnabled());
362 }
363
364 Q_DECLARE_METATYPE(QPixmap)
365 Q_DECLARE_METATYPE(QPolygon)
366 Q_DECLARE_METATYPE(QBrush)
367 Q_DECLARE_METATYPE(QPen)
368 Q_DECLARE_METATYPE(QFont)
369 Q_DECLARE_METATYPE(QColor)
370 Q_DECLARE_METATYPE(QRegion)
371
372 tst_QPainter::tst_QPainter()
373 {
374     // QtTestCase sets this to false, but this turns off alpha pixmaps on Unix.
375     QGuiApplication::setDesktopSettingsAware(true);
376 }
377
378 tst_QPainter::~tst_QPainter()
379 {
380 }
381
382 void tst_QPainter::init()
383 {
384 }
385
386 void tst_QPainter::cleanup()
387 {
388 }
389
390 void tst_QPainter::cleanupTestCase()
391 {
392     QFile::remove(QLatin1String("dest.png"));
393     QFile::remove(QLatin1String("expected.png"));
394     QFile::remove(QLatin1String("foo.png"));
395 }
396
397 static const char* const maskSource_data[] = {
398 "16 13 6 1",
399 ". c None",
400 "d c #000000",
401 "# c #999999",
402 "c c #cccccc",
403 "b c #ffff00",
404 "a c #ffffff",
405 "...#####........",
406 "..#aaaaa#.......",
407 ".#abcbcba######.",
408 ".#acbcbcaaaaaa#d",
409 ".#abcbcbcbcbcb#d",
410 "#############b#d",
411 "#aaaaaaaaaa##c#d",
412 "#abcbcbcbcbbd##d",
413 ".#abcbcbcbcbcd#d",
414 ".#acbcbcbcbcbd#d",
415 "..#acbcbcbcbb#dd",
416 "..#############d",
417 "...ddddddddddddd"};
418
419 static const char* const maskResult_data[] = {
420 "16 13 6 1",
421 ". c #ff0000",
422 "d c #000000",
423 "# c #999999",
424 "c c #cccccc",
425 "b c #ffff00",
426 "a c #ffffff",
427 "...#####........",
428 "..#aaaaa#.......",
429 ".#abcbcba######.",
430 ".#acbcbcaaaaaa#d",
431 ".#abcbcbcbcbcb#d",
432 "#############b#d",
433 "#aaaaaaaaaa##c#d",
434 "#abcbcbcbcbbd##d",
435 ".#abcbcbcbcbcd#d",
436 ".#acbcbcbcbcbd#d",
437 "..#acbcbcbcbb#dd",
438 "..#############d",
439 "...ddddddddddddd"};
440
441
442 #ifndef QT_NO_WIDGETS
443 void tst_QPainter::drawPixmap_comp_data()
444 {
445     if (qApp->desktop()->depth() < 24)
446         QSKIP("Test only works on 32 bit displays");
447
448     QTest::addColumn<uint>("dest");
449     QTest::addColumn<uint>("source");
450
451     QTest::newRow("0% on 0%, 1")           << 0x00000000u<< 0x00000000u;
452     QTest::newRow("0% on 0%, 2")           << 0x00007fffu << 0x00ff007fu;
453
454     QTest::newRow("50% on a=0%")           << 0x00000000u << 0x7fff0000u;
455     QTest::newRow("50% on a=50%")          << 0x7f000000u << 0x7fff0000u;
456     QTest::newRow("50% on deadbeef")      << 0xdeafbeefu <<  0x7fff0000u;
457     QTest::newRow("deadbeef on a=0%")      << 0x00000000u << 0xdeadbeefu;
458     QTest::newRow("deadbeef on a=50%")     << 0x7f000000u << 0xdeadbeefu;
459     QTest::newRow("50% blue on 50% red")   << 0x7fff0000u << 0x7f0000ffu;
460     QTest::newRow("50% blue on 50% green") << 0x7f00ff00u << 0x7f0000ffu;
461     QTest::newRow("50% red on 50% green")  << 0x7f00ff00u << 0x7fff0000u;
462     QTest::newRow("0% on 50%")             << 0x7fff00ffu << 0x00ffffffu;
463     QTest::newRow("100% on deadbeef")      << 0xdeafbeefu << 0xffabcdefu;
464     QTest::newRow("100% on a=0%")           << 0x00000000u << 0xffabcdefu;
465 }
466
467 QRgb qt_compose_alpha(QRgb source, QRgb dest)
468 {
469     int r1 = qRed(dest), g1 = qGreen(dest), b1 = qBlue(dest), a1 = qAlpha(dest);
470     int r2 = qRed(source), g2 = qGreen(source), b2 = qBlue(source), a2 = qAlpha(source);
471
472     int alpha = qMin(a2 + ((255 - a2) * a1 + 127) / 255, 255);
473     if (alpha == 0)
474         return qRgba(0, 0, 0, 0);
475
476     return qRgba(
477         qMin((r2 * a2 + (255 - a2) * r1 * a1 / 255) / alpha, 255),
478         qMin((g2 * a2 + (255 - a2) * g1 * a1 / 255) / alpha, 255),
479         qMin((b2 * a2 + (255 - a2) * b1 * a1 / 255) / alpha, 255),
480         alpha);
481 }
482
483 /* Tests that drawing masked pixmaps works
484 */
485 void tst_QPainter::drawPixmap_comp()
486 {
487 #ifdef Q_OS_MAC
488     QSKIP("Mac has other ideas about alpha composition");
489 #endif
490     QFETCH(uint, dest);
491     QFETCH(uint, source);
492
493     QRgb expected = qt_compose_alpha(source, dest);
494
495     QColor c1(qRed(dest), qGreen(dest), qBlue(dest), qAlpha(dest));
496     QColor c2(qRed(source), qGreen(source), qBlue(source), qAlpha(source));
497
498     QPixmap destPm(10, 10), srcPm(10, 10);
499     destPm.fill(c1);
500     srcPm.fill(c2);
501
502 #if defined(Q_WS_X11)
503     if (!destPm.x11PictureHandle())
504         QSKIP("Requires XRender support");
505 #endif
506
507     QPainter p(&destPm);
508     p.drawPixmap(0, 0, srcPm);
509     p.end();
510
511     QImage result = destPm.toImage().convertToFormat(QImage::Format_ARGB32);
512     bool different = false;
513     for (int y=0; y<result.height(); ++y)
514         for (int x=0; x<result.width(); ++x) {
515             bool diff;
516             if (qAlpha(expected) == 0) {
517                 diff = qAlpha(result.pixel(x, y)) != 0;
518             } else {
519                 // Compensate for possible roundoff / platform fudge
520                 int off = 1;
521                 QRgb pix = result.pixel(x, y);
522                 diff = (qAbs(qRed(pix) - qRed(expected)) > off)
523                              || (qAbs(qGreen(pix) - qGreen(expected)) > off)
524                              || (qAbs(qBlue(pix) - qBlue(expected)) > off)
525                              || (qAbs(qAlpha(pix) - qAlpha(expected)) > off);
526             }
527             if (diff && !different)
528                 qDebug( "Different at %d,%d pixel [%d,%d,%d,%d] expected [%d,%d,%d,%d]", x, y,
529                         qRed(result.pixel(x, y)), qGreen(result.pixel(x, y)),
530                         qBlue(result.pixel(x, y)), qAlpha(result.pixel(x, y)),
531                         qRed(expected), qGreen(expected), qBlue(expected), qAlpha(expected));
532             different |= diff;
533         }
534
535     QVERIFY(!different);
536 }
537 #endif
538
539 void tst_QPainter::saveAndRestore_data()
540 {
541     QTest::addColumn<QFont>("font");
542     QTest::addColumn<QPen>("pen");
543     QTest::addColumn<QBrush>("brush");
544     QTest::addColumn<QColor>("backgroundColor");
545     QTest::addColumn<int>("backgroundMode");
546     QTest::addColumn<QPoint>("brushOrigin");
547     QTest::addColumn<QRegion>("clipRegion");
548     QTest::addColumn<QRect>("window");
549     QTest::addColumn<QRect>("viewport");
550
551     QPixmap pixmap(1, 1);
552     QPainter p(&pixmap);
553     QFont font = p.font();
554     QPen pen = p.pen();
555     QBrush brush = p.brush();
556     QColor backgroundColor = p.background().color();
557     Qt::BGMode backgroundMode = p.backgroundMode();
558     QPoint brushOrigin = p.brushOrigin();
559     QRegion clipRegion = p.clipRegion();
560     QRect window = p.window();
561     QRect viewport = p.viewport();
562
563     QTest::newRow("Original") << font << pen << brush << backgroundColor << int(backgroundMode)
564             << brushOrigin << clipRegion << window << viewport;
565
566     QFont font2 = font;
567     font2.setPointSize( 24 );
568     QTest::newRow("Modified font.pointSize, brush, backgroundColor, backgroundMode")
569             << font2 << pen << QBrush(Qt::red) << QColor(Qt::blue) << int(Qt::TransparentMode)
570             << brushOrigin << clipRegion << window << viewport;
571
572     font2 = font;
573     font2.setPixelSize( 20 );
574     QTest::newRow("Modified font.pixelSize, brushOrigin, pos")
575             << font2 << pen << brush << backgroundColor << int(backgroundMode)
576             << QPoint( 50, 32 ) << clipRegion << window << viewport;
577
578     QTest::newRow("Modified clipRegion, window, viewport")
579             << font << pen << brush << backgroundColor << int(backgroundMode)
580             << brushOrigin << clipRegion.subtracted(QRect(10,10,50,30))
581             << QRect(-500, -500, 500, 500 ) << QRect( 0, 0, 50, 50 );
582 }
583
584 void tst_QPainter::saveAndRestore()
585 {
586     QFETCH( QFont, font );
587     QFETCH( QPen, pen );
588     QFETCH( QBrush, brush );
589     QFETCH( QColor, backgroundColor );
590     QFETCH( int, backgroundMode );
591     QFETCH( QPoint, brushOrigin );
592     QFETCH( QRegion, clipRegion );
593     QFETCH( QRect, window );
594     QFETCH( QRect, viewport );
595
596     QPixmap pixmap(1, 1);
597     QPainter painter(&pixmap);
598
599     QFont font_org = painter.font();
600     QPen pen_org = painter.pen();
601     QBrush brush_org = painter.brush();
602     QColor backgroundColor_org = painter.background().color();
603     Qt::BGMode backgroundMode_org = painter.backgroundMode();
604     QPoint brushOrigin_org = painter.brushOrigin();
605     QRegion clipRegion_org = painter.clipRegion();
606     QRect window_org = painter.window();
607     QRect viewport_org = painter.viewport();
608
609     painter.save();
610     painter.setFont( font );
611     painter.setPen( QPen(pen) );
612     painter.setBrush( brush );
613     painter.setBackground( backgroundColor );
614     painter.setBackgroundMode( (Qt::BGMode)backgroundMode );
615     painter.setBrushOrigin( brushOrigin );
616     painter.setClipRegion( clipRegion );
617     painter.setWindow( window );
618     painter.setViewport( viewport );
619     painter.restore();
620
621     QCOMPARE( painter.font(), font_org );
622     QCOMPARE( painter.font().pointSize(), font_org.pointSize() );
623     QCOMPARE( painter.font().pixelSize(), font_org.pixelSize() );
624     QCOMPARE( painter.pen(), pen_org );
625     QCOMPARE( painter.brush(), brush_org );
626     QCOMPARE( painter.background().color(), backgroundColor_org );
627     QCOMPARE( painter.backgroundMode(), backgroundMode_org );
628     QCOMPARE( painter.brushOrigin(), brushOrigin_org );
629     QCOMPARE( painter.clipRegion(), clipRegion_org );
630     QCOMPARE( painter.window(), window_org );
631     QCOMPARE( painter.viewport(), viewport_org );
632 }
633
634 /*
635    Helper functions
636 */
637
638 QColor tst_QPainter::baseColor( int k, int intensity )
639 {
640     int r = ( k & 1 ) * intensity;
641     int g = ( (k>>1) & 1 ) * intensity;
642     int b = ( (k>>2) & 1 ) * intensity;
643     return QColor( r, g, b );
644 }
645
646 QImage tst_QPainter::getResImage( const QString &dir, const QString &addition, const QString &extension )
647 {
648     QImage res;
649     QString resFilename  = dir + QString( "/res_%1." ).arg( addition ) + extension;
650     if ( !res.load( resFilename ) ) {
651         QWARN(QString("Could not load result data %s %1").arg(resFilename).toLatin1());
652         return QImage();
653     }
654     return res;
655 }
656
657 QBitmap tst_QPainter::getBitmap( const QString &dir, const QString &filename, bool mask )
658 {
659     QBitmap bm;
660     QString bmFilename = dir + QString( "/%1.xbm" ).arg( filename );
661     if ( !bm.load( bmFilename ) ) {
662         QWARN(QString("Could not load bitmap '%1'").arg(bmFilename).toLatin1());
663         return QBitmap();
664     }
665     if ( mask ) {
666         QBitmap mask;
667         QString maskFilename = dir + QString( "/%1-mask.xbm" ).arg( filename );
668         if ( !mask.load( maskFilename ) ) {
669         QWARN(QString("Could not load mask '%1'").arg(maskFilename).toLatin1());
670         return QBitmap();
671         }
672         bm.setMask( mask );
673     }
674     return bm;
675 }
676
677 static int getPaintedPixels(const QImage &image, const QColor &background)
678 {
679     uint color = background.rgba();
680
681     int pixels = 0;
682
683     for (int y = 0; y < image.height(); ++y)
684         for (int x = 0; x < image.width(); ++x)
685             if (image.pixel(x, y) != color)
686                 ++pixels;
687
688     return pixels;
689 }
690
691 static QRect getPaintedSize(const QImage &image, const QColor &background)
692 {
693     // not the fastest but at least it works..
694     int xmin = image.width() + 1;
695     int xmax = -1;
696     int ymin = image.height() +1;
697     int ymax = -1;
698
699     uint color = background.rgba();
700
701     for ( int y = 0; y < image.height(); ++y ) {
702         for ( int x = 0; x < image.width(); ++x ) {
703             QRgb pixel = image.pixel( x, y );
704             if ( pixel != color && x < xmin )
705                 xmin = x;
706             if ( pixel != color && x > xmax )
707                 xmax = x;
708             if ( pixel != color && y < ymin )
709                 ymin = y;
710             if ( pixel != color && y > ymax )
711                 ymax = y;
712         }
713     }
714
715     return QRect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
716 }
717
718 static QRect getPaintedSize(const QPixmap &pm, const QColor &background)
719 {
720     return getPaintedSize(pm.toImage(), background);
721 }
722
723 #ifndef QT_NO_WIDGETS
724 void tst_QPainter::initFrom()
725 {
726     QWidget *widget = new QWidget();
727     QPalette pal = widget->palette();
728     pal.setColor(QPalette::Foreground, QColor(255, 0, 0));
729     pal.setBrush(QPalette::Background, QColor(0, 255, 0));
730     widget->setPalette(pal);
731
732     QFont font = widget->font();
733     font.setPointSize(26);
734     font.setItalic(true);
735     widget->setFont(font);
736
737     QPixmap pm(100, 100);
738     QPainter p(&pm);
739     p.initFrom(widget);
740
741     QCOMPARE(p.font(), font);
742     QCOMPARE(p.pen().color(), pal.color(QPalette::Foreground));
743     QCOMPARE(p.background(), pal.background());
744
745     delete widget;
746 }
747
748 void tst_QPainter::drawBorderPixmap()
749 {
750     QPixmap src(79,79);
751     src.fill(Qt::transparent);
752
753     QImage pm(200,200,QImage::Format_RGB32);
754     QPainter p(&pm);
755     p.setTransform(QTransform(-1,0,0,-1,173.5,153.5));
756     qDrawBorderPixmap(&p, QRect(0,0,75,105), QMargins(39,39,39,39), src, QRect(0,0,79,79), QMargins(39,39,39,39),
757                        QTileRules(Qt::StretchTile,Qt::StretchTile), 0);
758 }
759 #endif
760
761 void tst_QPainter::drawPixmapFragments()
762 {
763     QPixmap origPixmap(20, 20);
764     QPixmap resPixmap(20, 20);
765     QPainter::PixmapFragment fragments[4] = { {15, 15,  0,  0, 10, 10, 1, 1, 0, 1},
766                                               { 5, 15, 10,  0, 10, 10, 1, 1, 0, 1},
767                                               {15,  5,  0, 10, 10, 10, 1, 1, 0, 1},
768                                               { 5,  5, 10, 10, 10, 10, 1, 1, 0, 1} };
769     {
770         QPainter p(&origPixmap);
771         p.fillRect(0, 0, 10, 10, Qt::red);
772         p.fillRect(10, 0, 10, 10, Qt::green);
773         p.fillRect(0, 10, 10, 10, Qt::blue);
774         p.fillRect(10, 10, 10, 10, Qt::yellow);
775     }
776     {
777         QPainter p(&resPixmap);
778         p.drawPixmapFragments(fragments, 4, origPixmap);
779     }
780
781     QImage origImage = origPixmap.toImage().convertToFormat(QImage::Format_ARGB32);
782     QImage resImage = resPixmap.toImage().convertToFormat(QImage::Format_ARGB32);
783
784     QVERIFY(resImage.size() == resPixmap.size());
785     QVERIFY(resImage.pixel(5, 5) == origImage.pixel(15, 15));
786     QVERIFY(resImage.pixel(5, 15) == origImage.pixel(15, 5));
787     QVERIFY(resImage.pixel(15, 5) == origImage.pixel(5, 15));
788     QVERIFY(resImage.pixel(15, 15) == origImage.pixel(5, 5));
789
790
791     QPainter::PixmapFragment fragment = QPainter::PixmapFragment::create(QPointF(20, 20), QRectF(30, 30, 2, 2));
792     QVERIFY(fragment.x == 20);
793     QVERIFY(fragment.y == 20);
794     QVERIFY(fragment.sourceLeft == 30);
795     QVERIFY(fragment.sourceTop == 30);
796     QVERIFY(fragment.width == 2);
797     QVERIFY(fragment.height == 2);
798     QVERIFY(fragment.scaleX == 1);
799     QVERIFY(fragment.scaleY == 1);
800     QVERIFY(fragment.rotation == 0);
801     QVERIFY(fragment.opacity == 1);
802 }
803
804 void tst_QPainter::drawLine_data()
805 {
806     QTest::addColumn<QLine>("line");
807
808     QTest::newRow("0-45") << QLine(0, 20, 100, 0);
809     QTest::newRow("45-90") << QLine(0, 100, 20, 0);
810     QTest::newRow("90-135") << QLine(20, 100, 0, 0);
811     QTest::newRow("135-180") << QLine(100, 20, 0, 0);
812     QTest::newRow("180-225") << QLine(100, 0, 0, 20);
813     QTest::newRow("225-270") << QLine(20, 0, 0, 100);
814     QTest::newRow("270-315") << QLine(0, 0, 20, 100);
815     QTest::newRow("315-360") << QLine(0, 0, 100, 20);
816 }
817
818 void tst_QPainter::drawLine()
819 {
820     const int offset = 5;
821     const int epsilon = 1; // allow for one pixel difference
822
823     QFETCH(QLine, line);
824
825     QPixmap pixmapUnclipped(qMin(line.x1(), line.x2())
826                             + 2*offset + qAbs(line.dx()),
827                             qMin(line.y1(), line.y2())
828                             + 2*offset + qAbs(line.dy()));
829
830     { // unclipped
831         pixmapUnclipped.fill(Qt::white);
832         QPainter p(&pixmapUnclipped);
833         p.translate(offset, offset);
834         p.setPen(QPen(Qt::black));
835         p.drawLine(line);
836         p.end();
837
838         const QRect painted = getPaintedSize(pixmapUnclipped, Qt::white);
839
840         QLine l = line;
841         l.translate(offset, offset);
842         QVERIFY(qAbs(painted.width() - qAbs(l.dx())) <= epsilon);
843         QVERIFY(qAbs(painted.height() - qAbs(l.dy())) <= epsilon);
844         QVERIFY(qAbs(painted.top() - qMin(l.y1(), l.y2())) <= epsilon);
845         QVERIFY(qAbs(painted.left() - qMin(l.x1(), l.x2())) <= epsilon);
846         QVERIFY(qAbs(painted.bottom() - qMax(l.y1(), l.y2())) <= epsilon);
847         QVERIFY(qAbs(painted.right() - qMax(l.x1(), l.x2())) <= epsilon);
848     }
849
850     QPixmap pixmapClipped(qMin(line.x1(), line.x2())
851                           + 2*offset + qAbs(line.dx()),
852                           qMin(line.y1(), line.y2())
853                           + 2*offset + qAbs(line.dy()));
854     { // clipped
855         const QRect clip = QRect(line.p1(), line.p2()).normalized();
856
857         pixmapClipped.fill(Qt::white);
858         QPainter p(&pixmapClipped);
859         p.translate(offset, offset);
860         p.setClipRect(clip);
861         p.setPen(QPen(Qt::black));
862         p.drawLine(line);
863         p.end();
864     }
865
866     const QImage unclipped = pixmapUnclipped.toImage();
867     const QImage clipped = pixmapClipped.toImage();
868     QCOMPARE(unclipped, clipped);
869 }
870
871 void tst_QPainter::drawLine_clipped()
872 {
873     QImage image(16, 1, QImage::Format_ARGB32_Premultiplied);
874     image.fill(0x0);
875
876     QPainter p(&image);
877     p.setPen(QPen(Qt::black, 10));
878
879     // this should fill the whole image
880     p.drawLine(-1, -1, 17, 1);
881     p.end();
882
883     for (int x = 0; x < 16; ++x)
884         QCOMPARE(image.pixel(x, 0), 0xff000000);
885 }
886
887 void tst_QPainter::drawLine_task121143()
888 {
889     QPen pen(Qt::black);
890
891     QImage image(5, 5, QImage::Format_ARGB32_Premultiplied);
892     image.fill(0xffffffff);
893     QPainter p(&image);
894     p.setPen(pen);
895     p.drawLine(QLine(0, 0+4, 0+4, 0));
896     p.end();
897
898     QImage expected(5, 5, QImage::Format_ARGB32_Premultiplied);
899     expected.fill(0xffffffff);
900     for (int x = 0; x < 5; ++x)
901         expected.setPixel(x, 5-x-1, pen.color().rgb());
902
903     QCOMPARE(image, expected);
904 }
905
906 void tst_QPainter::drawLine_task190634()
907 {
908     QPen pen(Qt::black, 3);
909
910     QImage image(32, 32, QImage::Format_ARGB32_Premultiplied);
911     QPainter p(&image);
912     p.fillRect(0, 0, image.width(), image.height(), Qt::white);
913
914     p.setPen(pen);
915     p.drawLine(QLineF(2, -1.6, 10, -1.6));
916     p.end();
917
918     const uint *data = reinterpret_cast<uint *>(image.bits());
919
920     for (int i = 0; i < image.width() * image.height(); ++i)
921         QCOMPARE(data[i], 0xffffffff);
922
923     p.begin(&image);
924     p.fillRect(0, 0, image.width(), image.height(), Qt::white);
925
926     p.setPen(pen);
927     p.drawLine(QLineF(-1.6, 2, -1.6, 10));
928     p.end();
929
930     data = reinterpret_cast<uint *>(image.bits());
931
932     for (int i = 0; i < image.width() * image.height(); ++i)
933         QCOMPARE(data[i], 0xffffffff);
934
935     p.begin(&image);
936     p.fillRect(0, 0, image.width(), image.height(), Qt::white);
937
938     p.setPen(pen);
939     p.drawLine( QPoint(2,-2), QPoint(3,-5) );
940     p.end();
941
942     data = reinterpret_cast<uint *>(image.bits());
943
944     for (int i = 0; i < image.width() * image.height(); ++i)
945         QCOMPARE(data[i], 0xffffffff);
946 }
947
948 void tst_QPainter::drawLine_task229459()
949 {
950     QImage image(32, 32, QImage::Format_ARGB32_Premultiplied);
951     image.fill(0x0);
952     QPen pen(Qt::black, 64);
953
954     QPainter p(&image);
955     p.setPen(pen);
956     p.drawLine(-8, -8, 10000000, 10000000);
957     p.end();
958
959     QImage expected = image;
960     expected.fill(0xff000000);
961
962     QCOMPARE(image, expected);
963 }
964
965 void tst_QPainter::drawLine_task234891()
966 {
967     QImage img(100, 1000, QImage::Format_ARGB32_Premultiplied);
968     img.fill(0x0);
969     QImage expected = img;
970
971     QPainter p(&img);
972     p.setPen(QPen(QBrush(QColor(255,0,0)), 6));
973     p.drawLine(QPointF(25000,100),QPointF(30000,105));
974
975     p.setPen(QPen(QBrush(QColor(0,255,0)), 6));
976     p.drawLine(QPointF(30000,150),QPointF(35000,155));
977
978     p.setPen(QPen(QBrush(QColor(0,0,255)), 6));
979     p.drawLine(QPointF(65000,200),QPointF(66000,205));
980
981     QCOMPARE(expected, img);
982 }
983
984 void tst_QPainter::drawLine_task216948()
985 {
986     QImage img(1, 10, QImage::Format_ARGB32_Premultiplied);
987     img.fill(0x0);
988
989     QPainter p(&img);
990     QLine line(10, 0, 10, 10);
991     p.translate(-10, 0);
992     p.drawLine(line);
993     p.end();
994
995     for (int i = 0; i < img.height(); ++i)
996         QCOMPARE(img.pixel(0, i), QColor(Qt::black).rgba());
997 }
998
999 void tst_QPainter::drawRect()
1000 {
1001     QFETCH(QRect, rect);
1002     QFETCH(bool, usePen);
1003
1004     QPixmap pixmap(rect.x() + rect.width() + 10,
1005                    rect.y() + rect.height() + 10);
1006     {
1007         pixmap.fill(Qt::white);
1008         QPainter p(&pixmap);
1009         p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1010         p.setBrush(Qt::black);
1011         p.drawRect(rect);
1012         p.end();
1013
1014         int increment = usePen ? 1 : 0;
1015
1016         const QRect painted = getPaintedSize(pixmap, Qt::white);
1017         QCOMPARE(painted.width(), rect.width() + increment);
1018         QCOMPARE(painted.height(), rect.height() + increment);
1019     }
1020 }
1021
1022 void tst_QPainter::drawRect2()
1023 {
1024     QImage image(64, 64, QImage::Format_ARGB32_Premultiplied);
1025     {
1026         image.fill(0xffffffff);
1027
1028         QTransform transform(0.368567, 0, 0, 0, 0.368567, 0, 0.0289, 0.0289, 1);
1029
1030         QPainter p(&image);
1031         p.setTransform(transform);
1032         p.setBrush(Qt::red);
1033         p.setPen(Qt::NoPen);
1034         p.drawRect(QRect(14, 14, 39, 39));
1035         p.end();
1036
1037         QRect fill = getPaintedSize(image, Qt::white);
1038         image.fill(0xffffffff);
1039
1040         p.begin(&image);
1041         p.setTransform(transform);
1042         p.drawRect(QRect(14, 14, 39, 39));
1043         p.end();
1044
1045         QRect stroke = getPaintedSize(image, Qt::white);
1046         QCOMPARE(stroke.adjusted(1, 1, 0, 0), fill.adjusted(0, 0, 1, 1));
1047     }
1048 }
1049
1050 void tst_QPainter::fillRect()
1051 {
1052     QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
1053     image.fill(QColor(0, 0, 0, 0).rgba());
1054
1055     QPainter p(&image);
1056
1057     p.fillRect(0, 0, 100, 100, QColor(255, 0, 0, 127));
1058
1059 //    pixmap.save("bla1.png", "PNG");
1060     QCOMPARE(getPaintedSize(image, QColor(0, 0, 0, 0)),
1061              QRect(0, 0, 100, 100));
1062     QCOMPARE(getPaintedSize(image, QColor(127, 0, 0, 127)).isValid(),
1063              QRect().isValid());
1064
1065     p.setCompositionMode(QPainter::CompositionMode_SourceIn);
1066     p.fillRect(50, 0, 50, 100, QColor(0, 0, 255, 255));
1067
1068     QCOMPARE(getPaintedSize(image, QColor(127, 0, 0, 127)),
1069              QRect(50, 0, 50, 100));
1070     QCOMPARE(getPaintedSize(image, QColor(0, 0, 127, 127)),
1071              QRect(0, 0, 50, 100));
1072 }
1073
1074 void tst_QPainter::fillRect2()
1075 {
1076     QRgb background = 0x0;
1077
1078     QImage img(1, 20, QImage::Format_ARGB32_Premultiplied);
1079     img.fill(background);
1080
1081     QPainter p(&img);
1082
1083     QRectF rect(0, 1, 1.2, 18);
1084     p.fillRect(rect, Qt::black);
1085
1086     p.end();
1087
1088     QCOMPARE(img.pixel(0, 0), background);
1089     QCOMPARE(img.pixel(0, img.height() - 1), background);
1090
1091     QCOMPARE(img.pixel(0, 1), img.pixel(0, 2));
1092     QCOMPARE(img.pixel(0, img.height() - 2), img.pixel(0, img.height() - 3));
1093 }
1094
1095 void tst_QPainter::fillRect3()
1096 {
1097     QImage img(1, 1, QImage::Format_ARGB32_Premultiplied);
1098     img.fill(QColor(Qt::black).rgba());
1099
1100     QPainter p(&img);
1101     p.setCompositionMode(QPainter::CompositionMode_Source);
1102     p.fillRect(img.rect(), Qt::transparent);
1103     p.end();
1104
1105     QCOMPARE(img.pixel(0, 0), 0U);
1106 }
1107
1108 void tst_QPainter::fillRect4()
1109 {
1110     QImage image(100, 1, QImage::Format_ARGB32_Premultiplied);
1111     image.fill(0x0);
1112
1113     QImage expected = image;
1114     expected.fill(0xffffffff);
1115
1116     QPainter p(&image);
1117     p.scale(1.1, 1);
1118     p.setPen(Qt::NoPen);
1119
1120     for (int i = 0; i < 33; ++i)
1121         p.fillRect(QRectF(3 * i, 0, 3, 1), Qt::white);
1122
1123     p.end();
1124
1125     QCOMPARE(image, expected);
1126 }
1127
1128 void tst_QPainter::drawPath_data()
1129 {
1130     QTest::addColumn<QPainterPath>("path");
1131     QTest::addColumn<QRect>("expectedBounds");
1132     QTest::addColumn<int>("expectedPixels");
1133
1134     {
1135         QPainterPath p;
1136         p.addRect(2, 2, 10, 10);
1137         QTest::newRow("int-aligned rect") << p << QRect(2, 2, 10, 10) << 10 * 10;
1138     }
1139
1140     {
1141         QPainterPath p;
1142         p.addRect(2.25, 2.25, 10, 10);
1143         QTest::newRow("non-aligned rect") << p << QRect(3, 3, 10, 10) << 10 * 10;
1144     }
1145
1146     {
1147         QPainterPath p;
1148         p.addRect(2.25, 2.25, 10.5, 10.5);
1149         QTest::newRow("non-aligned rect 2") << p << QRect(3, 3, 10, 10) << 10 * 10;
1150     }
1151
1152     {
1153         QPainterPath p;
1154         p.addRect(2.5, 2.5, 10, 10);
1155         QTest::newRow("non-aligned rect 3") << p << QRect(3, 3, 10, 10) << 10 * 10;
1156     }
1157
1158     {
1159         QPainterPath p;
1160         p.addRect(2, 2, 10, 10);
1161         p.addRect(4, 4, 6, 6);
1162         QTest::newRow("rect-in-rect") << p << QRect(2, 2, 10, 10) << 10 * 10 - 6 * 6;
1163     }
1164
1165     {
1166         QPainterPath p;
1167         p.addRect(2, 2, 10, 10);
1168         p.addRect(4, 4, 6, 6);
1169         p.addRect(6, 6, 2, 2);
1170         QTest::newRow("rect-in-rect-in-rect") << p << QRect(2, 2, 10, 10) << 10 * 10 - 6 * 6 + 2 * 2;
1171     }
1172 }
1173
1174 void tst_QPainter::drawPath()
1175 {
1176     QFETCH(QPainterPath, path);
1177     QFETCH(QRect, expectedBounds);
1178     QFETCH(int, expectedPixels);
1179
1180     const int offset = 2;
1181
1182     QImage image(expectedBounds.width() + 2 * offset, expectedBounds.height() + 2 * offset,
1183                  QImage::Format_ARGB32_Premultiplied);
1184     image.fill(QColor(Qt::white).rgb());
1185
1186     QPainter p(&image);
1187     p.setPen(Qt::NoPen);
1188     p.setBrush(Qt::black);
1189     p.translate(offset - expectedBounds.left(), offset - expectedBounds.top());
1190     p.drawPath(path);
1191     p.end();
1192
1193     const QRect paintedBounds = getPaintedSize(image, Qt::white);
1194
1195     QCOMPARE(paintedBounds.x(), offset);
1196     QCOMPARE(paintedBounds.y(), offset);
1197     QCOMPARE(paintedBounds.width(), expectedBounds.width());
1198     QCOMPARE(paintedBounds.height(), expectedBounds.height());
1199
1200     if (expectedPixels != -1) {
1201         int paintedPixels = getPaintedPixels(image, Qt::white);
1202         QCOMPARE(paintedPixels, expectedPixels);
1203     }
1204 }
1205
1206 void tst_QPainter::drawPath2()
1207 {
1208     const int w = 50;
1209
1210     for (int h = 5; h < 200; ++h) {
1211         QPainterPath p1, p2;
1212         p1.lineTo(w, 0);
1213         p1.lineTo(w, h);
1214
1215         p2.lineTo(w, h);
1216         p2.lineTo(0, h);
1217
1218         const int offset = 2;
1219
1220         QImage image(w + 2 * offset, h + 2 * offset,
1221                      QImage::Format_ARGB32_Premultiplied);
1222         image.fill(QColor(Qt::white).rgb());
1223
1224         QPainter p(&image);
1225         p.setPen(Qt::NoPen);
1226         p.setBrush(Qt::black);
1227         p.translate(offset, offset);
1228         p.drawPath(p1);
1229         p.end();
1230
1231         const int p1Pixels = getPaintedPixels(image, Qt::white);
1232
1233         image.fill(QColor(Qt::white).rgb());
1234         p.begin(&image);
1235         p.setPen(Qt::NoPen);
1236         p.setBrush(Qt::black);
1237         p.translate(offset, offset);
1238         p.drawPath(p2);
1239         p.end();
1240
1241         const int p2Pixels = getPaintedPixels(image, Qt::white);
1242
1243         QCOMPARE(p1Pixels + p2Pixels, w * h);
1244     }
1245 }
1246
1247 void tst_QPainter::drawPath3()
1248 {
1249 #if !defined(Q_OS_WINCE)
1250     QImage imgA(400, 400, QImage::Format_RGB32);
1251 #else
1252     QImage imgA(100, 100, QImage::Format_RGB32);
1253 #endif
1254     imgA.fill(0xffffff);
1255     QImage imgB = imgA;
1256
1257     QPainterPath path;
1258     for (int y = 0; y < imgA.height(); ++y) {
1259         for (int x = 0; x < imgA.width(); ++x) {
1260             if ((x + y) & 1) {
1261                 imgA.setPixel(x, y, 0);
1262                 path.addRect(x, y, 1, 1);
1263             }
1264         }
1265     }
1266
1267     QPainter p(&imgB);
1268     p.setPen(Qt::NoPen);
1269     p.setBrush(Qt::black);
1270
1271     p.drawPath(path);
1272     p.end();
1273
1274     QVERIFY(imgA == imgB);
1275
1276     imgA.invertPixels();
1277     imgB.fill(0xffffff);
1278
1279     p.begin(&imgB);
1280     p.setPen(Qt::NoPen);
1281     p.setBrush(Qt::black);
1282
1283     QRectF rect(0, 0, imgA.width(), imgA.height());
1284     path.addRect(rect.adjusted(-10, -10, 10, 10));
1285     p.drawPath(path);
1286     p.end();
1287
1288     QVERIFY(imgA == imgB);
1289
1290     path.setFillRule(Qt::WindingFill);
1291     imgB.fill(0xffffff);
1292
1293     p.begin(&imgB);
1294     p.setPen(Qt::NoPen);
1295     p.setBrush(Qt::black);
1296     QRect clip = rect.adjusted(10, 10, -10, -10).toRect();
1297     p.setClipRect(clip);
1298     p.drawPath(path);
1299     p.end();
1300
1301     QCOMPARE(getPaintedPixels(imgB, Qt::white), clip.width() * clip.height());
1302 }
1303
1304 void tst_QPainter::drawEllipse_data()
1305 {
1306     QTest::addColumn<QSize>("size");
1307     QTest::addColumn<bool>("usePen");
1308
1309     // The current drawEllipse algorithm (drawEllipse_midpoint_i in
1310     // qpaintengine_raster.cpp) draws ellipses that are too wide if the
1311     // ratio between width and hight is too large/small (task 114874). Those
1312     // ratios are therefore currently avoided.
1313     for (int w = 10; w < 128; w += 7) {
1314         for (int h = w/2; h < qMin(2*w, 128); h += 13) {
1315             QString s = QString("%1x%2").arg(w).arg(h);
1316             QTest::newRow(QString("%1 with pen").arg(s).toLatin1()) << QSize(w, h) << true;
1317             QTest::newRow(QString("%1 no pen").arg(s).toLatin1()) << QSize(w, h) << false;
1318         }
1319     }
1320 }
1321
1322 void tst_QPainter::drawEllipse()
1323 {
1324     QFETCH(QSize, size);
1325     QFETCH(bool, usePen);
1326
1327     const int offset = 10;
1328     QRect rect(QPoint(offset, offset), size);
1329
1330     QImage image(size.width() + 2 * offset, size.height() + 2 * offset,
1331                  QImage::Format_ARGB32_Premultiplied);
1332     image.fill(QColor(Qt::white).rgb());
1333
1334     QPainter p(&image);
1335     p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1336     p.setBrush(Qt::black);
1337     p.drawEllipse(rect);
1338     p.end();
1339
1340     QPixmap pixmap = QPixmap::fromImage(image);
1341
1342     const QRect painted = getPaintedSize(pixmap, Qt::white);
1343
1344     QCOMPARE(painted.x(), rect.x());
1345     QCOMPARE(painted.y(), rect.y() + (usePen ? 0 : 1));
1346     QCOMPARE(painted.width(), size.width() + (usePen ? 1 : 0));
1347     QCOMPARE(painted.height(), size.height() + (usePen ? 1 : -1));
1348 }
1349
1350 void tst_QPainter::drawClippedEllipse_data()
1351 {
1352     QTest::addColumn<QRect>("rect");
1353
1354     for (int w = 20; w < 128; w += 7) {
1355         for (int h = w/2; h < qMin(2*w, 128); h += 13) {
1356             QString s = QString("%1x%2").arg(w).arg(h);
1357             QTest::newRow(QString("%1 top").arg(s).toLatin1()) << QRect(0, -h/2, w, h);
1358             QTest::newRow(QString("%1 topright").arg(s).toLatin1()) << QRect(w/2, -h/2, w, h);
1359             QTest::newRow(QString("%1 right").arg(s).toLatin1()) << QRect(w/2, 0, w, h);
1360             QTest::newRow(QString("%1 bottomright").arg(s).toLatin1()) << QRect(w/2, h/2, w, h);
1361             QTest::newRow(QString("%1 bottom").arg(s).toLatin1()) << QRect(0, h/2, w, h);
1362             QTest::newRow(QString("%1 bottomleft").arg(s).toLatin1()) << QRect(-w/2, h/2, w, h);
1363             QTest::newRow(QString("%1 left").arg(s).toLatin1()) << QRect(-w/2, 0, w, h);
1364             QTest::newRow(QString("%1 topleft").arg(s).toLatin1()) << QRect(-w/2, -h/2, w, h);
1365         }
1366     }
1367 }
1368
1369 void tst_QPainter::drawClippedEllipse()
1370 {
1371     QFETCH(QRect, rect);
1372     if (sizeof(qreal) != sizeof(double))
1373         QSKIP("Test only works for qreal==double");
1374     QImage image(rect.width() + 1, rect.height() + 1,
1375                  QImage::Format_ARGB32_Premultiplied);
1376     QRect expected = QRect(rect.x(), rect.y(), rect.width()+1, rect.height()+1)
1377                      & QRect(0, 0, image.width(), image.height());
1378
1379
1380     image.fill(QColor(Qt::white).rgb());
1381     QPainter p(&image);
1382     p.drawEllipse(rect);
1383     p.end();
1384
1385     QPixmap pixmap = QPixmap::fromImage(image);
1386     const QRect painted = getPaintedSize(pixmap, Qt::white);
1387
1388     QCOMPARE(painted.x(), expected.x());
1389     QCOMPARE(painted.y(), expected.y());
1390     QCOMPARE(painted.width(), expected.width());
1391     QCOMPARE(painted.height(), expected.height());
1392
1393 }
1394
1395 void tst_QPainter::drawRoundRect()
1396 {
1397     QFETCH(QRect, rect);
1398     QFETCH(bool, usePen);
1399
1400 #ifdef Q_OS_MAC
1401     if (QTest::currentDataTag() == QByteArray("rect(6, 12, 3, 14) with pen") ||
1402         QTest::currentDataTag() == QByteArray("rect(6, 17, 3, 25) with pen") ||
1403         QTest::currentDataTag() == QByteArray("rect(10, 6, 10, 3) with pen") ||
1404         QTest::currentDataTag() == QByteArray("rect(10, 12, 10, 14) with pen") ||
1405         QTest::currentDataTag() == QByteArray("rect(13, 45, 17, 80) with pen") ||
1406         QTest::currentDataTag() == QByteArray("rect(13, 50, 17, 91) with pen") ||
1407         QTest::currentDataTag() == QByteArray("rect(17, 6, 24, 3) with pen") ||
1408         QTest::currentDataTag() == QByteArray("rect(24, 12, 38, 14) with pen"))
1409         QSKIP("The Mac paint engine is off-by-one on certain rect sizes");
1410 #endif
1411     QPixmap pixmap(rect.x() + rect.width() + 10,
1412                    rect.y() + rect.height() + 10);
1413     {
1414         pixmap.fill(Qt::white);
1415         QPainter p(&pixmap);
1416         p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1417         p.setBrush(Qt::black);
1418         p.drawRoundRect(rect);
1419         p.end();
1420
1421         int increment = usePen ? 1 : 0;
1422
1423         const QRect painted = getPaintedSize(pixmap, Qt::white);
1424         QCOMPARE(painted.width(), rect.width() + increment);
1425         QCOMPARE(painted.height(), rect.height() + increment);
1426     }
1427 }
1428
1429 Q_DECLARE_METATYPE(QImage::Format)
1430
1431 void tst_QPainter::qimageFormats_data()
1432 {
1433     QTest::addColumn<QImage::Format>("format");
1434     QTest::newRow("QImage::Format_RGB32") << QImage::Format_RGB32;
1435     QTest::newRow("QImage::Format_ARGB32") << QImage::Format_ARGB32;
1436     QTest::newRow("QImage::Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
1437     QTest::newRow("QImage::Format_RGB16") << QImage::Format_RGB16;
1438     QTest::newRow("Qimage::Format_ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied;
1439     QTest::newRow("Qimage::Format_RGB666") << QImage::Format_RGB666;
1440     QTest::newRow("Qimage::Format_RGB555") << QImage::Format_RGB555;
1441     QTest::newRow("Qimage::Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied;
1442     QTest::newRow("Qimage::Format_RGB888") << QImage::Format_RGB888;
1443 }
1444
1445 /*
1446     Tests that QPainter can paint on various QImage formats.
1447 */
1448 void tst_QPainter::qimageFormats()
1449 {
1450     QFETCH(QImage::Format, format);
1451
1452     const QSize size(100, 100);
1453     QImage image(size, format);
1454     image.fill(0);
1455
1456     const QColor testColor(Qt::red);
1457     QPainter p(&image);
1458     QVERIFY(p.isActive());
1459     p.setBrush(QBrush(testColor));
1460     p.drawRect(QRect(QPoint(0,0), size));
1461     QCOMPARE(image.pixel(50, 50), testColor.rgb());
1462 }
1463
1464 void tst_QPainter::fillData()
1465 {
1466     QTest::addColumn<QRect>("rect");
1467     QTest::addColumn<bool>("usePen");
1468
1469     for (int w = 3; w < 50; w += 7) {
1470         for (int h = 3; h < 50; h += 11) {
1471             int x = w/2 + 5;
1472             int y = h/2 + 5;
1473             QTest::newRow(QString("rect(%1, %2, %3, %4) with pen").arg(x).arg(y).arg(w).arg(h).toLatin1())
1474                 << QRect(x, y, w, h) << true;
1475             QTest::newRow(QString("rect(%1, %2, %3, %4) no pen").arg(x).arg(y).arg(w).arg(h).toLatin1())
1476                 << QRect(x, y, w, h) << false;
1477         }
1478     }
1479 }
1480
1481 /*
1482     Test that drawline works properly after setWindow has been called.
1483 */
1484 void tst_QPainter::setWindow()
1485 {
1486     QPixmap pixmap(600, 600);
1487     pixmap.fill(QColor(Qt::white));
1488
1489     QPainter painter(&pixmap);
1490     painter.setWindow(0, 0, 3, 3);
1491     painter.drawLine(1, 1, 2, 2);
1492
1493     const QRect painted = getPaintedSize(pixmap, Qt::white);
1494     QVERIFY(195 < painted.y() && painted.y() < 205); // correct value is around 200
1495     QVERIFY(195 < painted.height() && painted.height() < 205); // correct value is around 200
1496 }
1497
1498 void tst_QPainter::combinedMatrix()
1499 {
1500     QPixmap pm(64, 64);
1501
1502     QPainter p(&pm);
1503     p.setWindow(0, 0, 1, 1);
1504     p.setViewport(32, 0, 32, 32);
1505
1506     p.translate(0.5, 0.5);
1507
1508     QMatrix cm = p.combinedMatrix();
1509
1510     QPointF pt = QPointF(0, 0) * cm;
1511
1512     QCOMPARE(pt.x(), 48.0);
1513     QCOMPARE(pt.y(), 16.0);
1514 }
1515
1516 void tst_QPainter::textOnTransparentImage()
1517 {
1518     bool foundPixel = false;
1519     QImage image(10, 10, QImage::Format_ARGB32_Premultiplied);
1520     image.fill(qRgba(0, 0, 0, 0)); // transparent
1521     {
1522         QPainter painter(&image);
1523         painter.setPen(QColor(255, 255, 255));
1524         painter.drawText(0, 10, "W");
1525     }
1526     for (int x = 0; x < image.width(); ++x)
1527         for (int y = 0; y < image.height(); ++y)
1528             if (image.pixel(x, y) != 0)
1529                 foundPixel = true;
1530     QVERIFY(foundPixel);
1531 }
1532
1533 void tst_QPainter::renderHints()
1534 {
1535     QImage img(1, 1, QImage::Format_RGB32);
1536
1537     QPainter p(&img);
1538
1539     // Turn off all...
1540     p.setRenderHints(QPainter::RenderHints(0xffffffff), false);
1541     QCOMPARE(p.renderHints(), QPainter::RenderHints(0));
1542
1543     // Single set/get
1544     p.setRenderHint(QPainter::Antialiasing);
1545     QVERIFY(p.renderHints() & QPainter::Antialiasing);
1546
1547     p.setRenderHint(QPainter::Antialiasing, false);
1548     QVERIFY(!(p.renderHints() & QPainter::Antialiasing));
1549
1550     // Multi set/get
1551     p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
1552     QVERIFY(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform));
1553
1554     p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
1555     QVERIFY(!(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform)));
1556 }
1557
1558 int countPixels(const QImage &img, const QRgb &color)
1559 {
1560     int count = 0;
1561     for (int y = 0; y < img.height(); ++y) {
1562         for (int x = 0; x < img.width(); ++x) {
1563             count += ((img.pixel(x, y) & 0xffffff) == color);
1564         }
1565     }
1566     return count;
1567 }
1568
1569 template <typename T>
1570 void testClipping(QImage &img)
1571 {
1572     QPainterPath a, b;
1573     a.addRect(QRect(2, 2, 4, 4));
1574     b.addRect(QRect(4, 4, 4, 4));
1575     QPainter p(&img);
1576
1577     p.end();
1578     img.fill(0x0);
1579     p.begin(&img);
1580     p.setClipPath(a);
1581     p.setClipPath(b, Qt::IntersectClip);
1582
1583     p.setClipping(false);
1584     p.setPen(Qt::NoPen);
1585     p.setBrush(QColor(0xff0000));
1586     p.drawRect(T(0, 0, 10, 10));
1587
1588     p.setClipping(true);
1589     p.setBrush(QColor(0x00ff00));
1590     p.drawRect(T(0, 0, 10, 10));
1591
1592     QCOMPARE(countPixels(img, 0xff0000), 96);
1593     QCOMPARE(countPixels(img, 0x00ff00), 4);
1594 }
1595
1596 void tst_QPainter::disableEnableClipping()
1597 {
1598     QImage img(10, 10, QImage::Format_RGB32);
1599
1600     testClipping<QRectF>(img);
1601     testClipping<QRect>(img);
1602 }
1603
1604 void tst_QPainter::setClipRect()
1605 {
1606     QImage img(10, 10, QImage::Format_RGB32);
1607     // simple test to let valgrind check for buffer overflow
1608     {
1609         QPainter p(&img);
1610         p.setClipRect(-10, -10, 100, 100);
1611         p.fillRect(-10, -10, 100, 100, QBrush(QColor(Qt::red)));
1612     }
1613
1614     // rects with negative width/height
1615     {
1616         QPainter p(&img);
1617         p.setClipRect(QRect(10, 10, -10, 10));
1618         QVERIFY(p.clipRegion().isEmpty());
1619         p.setClipRect(QRect(10, 10, 10, -10));
1620         QVERIFY(p.clipRegion().isEmpty());
1621         p.setClipRect(QRectF(10.5, 10.5, -10.5, 10.5));
1622         QVERIFY(p.clipRegion().isEmpty());
1623         p.setClipRect(QRectF(10.5, 10.5, 10.5, -10.5));
1624         QVERIFY(p.clipRegion().isEmpty());
1625     }
1626 }
1627
1628 /*
1629     This tests the two different clipping approaches in QRasterPaintEngine,
1630     one when using a QRegion and one when using a QPainterPath. They should
1631     give equal results.
1632 */
1633 void tst_QPainter::setEqualClipRegionAndPath_data()
1634 {
1635     QTest::addColumn<QSize>("deviceSize");
1636     QTest::addColumn<QRegion>("region");
1637
1638     QTest::newRow("empty") << QSize(100, 100) << QRegion();
1639     QTest::newRow("simple rect") << QSize(100, 100)
1640                                  << QRegion(QRect(5, 5, 10, 10));
1641
1642     QVector<QRect> rects;
1643     QRegion region;
1644
1645     rects << QRect(5, 5, 10, 10) << QRect(20, 20, 10, 10);
1646     region.setRects(rects.constData(), rects.size());
1647     QTest::newRow("two rects") << QSize(100, 100) << region;
1648
1649     rects.clear();
1650     rects << QRect(5, 5, 10, 10) << QRect(20, 5, 10, 10);
1651     region.setRects(rects.constData(), rects.size());
1652     QTest::newRow("two x-adjacent rects") << QSize(100, 100) << region;
1653
1654     rects.clear();
1655     rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1656     region.setRects(rects.constData(), rects.size());
1657     QTest::newRow("two x-adjacent rects 2") << QSize(100, 100) << region;
1658
1659     rects.clear();
1660     rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1661     region.setRects(rects.constData(), rects.size());
1662     QTest::newRow("two x-adjacent rects 3") << QSize(50, 50) << region;
1663
1664     rects.clear();
1665     rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1666     region.setRects(rects.constData(), rects.size());
1667     QTest::newRow("two x-adjacent rects 4") << QSize(101, 101) << region;
1668
1669     region = QRegion(QRect(0, 0, 200, 200), QRegion::Ellipse);
1670
1671     QTest::newRow("ellipse") << QSize(190, 200) << region;
1672
1673     region ^= QRect(50, 50, 50, 50);
1674     QTest::newRow("ellipse 2") << QSize(200, 200) << region;
1675 }
1676
1677 void tst_QPainter::setEqualClipRegionAndPath()
1678 {
1679     QFETCH(QSize, deviceSize);
1680     QFETCH(QRegion, region);
1681
1682     QPainterPath path;
1683     path.addRegion(region);
1684
1685     QImage img1(deviceSize.width(), deviceSize.height(),
1686                 QImage::Format_ARGB32);
1687     QImage img2(deviceSize.width(), deviceSize.height(),
1688                 QImage::Format_ARGB32);
1689     img1.fill(0x12345678);
1690     img2.fill(0x12345678);
1691
1692     {
1693         QPainter p(&img1);
1694         p.setClipRegion(region);
1695         p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1696     }
1697     {
1698         QPainter p(&img2);
1699         p.setClipPath(path);
1700         p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1701     }
1702
1703     QCOMPARE(img1, img2);
1704
1705     // rotated
1706     img1.fill(0x12345678);
1707     img2.fill(0x12345678);
1708
1709     {
1710         QPainter p(&img1);
1711         p.rotate(25);
1712         p.setClipRegion(region);
1713         p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1714     }
1715     {
1716         QPainter p(&img2);
1717         p.rotate(25);
1718         p.setClipPath(path);
1719         p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1720     }
1721
1722     QCOMPARE(img1, img2);
1723
1724     img1.fill(0x12345678);
1725     img2.fill(0x12345678);
1726
1727     // simple intersectclip
1728     img1.fill(0x12345678);
1729     img2.fill(0x12345678);
1730     {
1731         QPainter p(&img1);
1732         p.setClipRegion(region);
1733         p.setClipRegion(region, Qt::IntersectClip);
1734         p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1735     }
1736     {
1737         QPainter p(&img2);
1738         p.setClipPath(path);
1739         p.setClipPath(path, Qt::IntersectClip);
1740         p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1741     }
1742     QCOMPARE(img1, img2);
1743
1744     img1.fill(0x12345678);
1745     img2.fill(0x12345678);
1746     {
1747         QPainter p(&img1);
1748         p.setClipPath(path);
1749         p.setClipRegion(region, Qt::IntersectClip);
1750         p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1751     }
1752     {
1753         QPainter p(&img2);
1754         p.setClipRegion(region);
1755         p.setClipPath(path, Qt::IntersectClip);
1756         p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1757     }
1758     QCOMPARE(img1, img2);
1759
1760 }
1761
1762 void tst_QPainter::clippedFillPath_data()
1763 {
1764     QTest::addColumn<QSize>("imageSize");
1765     QTest::addColumn<QPainterPath>("path");
1766     QTest::addColumn<QRect>("clipRect");
1767     QTest::addColumn<QBrush>("brush");
1768     QTest::addColumn<QPen>("pen");
1769
1770     QLinearGradient gradient(QPoint(0, 0), QPoint(100, 100));
1771     gradient.setColorAt(0, Qt::red);
1772     gradient.setColorAt(1, Qt::blue);
1773
1774
1775     QPen pen2(QColor(223, 223, 0, 223));
1776     pen2.setWidth(2);
1777
1778     QPainterPath path;
1779     path.addRect(QRect(15, 15, 50, 50));
1780     QTest::newRow("simple rect 0") << QSize(100, 100) << path
1781                                    << QRect(15, 15, 49, 49)
1782                                    << QBrush(Qt::NoBrush)
1783                                    << QPen(Qt::black);
1784     QTest::newRow("simple rect 1") << QSize(100, 100) << path
1785                                    << QRect(15, 15, 50, 50)
1786                                    << QBrush(Qt::NoBrush)
1787                                    << QPen(Qt::black);
1788     QTest::newRow("simple rect 2") << QSize(100, 100) << path
1789                                    << QRect(15, 15, 51, 51)
1790                                    << QBrush(Qt::NoBrush)
1791                                    << QPen(Qt::black);
1792     QTest::newRow("simple rect 3") << QSize(100, 100) << path
1793                                    << QRect(15, 15, 51, 51)
1794                                    << QBrush(QColor(Qt::blue))
1795                                    << QPen(Qt::NoPen);
1796     QTest::newRow("simple rect 4") << QSize(100, 100) << path
1797                                    << QRect(15, 15, 51, 51)
1798                                    << QBrush(gradient)
1799                                    << pen2;
1800
1801     path = QPainterPath();
1802     path.addEllipse(QRect(15, 15, 50, 50));
1803     QTest::newRow("ellipse 0") << QSize(100, 100) << path
1804                                << QRect(15, 15, 49, 49)
1805                                << QBrush(Qt::NoBrush)
1806                                << QPen(Qt::black);
1807     QTest::newRow("ellipse 1") << QSize(100, 100) << path
1808                                << QRect(15, 15, 50, 50)
1809                                << QBrush(Qt::NoBrush)
1810                                << QPen(Qt::black);
1811     QTest::newRow("ellipse 2") << QSize(100, 100) << path
1812                                << QRect(15, 15, 51, 51)
1813                                << QBrush(Qt::NoBrush)
1814                                << QPen(Qt::black);
1815     QTest::newRow("ellipse 3") << QSize(100, 100) << path
1816                                << QRect(15, 15, 51, 51)
1817                                << QBrush(QColor(Qt::blue))
1818                                << QPen(Qt::NoPen);
1819     QTest::newRow("ellipse 4") << QSize(100, 100) << path
1820                                << QRect(15, 15, 51, 51)
1821                                << QBrush(gradient)
1822                                << pen2;
1823
1824     path = QPainterPath();
1825     path.addRoundRect(QRect(15, 15, 50, 50), 20);
1826     QTest::newRow("round rect 0") << QSize(100, 100) << path
1827                                   << QRect(15, 15, 49, 49)
1828                                   << QBrush(Qt::NoBrush)
1829                                   << QPen(Qt::black);
1830     QTest::newRow("round rect 1") << QSize(100, 100) << path
1831                                   << QRect(15, 15, 50, 50)
1832                                   << QBrush(Qt::NoBrush)
1833                                   << QPen(Qt::black);
1834     QTest::newRow("round rect 2") << QSize(100, 100) << path
1835                                   << QRect(15, 15, 51, 51)
1836                                   << QBrush(Qt::NoBrush)
1837                                   << QPen(Qt::black);
1838     QTest::newRow("round rect 3") << QSize(100, 100) << path
1839                                   << QRect(15, 15, 51, 51)
1840                                   << QBrush(QColor(Qt::blue))
1841                                   << QPen(Qt::NoPen);
1842     QTest::newRow("round rect 4") << QSize(100, 100) << path
1843                                   << QRect(15, 15, 51, 51)
1844                                   << QBrush(gradient)
1845                                   << pen2;
1846
1847     path = QPainterPath();
1848     path.moveTo(15, 50);
1849     path.cubicTo(40, 50, 40, 15, 65, 50);
1850     path.lineTo(15, 50);
1851     QTest::newRow("cubic 0") << QSize(100, 100) << path
1852                              << QRect(15, 15, 49, 49)
1853                              << QBrush(Qt::NoBrush)
1854                              << QPen(Qt::black);
1855     QTest::newRow("cubic 1") << QSize(100, 100) << path
1856                              << QRect(15, 15, 50, 50)
1857                              << QBrush(Qt::NoBrush)
1858                              << QPen(Qt::black);
1859     QTest::newRow("cubic 2") << QSize(100, 100) << path
1860                              << QRect(15, 15, 51, 51)
1861                              << QBrush(Qt::NoBrush)
1862                              << QPen(Qt::black);
1863     QTest::newRow("cubic 3") << QSize(100, 100) << path
1864                              << QRect(15, 15, 51, 51)
1865                              << QBrush(QColor(Qt::blue))
1866                              << QPen(Qt::NoPen);
1867     QTest::newRow("cubic 4") << QSize(100, 100) << path
1868                              << QRect(15, 15, 51, 51)
1869                              << QBrush(gradient)
1870                              << pen2;
1871 }
1872
1873 void tst_QPainter::clippedFillPath()
1874 {
1875     QFETCH(QSize, imageSize);
1876     QFETCH(QPainterPath, path);
1877     QFETCH(QRect, clipRect);
1878     QPainterPath clipPath;
1879     clipPath.addRect(clipRect);
1880     QFETCH(QBrush, brush);
1881     QFETCH(QPen, pen);
1882
1883     const int width = imageSize.width();
1884     const int height = imageSize.height();
1885
1886     QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
1887     clippedRect.fill(0x12345678);
1888     {
1889         QPainter painter(&clippedRect);
1890         painter.setPen(pen);
1891         painter.setBrush(brush);
1892         painter.setClipRect(clipRect);
1893         painter.drawPath(path);
1894     }
1895
1896     QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
1897     clippedPath.fill(0x12345678);
1898     {
1899         QPainter painter(&clippedPath);
1900         painter.setPen(pen);
1901         painter.setBrush(brush);
1902         painter.setClipPath(clipPath);
1903         painter.drawPath(path);
1904     }
1905
1906     QCOMPARE(clippedRect, clippedPath);
1907
1908     // repeat with antialiasing
1909
1910     clippedRect.fill(0x12345678);
1911     {
1912         QPainter painter(&clippedRect);
1913         painter.setRenderHint(QPainter::Antialiasing);
1914         painter.setPen(pen);
1915         painter.setBrush(brush);
1916         painter.setClipRect(clipRect);
1917         painter.drawPath(path);
1918     }
1919
1920     clippedPath.fill(0x12345678);
1921     {
1922         QPainter painter(&clippedPath);
1923         painter.setRenderHint(QPainter::Antialiasing);
1924         painter.setPen(pen);
1925         painter.setBrush(brush);
1926         painter.setClipPath(clipPath);
1927         painter.drawPath(path);
1928     }
1929
1930     QCOMPARE(clippedRect, clippedPath);
1931 }
1932
1933 void tst_QPainter::clippedLines_data()
1934 {
1935     QTest::addColumn<QSize>("imageSize");
1936     QTest::addColumn<QLineF>("line");
1937     QTest::addColumn<QRect>("clipRect");
1938     QTest::addColumn<QPen>("pen");
1939
1940     QPen pen2(QColor(223, 223, 0, 223));
1941     pen2.setWidth(2);
1942
1943     QVector<QLineF> lines;
1944     lines << QLineF(15, 15, 65, 65)
1945           << QLineF(14, 14, 66, 66)
1946           << QLineF(16, 16, 64, 64)
1947           << QLineF(65, 65, 15, 15)
1948           << QLineF(66, 66, 14, 14)
1949           << QLineF(64, 64, 14, 14)
1950           << QLineF(15, 50, 15, 64)
1951           << QLineF(15, 50, 15, 65)
1952           << QLineF(15, 50, 15, 66)
1953           << QLineF(15, 50, 64, 50)
1954           << QLineF(15, 50, 65, 50)
1955           << QLineF(15, 50, 66, 50);
1956
1957     foreach (QLineF line, lines) {
1958         QString desc = QString("line (%1, %2, %3, %4) %5").arg(line.x1())
1959                        .arg(line.y1()).arg(line.x2()).arg(line.y2());
1960         QTest::newRow(qPrintable(desc.arg(0))) << QSize(100, 100) << line
1961                                    << QRect(15, 15, 49, 49)
1962                                    << QPen(Qt::black);
1963         QTest::newRow(qPrintable(desc.arg(1))) << QSize(100, 100) << line
1964                                    << QRect(15, 15, 50, 50)
1965                                    << QPen(Qt::black);
1966         QTest::newRow(qPrintable(desc.arg(2))) << QSize(100, 100) << line
1967                                    << QRect(15, 15, 51, 51)
1968                                    << QPen(Qt::black);
1969         QTest::newRow(qPrintable(desc.arg(3))) << QSize(100, 100) << line
1970                                    << QRect(15, 15, 51, 51)
1971                                    << QPen(Qt::NoPen);
1972         QTest::newRow(qPrintable(desc.arg(4))) << QSize(100, 100) << line
1973                                    << QRect(15, 15, 51, 51)
1974                                    << pen2;
1975     }
1976 }
1977
1978 void tst_QPainter::clippedLines()
1979 {
1980     QFETCH(QSize, imageSize);
1981     QFETCH(QLineF, line);
1982     QFETCH(QRect, clipRect);
1983     QPainterPath clipPath;
1984     clipPath.addRect(clipRect);
1985     QFETCH(QPen, pen);
1986
1987     const int width = imageSize.width();
1988     const int height = imageSize.height();
1989
1990     QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
1991     clippedRect.fill(0x12345678);
1992     {
1993         QPainter painter(&clippedRect);
1994         painter.setPen(pen);
1995         painter.setClipRect(clipRect);
1996         painter.drawLine(line);
1997         painter.drawLine(line.toLine());
1998     }
1999
2000     QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2001     clippedPath.fill(0x12345678);
2002     {
2003         QPainter painter(&clippedPath);
2004         painter.setPen(pen);
2005         painter.setClipPath(clipPath);
2006         painter.drawLine(line);
2007         painter.drawLine(line.toLine());
2008     }
2009
2010     QCOMPARE(clippedRect, clippedPath);
2011
2012     // repeat with antialiasing
2013     clippedRect.fill(0x12345678);
2014     {
2015         QPainter painter(&clippedRect);
2016         painter.setRenderHint(QPainter::Antialiasing);
2017         painter.setPen(pen);
2018         painter.setClipRect(clipRect);
2019         painter.drawLine(line);
2020         painter.drawLine(line.toLine());
2021     }
2022
2023     clippedPath.fill(0x12345678);
2024     {
2025         QPainter painter(&clippedPath);
2026         painter.setRenderHint(QPainter::Antialiasing);
2027         painter.setPen(pen);
2028         painter.setClipPath(clipPath);
2029         painter.drawLine(line);
2030         painter.drawLine(line.toLine());
2031     }
2032
2033     QCOMPARE(clippedRect, clippedPath);
2034 }
2035
2036 void tst_QPainter::clippedPolygon_data()
2037 {
2038     clippedFillPath_data();
2039 };
2040
2041 void tst_QPainter::clippedPolygon()
2042 {
2043     QFETCH(QSize, imageSize);
2044     QFETCH(QPainterPath, path);
2045     QPolygonF polygon = path.toFillPolygon();
2046     QFETCH(QRect, clipRect);
2047     QPainterPath clipPath;
2048     clipPath.addRect(clipRect);
2049     QFETCH(QPen, pen);
2050     QFETCH(QBrush, brush);
2051
2052     const int width = imageSize.width();
2053     const int height = imageSize.height();
2054
2055     QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
2056     clippedRect.fill(0x12345678);
2057     {
2058         QPainter painter(&clippedRect);
2059         painter.setPen(pen);
2060         painter.setBrush(brush);
2061         painter.setClipRect(clipRect);
2062         painter.drawPolygon(polygon);
2063         painter.drawPolygon(polygon.toPolygon());
2064     }
2065
2066     QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2067     clippedPath.fill(0x12345678);
2068     {
2069         QPainter painter(&clippedPath);
2070         painter.setPen(pen);
2071         painter.setBrush(brush);
2072         painter.setClipRect(clipRect);
2073         painter.drawPolygon(polygon);
2074         painter.drawPolygon(polygon.toPolygon());
2075     }
2076
2077     QCOMPARE(clippedRect, clippedPath);
2078
2079     // repeat with antialiasing
2080
2081     clippedRect.fill(0x12345678);
2082     {
2083         QPainter painter(&clippedRect);
2084         painter.setRenderHint(QPainter::Antialiasing);
2085         painter.setPen(pen);
2086         painter.setBrush(brush);
2087         painter.setClipRect(clipRect);
2088         painter.drawPolygon(polygon);
2089         painter.drawPolygon(polygon.toPolygon());
2090     }
2091
2092     clippedPath.fill(0x12345678);
2093     {
2094         QPainter painter(&clippedPath);
2095         painter.setRenderHint(QPainter::Antialiasing);
2096         painter.setPen(pen);
2097         painter.setBrush(brush);
2098         painter.setClipRect(clipRect);
2099         painter.drawPolygon(polygon);
2100         painter.drawPolygon(polygon.toPolygon());
2101     }
2102
2103     QCOMPARE(clippedRect, clippedPath);
2104 }
2105
2106 // this just draws some text that should be clipped in the raster
2107 // paint engine.
2108 void tst_QPainter::clippedText()
2109 {
2110     for (char ch = 'A'; ch < 'Z'; ++ch) {
2111         //qDebug() << ch;
2112         QFont f;
2113         f.setPixelSize(24);
2114         QFontMetrics metrics(f);
2115         QRect textRect = metrics.boundingRect(QChar(ch));
2116
2117         if (textRect.width() <= 8)
2118             continue;
2119         if (textRect.height() <= 8)
2120             continue;
2121
2122         QRect imageRect = textRect.adjusted(4, 4, -4, -4);
2123
2124         QImage image(imageRect.size(), QImage::Format_ARGB32_Premultiplied);
2125
2126         image.fill(qRgba(255, 255, 255, 255));
2127         {
2128             QPainter painter(&image);
2129             painter.setFont(f);
2130             painter.setPen(Qt::black);
2131
2132             painter.drawText(0, 0, QChar(ch));
2133         }
2134
2135         image.fill(qRgba(255, 255, 255, 255));
2136         {
2137             QPainter painter(&image);
2138             painter.setFont(f);
2139             painter.setPen(Qt::black);
2140
2141             painter.drawText(-imageRect.topLeft(), QChar(ch));
2142         }
2143
2144         bool foundPixel = false;
2145         for (int x = 0; x < image.width(); ++x)
2146             for (int y = 0; y < image.height(); ++y)
2147                 if (image.pixel(x, y) != 0)
2148                     foundPixel = true;
2149         // can't QVERIFY(foundPixel) as sometimes all pixels are clipped
2150         // away. For example for 'O'
2151         // just call /some/ function to prevent the compiler from optimizing
2152         // foundPixel away
2153         QString::number(foundPixel);
2154
2155         //image.save(QString("debug") + ch + ".xpm");
2156     }
2157
2158     QVERIFY(true); // reached, don't trigger any valgrind errors
2159 }
2160
2161 void tst_QPainter::setOpacity_data()
2162 {
2163     QTest::addColumn<QImage::Format>("destFormat");
2164     QTest::addColumn<QImage::Format>("srcFormat");
2165
2166     QTest::newRow("ARGB32P on ARGB32P") << QImage::Format_ARGB32_Premultiplied
2167                                         << QImage::Format_ARGB32_Premultiplied;
2168
2169     QTest::newRow("ARGB32 on ARGB32") << QImage::Format_ARGB32
2170                                       << QImage::Format_ARGB32;
2171
2172     QTest::newRow("RGB32 on RGB32") << QImage::Format_RGB32
2173                                     << QImage::Format_RGB32;
2174
2175     QTest::newRow("RGB16 on RGB16") << QImage::Format_RGB16
2176                                     << QImage::Format_RGB16;
2177
2178     QTest::newRow("ARGB8565_Premultiplied on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied
2179                                                                       << QImage::Format_ARGB8565_Premultiplied;
2180
2181     QTest::newRow("RGB555 on RGB555") << QImage::Format_RGB555
2182                                       << QImage::Format_RGB555;
2183
2184     QTest::newRow("RGB666 on RGB666") << QImage::Format_RGB666
2185                                       << QImage::Format_RGB666;
2186
2187     QTest::newRow("ARGB8555_Premultiplied on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied
2188                                                                       << QImage::Format_ARGB8555_Premultiplied;
2189
2190     QTest::newRow("RGB888 on RGB888") << QImage::Format_RGB888
2191                                       << QImage::Format_RGB888;
2192
2193     QTest::newRow("RGB32 on RGB16") << QImage::Format_RGB16
2194                                     << QImage::Format_RGB32;
2195
2196     QTest::newRow("RGB32 on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied
2197                                                      << QImage::Format_RGB32;
2198
2199     QTest::newRow("RGB32 on RGB666") << QImage::Format_RGB666
2200                                      << QImage::Format_RGB32;
2201
2202     QTest::newRow("RGB32 on RGB555") << QImage::Format_RGB555
2203                                      << QImage::Format_RGB32;
2204
2205     QTest::newRow("RGB32 on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied
2206                                                      << QImage::Format_RGB32;
2207
2208     QTest::newRow("RGB32 on RGB888") << QImage::Format_RGB888
2209                                      << QImage::Format_RGB32;
2210
2211     QTest::newRow("RGB16 on RGB32") << QImage::Format_RGB32
2212                                     << QImage::Format_RGB16;
2213
2214     QTest::newRow("ARGB8565_Premultiplied on RGB32") << QImage::Format_RGB32
2215                                                      << QImage::Format_ARGB8565_Premultiplied;
2216
2217     QTest::newRow("RGB666 on RGB32") << QImage::Format_RGB32
2218                                      << QImage::Format_RGB666;
2219
2220     QTest::newRow("RGB555 on RGB32") << QImage::Format_RGB32
2221                                      << QImage::Format_RGB555;
2222
2223     QTest::newRow("ARGB8555_Premultiplied on RGB32") << QImage::Format_RGB32
2224                                                      << QImage::Format_ARGB8555_Premultiplied;
2225
2226     QTest::newRow("RGB888 on RGB32") << QImage::Format_RGB32
2227                                      << QImage::Format_RGB888;
2228
2229     QTest::newRow("RGB555 on RGB888") << QImage::Format_RGB888
2230                                       << QImage::Format_RGB555;
2231
2232     QTest::newRow("RGB666 on RGB888") << QImage::Format_RGB888
2233                                       << QImage::Format_RGB666;
2234
2235     QTest::newRow("RGB444 on RGB444") << QImage::Format_RGB444
2236                                       << QImage::Format_RGB444;
2237 }
2238
2239 void tst_QPainter::setOpacity()
2240 {
2241     QFETCH(QImage::Format, destFormat);
2242     QFETCH(QImage::Format, srcFormat);
2243
2244     const QSize imageSize(12, 12);
2245     const QRect imageRect(QPoint(0, 0), imageSize);
2246     QColor destColor = Qt::black;
2247     QColor srcColor = Qt::white;
2248
2249     QImage dest(imageSize, destFormat);
2250     QImage src(imageSize, srcFormat);
2251
2252     QPainter p;
2253     p.begin(&dest);
2254     p.fillRect(imageRect, destColor);
2255     p.end();
2256
2257     p.begin(&src);
2258     p.fillRect(imageRect, srcColor);
2259     p.end();
2260
2261     p.begin(&dest);
2262     p.setOpacity(0.5);
2263     p.drawImage(imageRect, src, imageRect);
2264     p.end();
2265
2266     QImage actual = dest.convertToFormat(QImage::Format_RGB32);
2267
2268     for (int y = 0; y < actual.height(); ++y) {
2269         QRgb *p = (QRgb *)actual.scanLine(y);
2270         for (int x = 0; x < actual.width(); ++x) {
2271             QVERIFY(qAbs(qRed(p[x]) - 127) <= 0xf);
2272             QVERIFY(qAbs(qGreen(p[x]) - 127) <= 0xf);
2273             QVERIFY(qAbs(qBlue(p[x]) - 127) <= 0xf);
2274         }
2275     }
2276 }
2277
2278 void tst_QPainter::drawhelper_blend_untransformed_data()
2279 {
2280     setOpacity_data();
2281 }
2282
2283 void tst_QPainter::drawhelper_blend_untransformed()
2284 {
2285     QFETCH(QImage::Format, destFormat);
2286     QFETCH(QImage::Format, srcFormat);
2287
2288     const int size = 128;
2289     const QSize imageSize(size, size);
2290     const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing
2291
2292     QColor destColor(127, 127, 127);
2293     QColor srcColor(Qt::white);
2294
2295     QImage dest(imageSize, destFormat);
2296     QImage src(imageSize, srcFormat);
2297
2298     QPainter p;
2299     p.begin(&src);
2300     p.fillRect(paintRect, srcColor);
2301     p.end();
2302
2303     QList<qreal> opacities = (QList<qreal>() << 0.0 << 0.1  << 0.01 << 0.4
2304                               << 0.5 << 0.6 << 0.9 << 1.0);
2305     foreach (qreal opacity, opacities) {
2306         p.begin(&dest);
2307         p.fillRect(paintRect, destColor);
2308
2309         p.setOpacity(opacity);
2310         p.drawImage(paintRect, src, paintRect);
2311         p.end();
2312
2313         // sanity check: make sure all pixels are equal
2314         QImage expected(size - 2, size, destFormat);
2315         p.begin(&expected);
2316         p.fillRect(0, 0, expected.width(), expected.height(),
2317                    QColor(dest.pixel(1, 0)));
2318         p.end();
2319
2320         const QImage subDest(dest.bits() + dest.depth() / 8,
2321                              dest.width() - 2, dest.height(),
2322                              dest.bytesPerLine(), dest.format());
2323
2324         if (dest.format() == QImage::Format_ARGB8565_Premultiplied ||
2325             dest.format() == QImage::Format_ARGB8555_Premultiplied) {
2326             // Test skipped due to rounding errors...
2327             continue;
2328         }
2329         QCOMPARE(subDest, expected);
2330     }
2331 }
2332
2333 void tst_QPainter::drawhelper_blend_tiled_untransformed_data()
2334 {
2335     setOpacity_data();
2336 }
2337
2338 void tst_QPainter::drawhelper_blend_tiled_untransformed()
2339 {
2340     QFETCH(QImage::Format, destFormat);
2341     QFETCH(QImage::Format, srcFormat);
2342
2343     const int size = 128;
2344     const QSize imageSize(size, size);
2345     const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing
2346
2347     QColor destColor(127, 127, 127);
2348     QColor srcColor(Qt::white);
2349
2350     QImage dest(imageSize, destFormat);
2351     QImage src(imageSize / 2, srcFormat);
2352
2353     QPainter p;
2354     p.begin(&src);
2355     p.fillRect(QRect(QPoint(0, 0), imageSize/ 2), srcColor);
2356     p.end();
2357
2358     const QBrush brush(src);
2359
2360     QList<qreal> opacities = (QList<qreal>() << 0.0 << 0.1  << 0.01 << 0.4
2361                               << 0.5 << 0.6 << 0.9 << 1.0);
2362     foreach (qreal opacity, opacities) {
2363         p.begin(&dest);
2364         p.fillRect(paintRect, destColor);
2365
2366         p.setOpacity(opacity);
2367         p.fillRect(paintRect, brush);
2368         p.end();
2369
2370         // sanity check: make sure all pixels are equal
2371         QImage expected(size - 2, size, destFormat);
2372         p.begin(&expected);
2373         p.fillRect(0, 0, expected.width(), expected.height(),
2374                    QColor(dest.pixel(1, 0)));
2375         p.end();
2376
2377         const QImage subDest(dest.bits() + dest.depth() / 8,
2378                              dest.width() - 2, dest.height(),
2379                              dest.bytesPerLine(), dest.format());
2380
2381         if (dest.format() == QImage::Format_ARGB8565_Premultiplied ||
2382             dest.format() == QImage::Format_ARGB8555_Premultiplied) {
2383             // Skipping test due to rounding errors. Test needs rewrite
2384             continue;
2385         }
2386         QCOMPARE(subDest, expected);
2387     }
2388 }
2389
2390 static QPaintEngine::PaintEngineFeatures no_porter_duff()
2391 {
2392     QPaintEngine::PaintEngineFeatures features = QPaintEngine::AllFeatures;
2393     return features & ~QPaintEngine::PorterDuff;
2394 }
2395
2396 class DummyPaintEngine : public QPaintEngine, public QPaintDevice
2397 {
2398 public:
2399     DummyPaintEngine() : QPaintEngine(no_porter_duff()) {}
2400     virtual bool begin(QPaintDevice *) { return true; }
2401     virtual bool end() { return true; }
2402
2403     virtual void updateState(const QPaintEngineState &) {}
2404     virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
2405
2406     virtual Type type() const { return User; }
2407
2408     virtual QPaintEngine *paintEngine() const { return (QPaintEngine *)this; }
2409
2410     virtual int metric(PaintDeviceMetric metric) const { Q_UNUSED(metric); return 0; };
2411 };
2412
2413 static bool success;
2414
2415 void porterDuff_warningChecker(QtMsgType type, const QMessageLogContext &, const QString &msg)
2416 {
2417     if (type == QtWarningMsg && msg == QLatin1String("QPainter::setCompositionMode: PorterDuff modes not supported on device"))
2418         success = false;
2419 }
2420
2421 void tst_QPainter::porterDuff_warning()
2422 {
2423     QtMessageHandler old = qInstallMessageHandler(porterDuff_warningChecker);
2424     DummyPaintEngine dummy;
2425     QPainter p(&dummy);
2426
2427     success = true;
2428     p.setCompositionMode(QPainter::CompositionMode_Source);
2429     QVERIFY(success);
2430
2431     success = true;
2432     p.setCompositionMode(QPainter::CompositionMode_SourceOver);
2433     QVERIFY(success);
2434
2435     success = true;
2436     p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
2437     QVERIFY(!success);
2438
2439     QVERIFY(qInstallMessageHandler(old) == porterDuff_warningChecker);
2440 }
2441
2442 class quint24
2443 {
2444 public:
2445     inline quint24(quint32 v)
2446     {
2447         data[0] = qBlue(v);
2448         data[1] = qGreen(v);
2449         data[2] = qRed(v);
2450     }
2451
2452     inline operator quint32 ()
2453     {
2454         return qRgb(data[2], data[1], data[0]);
2455     }
2456
2457     inline bool operator==(const quint24 &v) const {
2458         return (data[0] == v.data[0] && data[1] == v.data[1] && data[2] == v.data[2]);
2459     }
2460
2461     uchar data[3];
2462 } Q_PACKED;
2463
2464 void tst_QPainter::drawhelper_blend_color()
2465 {
2466     QImage dest(32, 32, QImage::Format_ARGB8555_Premultiplied);
2467     dest.fill(0xff000000);
2468
2469     {
2470         QPainter p(&dest);
2471         p.fillRect(0, 0, dest.width(), dest.height(), QColor(255, 0, 0, 127));
2472     }
2473
2474     QImage expected(32, 32, QImage::Format_ARGB8555_Premultiplied);
2475     expected.fill(0xff3c007f);
2476
2477     QCOMPARE(dest.pixel(1, 1), expected.pixel(1, 1));
2478     QCOMPARE(dest, expected);
2479 }
2480
2481 #ifndef QT_NO_WIDGETS
2482 class ViewportTestWidget : public QWidget
2483 {
2484 public:
2485     ViewportTestWidget(QWidget *parent = 0) : QWidget(parent), hasPainted(false) {}
2486     QSize sizeHint() const {
2487         return QSize(100, 100);
2488     }
2489
2490     QRect viewport;
2491     bool hasPainted;
2492
2493 protected:
2494     void paintEvent(QPaintEvent *) {
2495         hasPainted = true;
2496         QPainter p(this);
2497         viewport = p.viewport();
2498     }
2499 };
2500
2501 void tst_QPainter::childWidgetViewport()
2502 {
2503     QWidget parent;
2504     parent.setAutoFillBackground(true);
2505     parent.resize(200, 200);
2506     ViewportTestWidget child(&parent);
2507     child.setAutoFillBackground(true);
2508     parent.show();
2509     parent.update();
2510     qApp->processEvents();
2511
2512     if (child.hasPainted) {
2513         QCOMPARE(child.viewport, QRect(QPoint(0, 0), child.sizeHint()));
2514     } else {
2515         qWarning("Failed to ensure that paintEvent has been run. Could not run test.");
2516     }
2517 }
2518 #endif
2519
2520 void tst_QPainter::fillRect_objectBoundingModeGradient()
2521 {
2522     QImage a(10, 10, QImage::Format_ARGB32_Premultiplied);
2523     a.fill(0x0);
2524     QImage b = a;
2525
2526     QLinearGradient g(QPoint(0, 0), QPoint(0, 1));
2527     g.setColorAt(0, Qt::red);
2528     g.setColorAt(1, Qt::blue);
2529     g.setCoordinateMode(QGradient::ObjectBoundingMode);
2530
2531     QPainter p(&a);
2532     p.fillRect(QRect(0, 0, a.width(), a.height()), g);
2533     p.end();
2534
2535     QPainterPath path;
2536     path.addRect(0, 0, a.width(), a.height());
2537
2538     p.begin(&b);
2539     p.fillPath(path, g);
2540     p.end();
2541
2542     QCOMPARE(a, b);
2543 }
2544
2545 void tst_QPainter::fillRect_stretchToDeviceMode()
2546 {
2547     QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2548
2549     QLinearGradient g(QPoint(0, 0), QPoint(0, 1));
2550     g.setCoordinateMode(QGradient::StretchToDeviceMode);
2551
2552     QPainter p(&img);
2553     p.fillRect(img.rect(), g);
2554     p.end();
2555
2556     for (int i = 1; i < img.height(); ++i)
2557         QVERIFY(img.pixel(0, i) != img.pixel(0, i-1));
2558 }
2559
2560 void tst_QPainter::monoImages()
2561 {
2562     Qt::GlobalColor colorPairs[][2] = {
2563         { Qt::white, Qt::black },
2564         { Qt::color0, Qt::color1 },
2565         { Qt::red, Qt::blue }
2566     };
2567
2568     const int numColorPairs = sizeof(colorPairs) / sizeof(QRgb[2]);
2569
2570     QImage transparent(2, 2, QImage::Format_ARGB32_Premultiplied);
2571     transparent.fill(0x0);
2572
2573     for (int i = 1; i < QImage::NImageFormats; ++i) {
2574         for (int j = 0; j < numColorPairs; ++j) {
2575             const QImage::Format format = QImage::Format(i);
2576             if (format == QImage::Format_Indexed8)
2577                 continue;
2578
2579             QImage img(2, 2, format);
2580
2581             if (img.colorCount() > 0) {
2582                 img.setColor(0, QColor(colorPairs[j][0]).rgba());
2583                 img.setColor(1, QColor(colorPairs[j][1]).rgba());
2584             }
2585
2586             img.fill(0x0);
2587             QPainter p(&img);
2588             p.fillRect(0, 0, 2, 2, colorPairs[j][0]);
2589             p.fillRect(0, 0, 1, 1, colorPairs[j][1]);
2590             p.fillRect(1, 1, 1, 1, colorPairs[j][1]);
2591             p.end();
2592
2593             QImage original = img;
2594
2595             p.begin(&img);
2596             p.drawImage(0, 0, transparent);
2597             p.end();
2598
2599             // drawing a transparent image on top of another image
2600             // should not change the image
2601             QCOMPARE(original, img);
2602
2603             if (img.colorCount() == 0)
2604                 continue;
2605
2606             for (int k = 0; k < 2; ++k) {
2607                 QPainter p(&img);
2608                 p.fillRect(0, 0, 2, 2, colorPairs[j][k]);
2609                 p.end();
2610
2611                 QImage argb32p(2, 2, QImage::Format_ARGB32_Premultiplied);
2612                 p.begin(&argb32p);
2613                 p.fillRect(0, 0, 2, 2, colorPairs[j][k]);
2614                 p.end();
2615
2616                 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2617
2618                 // drawing argb32p image on mono image
2619                 p.begin(&img);
2620                 p.drawImage(0, 0, argb32p);
2621                 p.end();
2622
2623                 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2624
2625                 // drawing mono image on argb32p image
2626                 p.begin(&argb32p);
2627                 p.drawImage(0, 0, img);
2628                 p.end();
2629
2630                 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2631             }
2632         }
2633     }
2634 }
2635
2636 #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_CC_MSVC) && !defined(Q_OS_SOLARIS) && !defined(__UCLIBC__)
2637 #include <fenv.h>
2638
2639 static const QString fpeExceptionString(int exception)
2640 {
2641 #ifdef FE_INEXACT
2642     if (exception & FE_INEXACT)
2643         return QLatin1String("Inexact result");
2644 #endif
2645     if (exception & FE_UNDERFLOW)
2646         return QLatin1String("Underflow");
2647     if (exception & FE_OVERFLOW)
2648         return QLatin1String("Overflow");
2649     if (exception & FE_DIVBYZERO)
2650         return QLatin1String("Divide by zero");
2651     if (exception & FE_INVALID)
2652         return QLatin1String("Invalid operation");
2653     return QLatin1String("No exception");
2654 }
2655
2656 class FpExceptionChecker
2657 {
2658 public:
2659     FpExceptionChecker(int exceptionMask)
2660         : m_exceptionMask(exceptionMask)
2661     {
2662         feclearexcept(m_exceptionMask);
2663     }
2664
2665     ~FpExceptionChecker()
2666     {
2667         const int exceptions = fetestexcept(m_exceptionMask);
2668         QVERIFY2(!exceptions, qPrintable(QLatin1String("Floating point exception: ") + fpeExceptionString(exceptions)));
2669     }
2670
2671 private:
2672     int m_exceptionMask;
2673 };
2674
2675 void fpe_rasterizeLine_task232012()
2676 {
2677     FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2678     QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2679     img.fill(0x0);
2680     QPainter p(&img);
2681
2682     p.setBrush(Qt::black);
2683     p.drawRect(QRectF(0, 0, 5, 0));
2684     p.drawRect(QRectF(0, 0, 0, 5));
2685 }
2686
2687 void fpe_pixmapTransform()
2688 {
2689     FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2690
2691     QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2692
2693     QPainter p(&img);
2694
2695     const qreal scaleFactor = 0.001;
2696     const int translateDistance = 1000000;
2697
2698     p.setPen(Qt::red);
2699     p.setBrush(QBrush(Qt::red,Qt::Dense6Pattern));
2700
2701     for (int i = 0; i < 2; ++i) {
2702         p.setRenderHint(QPainter::SmoothPixmapTransform, i);
2703
2704         p.resetTransform();
2705         p.scale(1.1, 1.1);
2706         p.translate(translateDistance, 0);
2707         p.drawRect(-translateDistance, 0, 100, 100);
2708
2709         p.resetTransform();
2710         p.scale(scaleFactor, scaleFactor);
2711         p.drawRect(QRectF(0, 0, 1 / scaleFactor, 1 / scaleFactor));
2712     }
2713 }
2714
2715 void fpe_zeroLengthLines()
2716 {
2717     FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2718
2719     QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2720
2721     QPainter p(&img);
2722
2723     p.setPen(QPen(Qt::black, 3));
2724     p.drawLine(64, 64, 64, 64);
2725 }
2726
2727 void fpe_divByZero()
2728 {
2729     FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2730
2731     QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2732
2733     QPainter p(&img);
2734
2735     p.setRenderHint(QPainter::Antialiasing);
2736
2737     p.drawRect(QRectF(10, 10, 100, 0));
2738     p.drawRect(QRectF(10, 10, 0, 100));
2739
2740     p.drawRect(QRect(10, 10, 100, 0));
2741     p.drawRect(QRect(10, 10, 0, 100));
2742
2743     p.fillRect(QRectF(10, 10, 100, 0), Qt::black);
2744     p.fillRect(QRectF(10, 10, 0, 100), Qt::black);
2745
2746     p.fillRect(QRect(10, 10, 100, 0), Qt::black);
2747     p.fillRect(QRect(10, 10, 0, 100), Qt::black);
2748 }
2749
2750 void fpe_steepSlopes()
2751 {
2752     FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2753
2754     QImage img(1024, 1024, QImage::Format_ARGB32_Premultiplied);
2755
2756     QFETCH(QTransform, transform);
2757     QFETCH(QLineF, line);
2758     QFETCH(bool, antialiased);
2759
2760     QPainter p(&img);
2761
2762     p.setPen(QPen(Qt::black, 1));
2763     p.setRenderHint(QPainter::Antialiasing, antialiased);
2764     p.setTransform(transform);
2765
2766     p.drawLine(line);
2767 }
2768
2769 void fpe_radialGradients()
2770 {
2771     FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2772
2773     QImage img(21, 21, QImage::Format_ARGB32_Premultiplied);
2774     img.fill(0);
2775
2776     double m = img.width() * 0.5;
2777
2778     QPainter p(&img);
2779     p.setRenderHints(QPainter::Antialiasing);
2780     p.setPen(Qt::NoPen);
2781     p.setBrush(QRadialGradient(m, m, m));
2782     p.drawEllipse(img.rect());
2783 }
2784
2785 #define FPE_TEST(x) \
2786 void tst_QPainter::x() \
2787 { \
2788     ::x(); \
2789 }
2790 #else
2791 #define FPE_TEST(x) \
2792 void tst_QPainter::x() \
2793 { \
2794     QSKIP("Floating point exception checking (fenv.h) not available"); \
2795 }
2796 #endif
2797
2798 FPE_TEST(fpe_rasterizeLine_task232012)
2799 FPE_TEST(fpe_pixmapTransform)
2800 FPE_TEST(fpe_zeroLengthLines)
2801 FPE_TEST(fpe_divByZero)
2802 FPE_TEST(fpe_steepSlopes)
2803 FPE_TEST(fpe_radialGradients)
2804
2805 void tst_QPainter::fpe_steepSlopes_data()
2806 {
2807     QTest::addColumn<QTransform>("transform");
2808     QTest::addColumn<QLineF>("line");
2809     QTest::addColumn<bool>("antialiased");
2810
2811     {
2812         const qreal dsin = 0.000014946676875461832484392500630665523431162000633776187896728515625;
2813         const qreal dcos = 0.9999999998882984630910186751862056553363800048828125;
2814
2815         const QTransform transform = QTransform(QMatrix(dcos, dsin, -dsin, dcos, 64, 64));
2816         const QLineF line(2, 2, 2, 6);
2817
2818         QTest::newRow("task 207147 aa") << transform << line << true;
2819         QTest::newRow("task 207147 no aa") << transform << line << false;
2820     }
2821
2822     {
2823         QTransform transform;
2824         transform.rotate(0.0000001);
2825         const QLineF line(5, 5, 10, 5);
2826
2827         QTest::newRow("task 166702 aa") << transform << line << true;
2828         QTest::newRow("task 166702 no aa") << transform << line << false;
2829     }
2830
2831     {
2832         const QTransform transform;
2833         const QLineF line(2.5, 2.5, 2.5 + 1/256., 60000.5);
2834
2835         QTest::newRow("steep line aa") << transform << line << true;
2836         QTest::newRow("steep line no aa") << transform << line << false;
2837     }
2838
2839     {
2840         const QTransform transform;
2841         const QLineF line(2.5, 2.5, 2.5 + 1/256., 1024);
2842
2843         QTest::newRow("steep line 2 aa") << transform << line << true;
2844         QTest::newRow("steep line 2 no aa") << transform << line << false;
2845     }
2846
2847     {
2848         const QTransform transform;
2849         const QLineF line(2.5, 2.5, 2.5 + 1/64., 1024);
2850
2851         QTest::newRow("steep line 3 aa") << transform << line << true;
2852         QTest::newRow("steep line 3 no aa") << transform << line << false;
2853     }
2854 }
2855
2856 qreal randf()
2857 {
2858     return rand() / (RAND_MAX + 1.0);
2859 }
2860
2861 QPointF randInRect(const QRectF &rect)
2862 {
2863     const qreal x = rect.left() + rect.width() * randf();
2864     const qreal y = rect.top() + rect.height() * randf();
2865
2866     return QPointF(x, y);
2867 }
2868
2869 void tst_QPainter::rasterizer_asserts()
2870 {
2871     QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2872
2873     QRectF middle(QPointF(0, 0), img.size());
2874     QRectF left = middle.translated(-middle.width(), 0);
2875     QRectF right = middle.translated(middle.width(), 0);
2876
2877     QPainter p(&img);
2878     img.fill(Qt::white);
2879     p.setCompositionMode(QPainter::CompositionMode_Destination);
2880     for (int i = 0; i < 100000; ++i) {
2881         QPainterPath path;
2882         path.moveTo(randInRect(middle));
2883         path.lineTo(randInRect(left));
2884         path.lineTo(randInRect(right));
2885
2886         p.fillPath(path, Qt::black);
2887     }
2888 }
2889
2890 void tst_QPainter::rasterizer_negativeCoords()
2891 {
2892     QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2893     img.fill(0x0);
2894
2895     QImage original = img;
2896
2897     QPainter p(&img);
2898     p.rotate(90);
2899     p.fillRect(0, 0, 70, 50, Qt::black);
2900
2901     // image should not have changed
2902     QCOMPARE(img.pixel(0, 0), 0x0U);
2903     QCOMPARE(img, original);
2904 }
2905
2906 void tst_QPainter::blendOverFlow_data()
2907 {
2908     QTest::addColumn<QImage::Format>("format");
2909     QTest::addColumn<int>("width");
2910     QTest::addColumn<int>("height");
2911
2912     QImage::Format format = QImage::Format_ARGB8555_Premultiplied;
2913     QTest::newRow("555,1,1") << format << 1 << 1;
2914     QTest::newRow("555,2,2") << format << 2 << 2;
2915     QTest::newRow("555,10,10") << format << 10 << 10;
2916
2917     format = QImage::Format_ARGB8565_Premultiplied;
2918     QTest::newRow("565,1,1") << format << 1 << 1;
2919     QTest::newRow("565,2,2") << format << 2 << 2;
2920     QTest::newRow("565,10,10") << format << 10 << 10;
2921 }
2922
2923 void tst_QPainter::blendOverFlow()
2924 {
2925     QFETCH(QImage::Format, format);
2926     QFETCH(int, width);
2927     QFETCH(int, height);
2928
2929     QImage dest(width, height, format);
2930     QImage src(width, height, format);
2931
2932     {
2933         QPainter p(&dest);
2934         p.fillRect(0, 0, width, height, Qt::green);
2935     }
2936     QImage expected = dest;
2937
2938     {
2939         QPainter p(&src);
2940         p.setCompositionMode(QPainter::CompositionMode_Source);
2941         p.fillRect(0, 0, width, height, QColor(0, 255, 0, 6));
2942     }
2943
2944     {
2945         QPainter p(&dest);
2946         p.drawImage(0, 0, src);
2947     }
2948
2949     QCOMPARE(dest.pixel(0, 0), expected.pixel(0, 0));
2950     QCOMPARE(dest, expected);
2951 }
2952
2953 void tst_QPainter::largeImagePainting_data()
2954 {
2955     QTest::addColumn<int>("width");
2956     QTest::addColumn<int>("height");
2957     QTest::addColumn<bool>("antialiased");
2958
2959     QTest::newRow("tall") << 1 << 32767 << false;
2960     QTest::newRow("tall aa") << 1 << 32767 << true;
2961     QTest::newRow("wide") << 32767 << 1 << false;
2962     QTest::newRow("wide aa") << 32767 << 1 << true;
2963 }
2964
2965 void tst_QPainter::largeImagePainting()
2966 {
2967     QPainterPath path;
2968     path.addRect(0, 0, 1, 1);
2969     path.addRect(2, 0, 1, 1);
2970     path.addRect(0, 2, 1, 1);
2971
2972     QFETCH(int, width);
2973     QFETCH(int, height);
2974     QFETCH(bool, antialiased);
2975
2976     QImage img(width, height, QImage::Format_ARGB32_Premultiplied);
2977     img.fill(0x0);
2978
2979     QPainter p(&img);
2980     p.setPen(Qt::NoPen);
2981     p.setBrush(Qt::white);
2982
2983     p.setRenderHint(QPainter::Antialiasing, antialiased);
2984
2985     for (int i = 0; i < img.width(); i += 4) {
2986         p.drawPath(path);
2987         p.translate(4, 0);
2988     }
2989
2990     p.resetMatrix();
2991
2992     for (int i = 4; i < img.height(); i += 4) {
2993         p.translate(0, 4);
2994         p.drawPath(path);
2995     }
2996
2997     for (int i = 0; i < img.width(); ++i) {
2998         if (i % 2)
2999             QCOMPARE(img.pixel(i, 0), 0x0U);
3000         else
3001             QCOMPARE(img.pixel(i, 0), 0xffffffffU);
3002     }
3003
3004     for (int i = 1; i < img.height(); ++i) {
3005         if (i % 2)
3006             QCOMPARE(img.pixel(0, i), 0x0U);
3007         else
3008             QCOMPARE(img.pixel(0, i), 0xffffffffU);
3009     }
3010 }
3011
3012 void tst_QPainter::imageScaling_task206785()
3013 {
3014     QImage src(32, 2, QImage::Format_ARGB32_Premultiplied);
3015     src.fill(0xffffffff);
3016
3017     QImage dst(128, 128, QImage::Format_ARGB32_Premultiplied);
3018
3019     QImage expected(128, 128, QImage::Format_ARGB32_Premultiplied);
3020     expected.fill(0xffffffff);
3021
3022     for (int i = 1; i < 5; ++i) {
3023         qreal scale = i / qreal(5);
3024
3025         dst.fill(0xff000000);
3026
3027         QPainter p(&dst);
3028         p.scale(dst.width() / qreal(src.width()), scale);
3029
3030         for (int y = 0; y * scale < dst.height(); ++y)
3031             p.drawImage(0, y, src);
3032
3033         p.end();
3034
3035         QCOMPARE(dst, expected);
3036     }
3037 }
3038
3039 #define FOR_EACH_NEIGHBOR_8 for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if (dx != 0 || dy != 0)
3040 #define FOR_EACH_NEIGHBOR_4 for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if ((dx == 0) != (dy == 0))
3041
3042 uint qHash(const QPoint &point)
3043 {
3044     return qHash(qMakePair(point.x(), point.y()));
3045 }
3046
3047 bool verifyOutlineFillConsistency(const QImage &img, QRgb outside, QRgb inside, QRgb outline)
3048 {
3049     if (img.pixel(img.width() / 2, img.height() / 2) != inside)
3050         return false;
3051
3052     int x = img.width() / 2;
3053     int y = img.height() / 2;
3054
3055     while (img.pixel(++x, y) == inside)
3056         ;
3057
3058     if (img.pixel(x, y) != outline)
3059         return false;
3060
3061     QQueue<QPoint> discovered;
3062     discovered.enqueue(QPoint(x, y));
3063
3064     QVector<bool> visited(img.width() * img.height());
3065     visited.fill(false);
3066
3067     while (!discovered.isEmpty()) {
3068         QPoint p = discovered.dequeue();
3069         QRgb pixel = img.pixel(p.x(), p.y());
3070
3071         bool &v = visited[p.y() * img.width() + p.x()];
3072         if (v)
3073             continue;
3074         v = true;
3075
3076         if (pixel == outline) {
3077             FOR_EACH_NEIGHBOR_8 {
3078                 QPoint x(p.x() + dx, p.y() + dy);
3079                 discovered.enqueue(x);
3080             }
3081         } else {
3082             FOR_EACH_NEIGHBOR_4 {
3083                 if ((dx == 0) == (dy == 0))
3084                     continue;
3085                 QRgb neighbor = img.pixel(p.x() + dx, p.y() + dy);
3086                 if ((pixel == inside && neighbor == outside) ||
3087                     (pixel == outside && neighbor == inside))
3088                     return false;
3089             }
3090         }
3091     }
3092
3093     return true;
3094 }
3095
3096 #undef FOR_EACH_NEIGHBOR_8
3097 #undef FOR_EACH_NEIGHBOR_4
3098
3099 void tst_QPainter::outlineFillConsistency()
3100 {
3101     QImage dst(256, 256, QImage::Format_ARGB32_Premultiplied);
3102
3103     QPolygonF poly;
3104     poly << QPointF(5, -100) << QPointF(-70, 20) << QPointF(95, 25);
3105
3106     QPen pen(Qt::red);
3107     QBrush brush(Qt::black);
3108
3109     QRgb background = 0xffffffff;
3110     for (int i = 0; i < 360; ++i) {
3111         dst.fill(background);
3112
3113         QPainter p(&dst);
3114         p.translate(dst.width() / 2, dst.height() / 2);
3115
3116         QPolygonF copy = poly;
3117         for (int j = 0; j < copy.size(); ++j)
3118             copy[j] = QTransform().rotate(i).map(copy[j]);
3119
3120         p.setPen(pen);
3121         p.setBrush(brush);
3122         p.drawPolygon(copy);
3123         p.end();
3124
3125         QVERIFY(verifyOutlineFillConsistency(dst, background, brush.color().rgba(), pen.color().rgba()));
3126     }
3127 }
3128
3129 void tst_QPainter::drawImage_task217400_data()
3130 {
3131     QTest::addColumn<QImage::Format>("format");
3132
3133     QTest::newRow("444") << QImage::Format_ARGB4444_Premultiplied;
3134     QTest::newRow("555") << QImage::Format_ARGB8555_Premultiplied;
3135     QTest::newRow("565") << QImage::Format_ARGB8565_Premultiplied;
3136 //    QTest::newRow("666") << QImage::Format_ARGB6666_Premultiplied;
3137     QTest::newRow("888p") << QImage::Format_ARGB32_Premultiplied;
3138     QTest::newRow("888") << QImage::Format_ARGB32;
3139 }
3140
3141 void tst_QPainter::drawImage_task217400()
3142 {
3143     QFETCH(QImage::Format, format);
3144
3145     const QImage src = QImage(QFINDTESTDATA("task217400.png"))
3146                        .convertToFormat(format);
3147     QVERIFY(!src.isNull());
3148
3149     QImage expected(src.size(), format);
3150     {
3151         QPainter p(&expected);
3152         p.fillRect(0, 0, expected.width(), expected.height(), Qt::white);
3153         p.drawImage(0, 0, src);
3154     }
3155
3156     for (int i = 1; i <= 4; ++i) {
3157         QImage dest(src.width() + i, src.height(), format);
3158         {
3159             QPainter p(&dest);
3160             p.fillRect(0, 0, dest.width(), dest.height(), Qt::white);
3161             p.drawImage(i, 0, src);
3162         }
3163
3164         const QImage result = dest.copy(i, 0, src.width(), src.height());
3165
3166         QCOMPARE(result, expected);
3167     }
3168 }
3169
3170 void tst_QPainter::drawImage_task258776()
3171 {
3172     QImage src(16, 16, QImage::Format_RGB888);
3173     QImage dest(33, 33, QImage::Format_RGB888);
3174     src.fill(0x00ff00);
3175     dest.fill(0xff0000);
3176
3177     QPainter painter(&dest);
3178     painter.drawImage(QRectF(0.499, 0.499, 32, 32), src, QRectF(0, 0, 16, 16));
3179     painter.end();
3180
3181     QImage expected(33, 33, QImage::Format_RGB32);
3182     expected.fill(0xff0000);
3183
3184     painter.begin(&expected);
3185     painter.drawImage(QRectF(0, 0, 32, 32), src);
3186     painter.end();
3187
3188     dest = dest.convertToFormat(QImage::Format_RGB32);
3189
3190     dest.save("dest.png");
3191     expected.save("expected.png");
3192     QCOMPARE(dest, expected);
3193 }
3194
3195 void tst_QPainter::clipRectSaveRestore()
3196 {
3197     QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3198     img.fill(0x0);
3199
3200     QPainter p(&img);
3201     p.setClipRect(QRect(0, 0, 10, 10));
3202     p.save();
3203     p.setClipRect(QRect(5, 5, 5, 5), Qt::IntersectClip);
3204     p.restore();
3205     p.fillRect(0, 0, 64, 64, Qt::black);
3206     p.end();
3207
3208     QCOMPARE(img.pixel(0, 0), QColor(Qt::black).rgba());
3209 }
3210
3211 void tst_QPainter::clippedImage()
3212 {
3213     QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
3214     img.fill(0x0);
3215
3216     QImage src(16, 16, QImage::Format_RGB32);
3217     src.fill(QColor(Qt::red).rgba());
3218
3219     QPainter p(&img);
3220     p.setClipRect(QRect(1, 1, 14, 14));
3221     p.drawImage(0, 0, src);
3222     p.end();
3223
3224     QCOMPARE(img.pixel(0, 0), 0x0U);
3225     QCOMPARE(img.pixel(1, 1), src.pixel(1, 1));
3226 }
3227
3228 void tst_QPainter::stateResetBetweenQPainters()
3229 {
3230     QImage img(16, 16, QImage::Format_ARGB32);
3231
3232     {
3233         QPainter p(&img);
3234         p.setCompositionMode(QPainter::CompositionMode_Source);
3235         p.fillRect(0, 0, 16, 16, Qt::red);
3236     }
3237
3238     {
3239         QPainter p2(&img);
3240         p2.fillRect(0, 0, 16, 16, QColor(0, 0, 255, 63));
3241     }
3242
3243     img.save("foo.png");
3244
3245     QVERIFY(img.pixel(0, 0) != qRgba(0, 0, 255, 63));
3246     QVERIFY(qRed(img.pixel(0, 0)) > 0); // We didn't erase the red channel...
3247     QVERIFY(qBlue(img.pixel(0, 0)) < 255); // We blended the blue channel
3248 }
3249
3250 void tst_QPainter::drawRect_task215378()
3251 {
3252     QImage img(11, 11, QImage::Format_ARGB32_Premultiplied);
3253     img.fill(QColor(Qt::white).rgba());
3254
3255     QPainter p(&img);
3256     p.setPen(QColor(127, 127, 127, 127));
3257     p.drawRect(0, 0, 10, 10);
3258     p.end();
3259
3260     QCOMPARE(img.pixel(0, 0), img.pixel(1, 0));
3261     QCOMPARE(img.pixel(0, 0), img.pixel(0, 1));
3262     QVERIFY(img.pixel(0, 0) != img.pixel(1, 1));
3263 }
3264
3265 void tst_QPainter::drawRect_task247505()
3266 {
3267     QImage a(10, 10, QImage::Format_ARGB32_Premultiplied);
3268     a.fill(0);
3269     QImage b = a;
3270
3271     QPainter p(&a);
3272     p.setPen(Qt::NoPen);
3273     p.setBrush(Qt::black);
3274     p.drawRect(QRectF(10, 0, -10, 10));
3275     p.end();
3276     p.begin(&b);
3277     p.setPen(Qt::NoPen);
3278     p.setBrush(Qt::black);
3279     p.drawRect(QRectF(0, 0, 10, 10));
3280     p.end();
3281
3282     QCOMPARE(a, b);
3283 }
3284
3285 void tst_QPainter::drawImage_data()
3286 {
3287     QTest::addColumn<int>("x");
3288     QTest::addColumn<int>("y");
3289     QTest::addColumn<int>("w");
3290     QTest::addColumn<int>("h");
3291     QTest::addColumn<QImage::Format>("srcFormat");
3292     QTest::addColumn<QImage::Format>("dstFormat");
3293
3294     for (int srcFormat = QImage::Format_Mono; srcFormat < QImage::NImageFormats; ++srcFormat) {
3295         for (int dstFormat = QImage::Format_Mono; dstFormat < QImage::NImageFormats; ++dstFormat) {
3296             if (dstFormat == QImage::Format_Indexed8)
3297                 continue;
3298             for (int odd_x = 0; odd_x <= 1; ++odd_x) {
3299                 for (int odd_width = 0; odd_width <= 1; ++odd_width) {
3300                     QString description =
3301                         QString("srcFormat %1, dstFormat %2, odd x: %3, odd width: %4")
3302                             .arg(srcFormat).arg(dstFormat).arg(odd_x).arg(odd_width);
3303
3304                     QTest::newRow(qPrintable(description)) << (10 + odd_x) << 10 << (20 + odd_width) << 20
3305                         << QImage::Format(srcFormat)
3306                         << QImage::Format(dstFormat);
3307                 }
3308             }
3309         }
3310     }
3311 }
3312
3313 bool verifyImage(const QImage &img, int x, int y, int w, int h, uint background)
3314 {
3315     int imgWidth = img.width();
3316     int imgHeight = img.height();
3317     for (int i = 0; i < imgHeight; ++i) {
3318         for (int j = 0; j < imgWidth; ++j) {
3319             uint pixel = img.pixel(j, i);
3320             bool outside = j < x || j >= (x + w) || i < y || i >= (y + h);
3321             if (outside != (pixel == background)) {
3322                 //printf("%d %d, expected %x, got %x, outside: %d\n", x, y, background, pixel, outside);
3323                 return false;
3324             }
3325         }
3326     }
3327
3328     return true;
3329 }
3330
3331 void tst_QPainter::drawImage()
3332 {
3333     QFETCH(int, x);
3334     QFETCH(int, y);
3335     QFETCH(int, w);
3336     QFETCH(int, h);
3337     QFETCH(QImage::Format, srcFormat);
3338     QFETCH(QImage::Format, dstFormat);
3339
3340     QImage dst(40, 40, QImage::Format_RGB32);
3341     dst.fill(0xffffffff);
3342
3343     dst = dst.convertToFormat(dstFormat);
3344     uint background = dst.pixel(0, 0);
3345
3346     QImage src(w, h, QImage::Format_RGB32);
3347     src.fill(0xff000000);
3348     src = src.convertToFormat(srcFormat);
3349
3350     QPainter p(&dst);
3351     p.drawImage(x, y, src);
3352     p.end();
3353
3354     QVERIFY(verifyImage(dst, x, y, w, h, background));
3355 }
3356
3357 void tst_QPainter::imageCoordinateLimit()
3358 {
3359     QImage img(64, 40000, QImage::Format_MonoLSB);
3360     QPainter p(&img);
3361     p.drawText(10, 36000, QLatin1String("foo"));
3362     p.setPen(QPen(Qt::black, 2));
3363     p.drawLine(10, 0, 60, 40000);
3364
3365     p.setRenderHint(QPainter::Antialiasing);
3366     p.drawLine(10, 0, 60, 40000);
3367 }
3368
3369
3370 void tst_QPainter::imageBlending_data()
3371 {
3372     QTest::addColumn<QImage::Format>("sourceFormat");
3373     QTest::addColumn<QImage::Format>("destFormat");
3374     QTest::addColumn<int>("error");
3375
3376     int error_rgb565 = ((1<<3) + (1<<2) + (1<<3));
3377     QTest::newRow("rgb565_on_rgb565") << QImage::Format_RGB16
3378                                       << QImage::Format_RGB16
3379                                       << 0;
3380     QTest::newRow("argb8565_on_rgb565") << QImage::Format_ARGB8565_Premultiplied
3381                                         << QImage::Format_RGB16
3382                                         << error_rgb565;
3383
3384     QTest::newRow("rgb32_on_rgb565") << QImage::Format_RGB32
3385                                      << QImage::Format_RGB16
3386                                      << error_rgb565;
3387
3388     QTest::newRow("argb32pm_on_rgb565") << QImage::Format_ARGB32_Premultiplied
3389                                         << QImage::Format_RGB16
3390                                         << error_rgb565;
3391 }
3392
3393 int diffColor(quint32 ap, quint32 bp)
3394 {
3395     int a = qAlpha(ap) - qAlpha(bp);
3396     int r = qRed(ap) - qRed(bp);
3397     int b = qBlue(ap) - qBlue(bp);
3398     int g = qBlue(ap) - qBlue(bp);
3399
3400     return qAbs(a) + qAbs(r) + qAbs(g) + qAbs(b);
3401 }
3402
3403 // this test assumes premultiplied pixels...
3404
3405 void tst_QPainter::imageBlending()
3406 {
3407     QFETCH(QImage::Format, sourceFormat);
3408     QFETCH(QImage::Format, destFormat);
3409     QFETCH(int, error);
3410
3411     QImage dest;
3412     {
3413         QImage orig_dest(6, 6, QImage::Format_ARGB32_Premultiplied);
3414         orig_dest.fill(0);
3415         QPainter p(&orig_dest);
3416         p.fillRect(0, 0, 6, 3, QColor::fromRgbF(1, 0, 0));
3417         p.fillRect(3, 0, 3, 6, QColor::fromRgbF(0, 0, 1, 0.5));
3418         p.end();
3419         dest = orig_dest.convertToFormat(destFormat);
3420
3421         // An image like this: (r = red, m = magenta, b = light alpha blue, 0 = transparent)
3422         // r r r m m m
3423         // r r r m m m
3424         // r r r m m m
3425         // 0 0 0 b b b
3426         // 0 0 0 b b b
3427         // 0 0 0 b b b
3428     }
3429
3430     QImage source;
3431     {
3432         QImage orig_source(6, 6, QImage::Format_ARGB32_Premultiplied);
3433         orig_source.fill(0);
3434         QPainter p(&orig_source);
3435         p.fillRect(1, 1, 4, 4, QColor::fromRgbF(0, 1, 0, 0.5));
3436         p.fillRect(2, 2, 2, 2, QColor::fromRgbF(0, 1, 0));
3437         p.end();
3438         source = orig_source.convertToFormat(sourceFormat);
3439
3440         // An image like this: (0 = transparent, . = green at 0.5 alpha, g = opaque green.
3441         // 0 0 0 0 0 0
3442         // 0 . . . . 0
3443         // 0 . g g . 0
3444         // 0 . g g . 0
3445         // 0 . . . . 0
3446         // 0 0 0 0 0 0
3447     }
3448
3449     QPainter p(&dest);
3450     p.drawImage(0, 0, source);
3451     p.end();
3452
3453     // resulting image:
3454     // r  r  r  m  m  m
3455     // r  r. r. m. m. m
3456     // r  r. g  g  m. m
3457     // 0  .  g  g  b. b
3458     // 0  .  .  b. b. b
3459     // 0  0  0  b  b  b
3460
3461     // the g pixels, always green..
3462     QVERIFY(diffColor(dest.pixel(2, 2), 0xff00ff00) <= error); // g
3463
3464     if (source.hasAlphaChannel()) {
3465         QVERIFY(diffColor(dest.pixel(0, 0), 0xffff0000) <= error); // r
3466         QVERIFY(diffColor(dest.pixel(5, 0), 0xff7f007f) <= error); // m
3467         QVERIFY(diffColor(dest.pixel(1, 1), 0xff7f7f00) <= error); // r.
3468         QVERIFY(diffColor(dest.pixel(4, 1), 0xff3f7f3f) <= error); // m.
3469         if (dest.hasAlphaChannel()) {
3470             QVERIFY(diffColor(dest.pixel(1, 3), 0x7f007f00) <= error); // .
3471             QVERIFY(diffColor(dest.pixel(4, 3), 0x7f007f3f) <= error); // b.
3472             QVERIFY(diffColor(dest.pixel(4, 3), 0x7f007f3f) <= error); // b.
3473             QVERIFY(diffColor(dest.pixel(4, 4), 0x7f00007f) <= error); // b
3474             QVERIFY(diffColor(dest.pixel(4, 0), 0) <= 0); // 0
3475        }
3476     } else {
3477         QVERIFY(diffColor(dest.pixel(0, 0), 0xff000000) <= 0);
3478         QVERIFY(diffColor(dest.pixel(1, 1), 0xff007f00) <= error);
3479     }
3480 }
3481
3482 void tst_QPainter::imageBlending_clipped()
3483 {
3484     QImage src(20, 20, QImage::Format_RGB16);
3485     QPainter p(&src);
3486     p.fillRect(src.rect(), Qt::red);
3487     p.end();
3488
3489     QImage dst(40, 20, QImage::Format_RGB16);
3490     p.begin(&dst);
3491     p.fillRect(dst.rect(), Qt::white);
3492     p.end();
3493
3494     QImage expected = dst;
3495
3496     p.begin(&dst);
3497     p.setClipRect(QRect(23, 0, 20, 20));
3498
3499     // should be completely clipped
3500     p.drawImage(QRectF(3, 0, 20, 20), src);
3501     p.end();
3502
3503     // dst should be left unchanged
3504     QCOMPARE(dst, expected);
3505 }
3506
3507 void tst_QPainter::paintOnNullPixmap()
3508 {
3509     QPixmap pix(16, 16);
3510
3511     QPixmap textPixmap;
3512     QPainter p(&textPixmap);
3513     p.drawPixmap(10, 10, pix);
3514     p.end();
3515
3516     QPixmap textPixmap2(16,16);
3517     p.begin(&textPixmap2);
3518     p.end();
3519 }
3520
3521 void tst_QPainter::checkCompositionMode()
3522 {
3523     QImage refImage(50,50,QImage::Format_ARGB32);
3524     QPainter painter(&refImage);
3525     painter.fillRect(QRect(0,0,50,50),Qt::blue);
3526
3527     QImage testImage(50,50,QImage::Format_ARGB32);
3528     QPainter p(&testImage);
3529     p.fillRect(QRect(0,0,50,50),Qt::red);
3530     p.save();
3531     p.setCompositionMode(QPainter::CompositionMode_SourceOut);
3532     p.restore();
3533     p.fillRect(QRect(0,0,50,50),Qt::blue);
3534
3535     QCOMPARE(refImage.pixel(20,20),testImage.pixel(20,20));
3536 }
3537
3538 static QLinearGradient inverseGradient(QLinearGradient g)
3539 {
3540     QLinearGradient g2 = g;
3541
3542     QGradientStops stops = g.stops();
3543
3544     QGradientStops inverse;
3545     foreach (QGradientStop stop, stops)
3546         inverse << QGradientStop(1 - stop.first, stop.second);
3547
3548     g2.setStops(inverse);
3549     return g2;
3550 }
3551
3552 void tst_QPainter::linearGradientSymmetry_data()
3553 {
3554     QTest::addColumn<QGradientStops>("stops");
3555
3556     if (sizeof(qreal) != sizeof(float)) {
3557         QGradientStops stops;
3558         stops << qMakePair(qreal(0.0), QColor(Qt::blue));
3559         stops << qMakePair(qreal(0.2), QColor(220, 220, 220, 0));
3560         stops << qMakePair(qreal(0.6), QColor(Qt::red));
3561         stops << qMakePair(qreal(0.9), QColor(220, 220, 220, 255));
3562         stops << qMakePair(qreal(1.0), QColor(Qt::black));
3563         QTest::newRow("multiple stops") << stops;
3564     }
3565
3566     {
3567         QGradientStops stops;
3568         stops << qMakePair(qreal(0.0), QColor(Qt::blue));
3569         stops << qMakePair(qreal(1.0), QColor(Qt::black));
3570         QTest::newRow("two stops") << stops;
3571     }
3572
3573     if (sizeof(qreal) != sizeof(float)) {
3574         QGradientStops stops;
3575         stops << qMakePair(qreal(0.3), QColor(Qt::blue));
3576         stops << qMakePair(qreal(0.6), QColor(Qt::black));
3577         QTest::newRow("two stops 2") << stops;
3578     }
3579 }
3580
3581 void tst_QPainter::linearGradientSymmetry()
3582 {
3583     QFETCH(QGradientStops, stops);
3584
3585     QImage a(64, 8, QImage::Format_ARGB32_Premultiplied);
3586     QImage b(64, 8, QImage::Format_ARGB32_Premultiplied);
3587
3588     a.fill(0);
3589     b.fill(0);
3590
3591     QLinearGradient gradient(QRectF(b.rect()).topLeft(), QRectF(b.rect()).topRight());
3592     gradient.setStops(stops);
3593
3594     QPainter pa(&a);
3595     pa.fillRect(a.rect(), gradient);
3596     pa.end();
3597
3598     QPainter pb(&b);
3599     pb.fillRect(b.rect(), inverseGradient(gradient));
3600     pb.end();
3601
3602     b = b.mirrored(true);
3603     QCOMPARE(a, b);
3604 }
3605
3606 void tst_QPainter::gradientInterpolation()
3607 {
3608     QImage image(256, 8, QImage::Format_ARGB32_Premultiplied);
3609     QPainter painter;
3610
3611     QLinearGradient gradient(QRectF(image.rect()).topLeft(), QRectF(image.rect()).topRight());
3612     gradient.setColorAt(0.0, QColor(255, 0, 0, 0));
3613     gradient.setColorAt(1.0, Qt::blue);
3614
3615     image.fill(0);
3616     painter.begin(&image);
3617     painter.fillRect(image.rect(), gradient);
3618     painter.end();
3619
3620     const QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(3));
3621
3622     for (int i = 0; i < 256; ++i) {
3623         QCOMPARE(qAlpha(line[i]), qBlue(line[i])); // bright blue
3624         QVERIFY(qAbs(qAlpha(line[i]) - i) < 3); // linear alpha
3625         QCOMPARE(qRed(line[i]), 0); // no red component
3626         QCOMPARE(qGreen(line[i]), 0); // no green component
3627     }
3628
3629     gradient.setInterpolationMode(QGradient::ComponentInterpolation);
3630
3631     image.fill(0);
3632     painter.begin(&image);
3633     painter.fillRect(image.rect(), gradient);
3634     painter.end();
3635
3636     for (int i = 1; i < 256; ++i) {
3637         if (i < 128) {
3638             QVERIFY(qRed(line[i]) >= qBlue(line[i])); // red is dominant
3639         } else {
3640             QVERIFY(qRed(line[i]) <= qBlue(line[i])); // blue is dominant
3641         }
3642         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
3643         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
3644         QVERIFY(qAbs(qAlpha(line[i]) - i) < 3); // linear alpha
3645         QCOMPARE(qGreen(line[i]), 0); // no green component
3646     }
3647 }
3648
3649 void tst_QPainter::drawPolygon()
3650 {
3651     QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
3652
3653     QPainterPathStroker stroker;
3654     stroker.setWidth(1.5);
3655
3656     QPainterPath path;
3657     path.moveTo(2, 34);
3658     path.lineTo(34, 2);
3659
3660     QPolygonF poly = stroker.createStroke(path).toFillPolygon();
3661
3662     img.fill(0xffffffff);
3663     QPainter p(&img);
3664     p.setRenderHint(QPainter::Antialiasing);
3665     p.setBrush(Qt::red);
3666     p.setPen(Qt::NoPen);
3667     p.drawPolygon(poly);
3668     p.translate(64, 64);
3669     p.drawPolygon(poly);
3670     p.end();
3671
3672     QImage a = img.copy();
3673
3674     img.fill(0xffffffff);
3675     p.begin(&img);
3676     p.setRenderHint(QPainter::Antialiasing);
3677     p.setBrush(Qt::red);
3678     p.setPen(Qt::NoPen);
3679     p.translate(64, 64);
3680     p.drawPolygon(poly);
3681     p.resetTransform();
3682     p.drawPolygon(poly);
3683     p.end();
3684
3685     QCOMPARE(a, img);
3686 }
3687
3688 void tst_QPainter::inactivePainter()
3689 {
3690     // This test succeeds if it doesn't segfault.
3691
3692     QPainter p;
3693     QPainterPath path;
3694     QRegion region(QRect(20, 20, 60, 40));
3695     QPolygonF polygon(QVector<QPointF>() << QPointF(0, 0) << QPointF(12, 0) << QPointF(8, 6));
3696     path.addPolygon(polygon);
3697
3698     p.save();
3699     p.restore();
3700
3701     p.background();
3702     p.setBackground(QBrush(Qt::blue));
3703
3704     p.brush();
3705     p.setBrush(Qt::red);
3706     p.setBrush(Qt::NoBrush);
3707     p.setBrush(QBrush(Qt::white, Qt::DiagCrossPattern));
3708
3709     p.backgroundMode();
3710     p.setBackgroundMode(Qt::OpaqueMode);
3711
3712     p.boundingRect(QRectF(0, 0, 100, 20), Qt::AlignCenter, QLatin1String("Hello, World!"));
3713     p.boundingRect(QRect(0, 0, 100, 20), Qt::AlignCenter, QLatin1String("Hello, World!"));
3714
3715     p.brushOrigin();
3716     p.setBrushOrigin(QPointF(12, 34));
3717     p.setBrushOrigin(QPoint(12, 34));
3718
3719     p.clipPath();
3720     p.clipRegion();
3721     p.hasClipping();
3722     p.setClipPath(path);
3723     p.setClipRect(QRectF(42, 42, 42, 42));
3724     p.setClipRect(QRect(42, 42, 42, 42));
3725     p.setClipRegion(region);
3726     p.setClipping(true);
3727
3728     p.combinedMatrix();
3729     p.combinedTransform();
3730
3731     p.compositionMode();
3732     p.setCompositionMode(QPainter::CompositionMode_Plus);
3733
3734     p.device();
3735     p.deviceMatrix();
3736     p.deviceTransform();
3737
3738     p.font();
3739     p.setFont(QFont(QLatin1String("Times"), 24));
3740
3741     p.fontInfo();
3742     p.fontMetrics();
3743
3744     p.layoutDirection();
3745     p.setLayoutDirection(Qt::RightToLeft);
3746
3747     p.opacity();
3748     p.setOpacity(0.75);
3749
3750     p.pen();
3751     p.setPen(QPen(Qt::red));
3752     p.setPen(Qt::green);
3753     p.setPen(Qt::NoPen);
3754
3755     p.renderHints();
3756     p.setRenderHint(QPainter::Antialiasing, true);
3757     p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
3758
3759     p.resetMatrix();
3760     p.resetTransform();
3761     p.rotate(1);
3762     p.scale(2, 2);
3763     p.shear(-1, 1);
3764     p.translate(3, 14);
3765
3766     p.viewTransformEnabled();
3767     p.setViewTransformEnabled(true);
3768
3769     p.viewport();
3770     p.setViewport(QRect(10, 10, 620, 460));
3771
3772     p.window();
3773     p.setWindow(QRect(10, 10, 620, 460));
3774
3775     p.worldMatrix();
3776     p.setWorldMatrix(QMatrix().translate(43, 21), true);
3777     p.setWorldMatrixEnabled(true);
3778
3779     p.transform();
3780     p.setTransform(QTransform().translate(12, 34), true);
3781
3782     p.worldTransform();
3783     p.setWorldTransform(QTransform().scale(0.5, 0.5), true);
3784 }
3785
3786 bool testCompositionMode(int src, int dst, int expected, QPainter::CompositionMode op, qreal opacity = 1.0)
3787 {
3788     // The test image needs to be large enough to test SIMD code
3789     const QSize imageSize(100, 100);
3790
3791     QImage actual(imageSize, QImage::Format_ARGB32_Premultiplied);
3792     actual.fill(QColor(dst, dst, dst).rgb());
3793
3794     QPainter p(&actual);
3795     p.setCompositionMode(op);
3796     p.setOpacity(opacity);
3797     p.fillRect(QRect(QPoint(), imageSize), QColor(src, src, src));
3798     p.end();
3799
3800     if (qRed(actual.pixel(0, 0)) != expected) {
3801         qDebug("Fail: mode %d, src[%d] dst [%d] actual [%d] expected [%d]", op,
3802                src, dst, qRed(actual.pixel(0, 0)), expected);
3803         return false;
3804     } else {
3805         QImage refImage(imageSize, QImage::Format_ARGB32_Premultiplied);
3806         refImage.fill(QColor(expected, expected, expected).rgb());
3807         return actual == refImage;
3808     }
3809 }
3810
3811 void tst_QPainter::extendedBlendModes()
3812 {
3813     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Plus));
3814     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Plus));
3815     QVERIFY(testCompositionMode(127, 128, 255, QPainter::CompositionMode_Plus));
3816     QVERIFY(testCompositionMode(127,   0, 127, QPainter::CompositionMode_Plus));
3817     QVERIFY(testCompositionMode(  0, 127, 127, QPainter::CompositionMode_Plus));
3818     QVERIFY(testCompositionMode(255,   0, 255, QPainter::CompositionMode_Plus));
3819     QVERIFY(testCompositionMode(  0, 255, 255, QPainter::CompositionMode_Plus));
3820     QVERIFY(testCompositionMode(128, 128, 255, QPainter::CompositionMode_Plus));
3821
3822     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Plus, 0.3));
3823     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Plus, 0.3));
3824     QVERIFY(testCompositionMode(127, 128, 165, QPainter::CompositionMode_Plus, 0.3));
3825     QVERIFY(testCompositionMode(127,   0,  37, QPainter::CompositionMode_Plus, 0.3));
3826     QVERIFY(testCompositionMode(  0, 127, 127, QPainter::CompositionMode_Plus, 0.3));
3827     QVERIFY(testCompositionMode(255,   0,  75, QPainter::CompositionMode_Plus, 0.3));
3828     QVERIFY(testCompositionMode(  0, 255, 255, QPainter::CompositionMode_Plus, 0.3));
3829     QVERIFY(testCompositionMode(128, 128, 166, QPainter::CompositionMode_Plus, 0.3));
3830     QVERIFY(testCompositionMode(186, 200, 255, QPainter::CompositionMode_Plus, 0.3));
3831
3832     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Multiply));
3833     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Multiply));
3834     QVERIFY(testCompositionMode(127, 255, 127, QPainter::CompositionMode_Multiply));
3835     QVERIFY(testCompositionMode(255, 127, 127, QPainter::CompositionMode_Multiply));
3836     QVERIFY(testCompositionMode( 63, 255,  63, QPainter::CompositionMode_Multiply));
3837     QVERIFY(testCompositionMode(255,  63,  63, QPainter::CompositionMode_Multiply));
3838     QVERIFY(testCompositionMode(127, 127,  63, QPainter::CompositionMode_Multiply));
3839
3840     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Screen));
3841     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Screen));
3842     QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Screen));
3843     QVERIFY(testCompositionMode(255,  63, 255, QPainter::CompositionMode_Screen));
3844     QVERIFY(testCompositionMode( 63,   0,  63, QPainter::CompositionMode_Screen));
3845     QVERIFY(testCompositionMode(  0,  63,  63, QPainter::CompositionMode_Screen));
3846     QVERIFY(testCompositionMode(127, 127, 191, QPainter::CompositionMode_Screen));
3847
3848     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Overlay));
3849     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Overlay));
3850     QVERIFY(testCompositionMode( 63,  63,  31, QPainter::CompositionMode_Overlay));
3851     QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Overlay));
3852
3853     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Darken));
3854     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Darken));
3855     QVERIFY(testCompositionMode( 63,  63,  63, QPainter::CompositionMode_Darken));
3856     QVERIFY(testCompositionMode( 63, 255,  63, QPainter::CompositionMode_Darken));
3857     QVERIFY(testCompositionMode(255,  63,  63, QPainter::CompositionMode_Darken));
3858     QVERIFY(testCompositionMode( 63, 127,  63, QPainter::CompositionMode_Darken));
3859     QVERIFY(testCompositionMode(127,  63,  63, QPainter::CompositionMode_Darken));
3860
3861     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Lighten));
3862     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Lighten));
3863     QVERIFY(testCompositionMode( 63,  63,  63, QPainter::CompositionMode_Lighten));
3864     QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Lighten));
3865     QVERIFY(testCompositionMode(255,  63, 255, QPainter::CompositionMode_Lighten));
3866     QVERIFY(testCompositionMode( 63, 127, 127, QPainter::CompositionMode_Lighten));
3867     QVERIFY(testCompositionMode(127,  63, 127, QPainter::CompositionMode_Lighten));
3868
3869     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_ColorDodge));
3870     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_ColorDodge));
3871     QVERIFY(testCompositionMode( 63, 127, 169, QPainter::CompositionMode_ColorDodge));
3872     QVERIFY(testCompositionMode(191, 127, 255, QPainter::CompositionMode_ColorDodge));
3873     QVERIFY(testCompositionMode(127, 191, 255, QPainter::CompositionMode_ColorDodge));
3874
3875     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_ColorBurn));
3876     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_ColorBurn));
3877     QVERIFY(testCompositionMode(127, 127,   0, QPainter::CompositionMode_ColorBurn));
3878     QVERIFY(testCompositionMode(128, 128,   2, QPainter::CompositionMode_ColorBurn));
3879     QVERIFY(testCompositionMode(191, 127,  84, QPainter::CompositionMode_ColorBurn));
3880
3881     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_HardLight));
3882     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_HardLight));
3883     QVERIFY(testCompositionMode(127, 127, 127, QPainter::CompositionMode_HardLight));
3884     QVERIFY(testCompositionMode( 63,  63,  31, QPainter::CompositionMode_HardLight));
3885     QVERIFY(testCompositionMode(127,  63,  63, QPainter::CompositionMode_HardLight));
3886
3887     QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_SoftLight));
3888     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_SoftLight));
3889     QVERIFY(testCompositionMode(127, 127, 126, QPainter::CompositionMode_SoftLight));
3890     QVERIFY(testCompositionMode( 63,  63,  39, QPainter::CompositionMode_SoftLight));
3891     QVERIFY(testCompositionMode(127,  63,  62, QPainter::CompositionMode_SoftLight));
3892
3893     QVERIFY(testCompositionMode(255, 255,   0, QPainter::CompositionMode_Difference));
3894     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Difference));
3895     QVERIFY(testCompositionMode(255,   0, 255, QPainter::CompositionMode_Difference));
3896     QVERIFY(testCompositionMode(127, 127,   0, QPainter::CompositionMode_Difference));
3897     QVERIFY(testCompositionMode(127, 128,   1, QPainter::CompositionMode_Difference));
3898     QVERIFY(testCompositionMode(127,  63,  64, QPainter::CompositionMode_Difference));
3899     QVERIFY(testCompositionMode(  0, 127, 127, QPainter::CompositionMode_Difference));
3900
3901     QVERIFY(testCompositionMode(255, 255,   0, QPainter::CompositionMode_Exclusion));
3902     QVERIFY(testCompositionMode(  0,   0,   0, QPainter::CompositionMode_Exclusion));
3903     QVERIFY(testCompositionMode(255,   0, 255, QPainter::CompositionMode_Exclusion));
3904     QVERIFY(testCompositionMode(127, 127, 127, QPainter::CompositionMode_Exclusion));
3905     QVERIFY(testCompositionMode( 63, 127, 127, QPainter::CompositionMode_Exclusion));
3906     QVERIFY(testCompositionMode( 63,  63,  95, QPainter::CompositionMode_Exclusion));
3907     QVERIFY(testCompositionMode(191, 191,  96, QPainter::CompositionMode_Exclusion));
3908 }
3909
3910 void tst_QPainter::zeroOpacity()
3911 {
3912     QImage source(1, 1, QImage::Format_ARGB32_Premultiplied);
3913     source.fill(0xffffffff);
3914
3915     QImage target(1, 1, QImage::Format_RGB32);
3916     target.fill(0xff000000);
3917
3918     QPainter p(&target);
3919     p.setOpacity(0.0);
3920     p.drawImage(0, 0, source);
3921     p.end();
3922
3923     QCOMPARE(target.pixel(0, 0), 0xff000000);
3924 }
3925
3926 void tst_QPainter::clippingBug()
3927 {
3928     QImage img(32, 32, QImage::Format_ARGB32_Premultiplied);
3929     img.fill(0);
3930
3931     QImage expected = img;
3932     QPainter p(&expected);
3933     p.fillRect(1, 1, 30, 30, Qt::red);
3934     p.end();
3935
3936     QPainterPath path;
3937     path.addRect(1, 1, 30, 30);
3938     path.addRect(1, 1, 30, 30);
3939     path.addRect(1, 1, 30, 30);
3940
3941     p.begin(&img);
3942     p.setClipPath(path);
3943     p.fillRect(0, 0, 32, 32, Qt::red);
3944     p.end();
3945
3946     QCOMPARE(img, expected);
3947 }
3948
3949 void tst_QPainter::emptyClip()
3950 {
3951     QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3952     QPainter p(&img);
3953     p.setRenderHints(QPainter::Antialiasing);
3954     p.setClipRect(0, 32, 64, 0);
3955     p.fillRect(0, 0, 64, 64, Qt::white);
3956
3957     QPainterPath path;
3958     path.lineTo(64, 0);
3959     path.lineTo(64, 64);
3960     path.lineTo(40, 64);
3961     path.lineTo(40, 80);
3962     path.lineTo(0, 80);
3963
3964     p.fillPath(path, Qt::green);
3965 }
3966
3967 void tst_QPainter::drawImage_1x1()
3968 {
3969     QImage source(1, 1, QImage::Format_ARGB32_Premultiplied);
3970     source.fill(0xffffffff);
3971
3972     QImage img(32, 32, QImage::Format_ARGB32_Premultiplied);
3973     img.fill(0xff000000);
3974     QPainter p(&img);
3975     p.drawImage(QRectF(0.9, 0.9, 32, 32), source);
3976     p.end();
3977
3978     QImage expected = img;
3979     expected.fill(0xff000000);
3980     p.begin(&expected);
3981     p.fillRect(1, 1, 31, 31, Qt::white);
3982     p.end();
3983
3984     QCOMPARE(img, expected);
3985 }
3986
3987 void tst_QPainter::taskQT4444_dontOverflowDashOffset()
3988 {
3989     QPainter p;
3990
3991     QPen pen;
3992     pen.setWidth(2);
3993     pen.setStyle(Qt::DashDotLine);
3994
3995     QPointF point[4];
3996     point[0] = QPointF(182.50868749707968,347.78457234212630);
3997     point[1] = QPointF(182.50868749707968,107.22501998401277);
3998     point[2] = QPointF(182.50868749707968,107.22501998401277);
3999     point[3] = QPointF(520.46600762283651,107.22501998401277);
4000
4001     QImage crashImage(QSize(1000, 120), QImage::Format_ARGB32_Premultiplied);
4002     p.begin(&crashImage);
4003     p.setPen(pen);
4004     p.drawLines(point, 2);
4005     p.end();
4006
4007     QVERIFY(true); // Don't crash
4008 }
4009
4010 void tst_QPainter::painterBegin()
4011 {
4012     QImage nullImage;
4013     QImage indexed8Image(16, 16, QImage::Format_Indexed8);
4014     QImage rgb32Image(16, 16, QImage::Format_RGB32);
4015     QImage argb32Image(16, 16, QImage::Format_ARGB32_Premultiplied);
4016
4017     QPainter p;
4018
4019     // Painting on null image should fail.
4020     QVERIFY(!p.begin(&nullImage));
4021
4022     // Check that the painter is not messed up by using it on another image.
4023     QVERIFY(p.begin(&rgb32Image));
4024     QVERIFY(p.end());
4025
4026     // If painting on indexed8 image fails, the painter state should still be OK.
4027     if (p.begin(&indexed8Image))
4028         QVERIFY(p.end());
4029     QVERIFY(p.begin(&rgb32Image));
4030     QVERIFY(p.end());
4031
4032     // Try opening a painter on the two different images.
4033     QVERIFY(p.begin(&rgb32Image));
4034     QVERIFY(!p.begin(&argb32Image));
4035     QVERIFY(p.end());
4036
4037     // Try opening two painters on the same image.
4038     QVERIFY(p.begin(&rgb32Image));
4039     QPainter q;
4040     QVERIFY(!q.begin(&rgb32Image));
4041     QVERIFY(!q.end());
4042     QVERIFY(p.end());
4043
4044     // Try ending an inactive painter.
4045     QVERIFY(!p.end());
4046 }
4047
4048 void tst_QPainter::setPenColor(QPainter& p)
4049 {
4050     p.setPen(Qt::NoPen);
4051
4052     // Setting color, then style
4053     // Should work even though the pen is "NoPen with color", temporarily.
4054     QPen newPen(p.pen());
4055     newPen.setColor(Qt::red);
4056     QCOMPARE(p.pen().style(), newPen.style());
4057     QCOMPARE(p.pen().style(), Qt::NoPen);
4058     p.setPen(newPen);
4059
4060     QCOMPARE(p.pen().color().name(), QString("#ff0000"));
4061
4062     QPen newPen2(p.pen());
4063     newPen2.setStyle(Qt::SolidLine);
4064     p.setPen(newPen2);
4065
4066     QCOMPARE(p.pen().color().name(), QString("#ff0000"));
4067 }
4068
4069 void tst_QPainter::setPenColorOnImage()
4070 {
4071     QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
4072     QPainter p(&img);
4073     setPenColor(p);
4074 }
4075
4076 void tst_QPainter::setPenColorOnPixmap()
4077 {
4078     QPixmap pix(10, 10);
4079     QPainter p(&pix);
4080     setPenColor(p);
4081 }
4082
4083 #ifndef QT_NO_WIDGETS
4084 class TestProxy : public QGraphicsProxyWidget
4085 {
4086 public:
4087     TestProxy() : QGraphicsProxyWidget() {}
4088     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
4089     {
4090         QGraphicsProxyWidget::paint(painter, option, widget);
4091         deviceTransform = painter->deviceTransform();
4092     }
4093     QTransform deviceTransform;
4094 };
4095
4096 class TestWidget : public QWidget
4097 {
4098 Q_OBJECT
4099 public:
4100     TestWidget() : QWidget(), painted(false) {}
4101     void paintEvent(QPaintEvent *)
4102     {
4103         QPainter p(this);
4104         deviceTransform = p.deviceTransform();
4105         worldTransform = p.worldTransform();
4106         painted = true;
4107     }
4108     QTransform deviceTransform;
4109     QTransform worldTransform;
4110     bool painted;
4111 };
4112
4113 void tst_QPainter::QTBUG5939_attachPainterPrivate()
4114 {
4115     QWidget *w = new QWidget();
4116     QGraphicsScene *scene = new QGraphicsScene();
4117     QGraphicsView *view = new QGraphicsView(scene, w);
4118     view->move(50 ,50);
4119     TestProxy *proxy = new TestProxy();
4120     TestWidget *widget = new TestWidget();
4121     proxy->setWidget(widget);
4122     scene->addItem(proxy);
4123     proxy->rotate(45);
4124     w->resize(scene->sceneRect().size().toSize());
4125
4126     w->show();
4127     QTRY_VERIFY(widget->painted);
4128
4129     QVERIFY(widget->worldTransform.isIdentity());
4130     QCOMPARE(widget->deviceTransform, proxy->deviceTransform);
4131 }
4132 #endif
4133
4134 void tst_QPainter::clipBoundingRect()
4135 {
4136     QPixmap pix(500, 500);
4137
4138     QPainter p(&pix);
4139
4140     // Test a basic rectangle
4141     p.setClipRect(100, 100, 200, 100);
4142     QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4143     QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4144     p.setClipRect(120, 120, 20, 20, Qt::IntersectClip);
4145     QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4146     QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4147
4148     // Test a basic float rectangle
4149     p.setClipRect(QRectF(100, 100, 200, 100));
4150     QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4151     QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4152     p.setClipRect(QRectF(120, 120, 20, 20), Qt::IntersectClip);
4153     QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4154     QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4155
4156     // Test a basic path + region
4157     QPainterPath path;
4158     path.addRect(100, 100, 200, 100);
4159     p.setClipPath(path);
4160     QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4161     QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4162     p.setClipRegion(QRegion(120, 120, 20, 20), Qt::IntersectClip);
4163     QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4164     QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4165
4166     p.setClipRect(0, 0, 500, 500);
4167     p.translate(250, 250);
4168     for (int i=0; i<360; ++i) {
4169         p.rotate(1);
4170         p.setClipRect(-100, -100, 200, 200, Qt::IntersectClip);
4171     }
4172     QVERIFY(p.clipBoundingRect().contains(QRectF(-100, -100, 200, 200)));
4173     QVERIFY(!p.clipBoundingRect().contains(QRectF(-250, -250, 500, 500)));
4174
4175 }
4176
4177 void tst_QPainter::drawText_subPixelPositionsInRaster_qtbug5053()
4178 {
4179 #if !defined(Q_OS_MAC)
4180     QSKIP("Only Mac supports sub pixel positions in raster engine currently");
4181 #endif
4182     QFontMetricsF fm(qApp->font());
4183
4184     QImage baseLine(fm.width(QChar::fromLatin1('e')), fm.height(), QImage::Format_RGB32);
4185     baseLine.fill(Qt::white);
4186     {
4187         QPainter p(&baseLine);
4188         p.drawText(0, fm.ascent(), QString::fromLatin1("e"));
4189     }
4190
4191     bool foundDifferentRasterization = false;
4192     for (int i=1; i<12; ++i) {
4193         QImage comparison(baseLine.size(), QImage::Format_RGB32);
4194         comparison.fill(Qt::white);
4195
4196         {
4197             QPainter p(&comparison);
4198             p.drawText(QPointF(i / 12.0, fm.ascent()), QString::fromLatin1("e"));
4199         }
4200
4201         if (comparison != baseLine) {
4202             foundDifferentRasterization = true;
4203             break;
4204         }
4205     }
4206
4207     QVERIFY(foundDifferentRasterization);
4208 }
4209
4210 void tst_QPainter::drawPointScaled()
4211 {
4212     QImage image(32, 32, QImage::Format_RGB32);
4213     image.fill(0xffffffff);
4214
4215     QPainter p(&image);
4216
4217     p.scale(0.1, 0.1);
4218
4219     QPen pen;
4220     pen.setWidth(1000);
4221     pen.setColor(Qt::red);
4222
4223     p.setPen(pen);
4224     p.drawPoint(0, 0);
4225     p.end();
4226
4227     QCOMPARE(image.pixel(16, 16), 0xffff0000);
4228 }
4229
4230 class GradientProducer : public QThread
4231 {
4232 protected:
4233     void run();
4234 };
4235
4236 void GradientProducer::run()
4237 {
4238     QImage image(1, 1, QImage::Format_RGB32);
4239     QPainter p(&image);
4240
4241     for (int i = 0; i < 1000; ++i) {
4242         QLinearGradient g;
4243         g.setColorAt(0, QColor(i % 256, 0, 0));
4244         g.setColorAt(1, Qt::white);
4245
4246         p.fillRect(image.rect(), g);
4247     }
4248 }
4249
4250 void tst_QPainter::QTBUG14614_gradientCacheRaceCondition()
4251 {
4252     const int threadCount = 16;
4253     GradientProducer producers[threadCount];
4254     for (int i = 0; i < threadCount; ++i)
4255         producers[i].start();
4256     for (int i = 0; i < threadCount; ++i)
4257         producers[i].wait();
4258 }
4259
4260 void tst_QPainter::drawTextOpacity()
4261 {
4262     QImage image(32, 32, QImage::Format_RGB32);
4263     image.fill(0xffffffff);
4264
4265     QPainter p(&image);
4266     p.setPen(QColor("#6F6F6F"));
4267     p.setOpacity(0.5);
4268     p.drawText(5, 30, QLatin1String("Qt"));
4269     p.end();
4270
4271     QImage copy = image;
4272     image.fill(0xffffffff);
4273
4274     p.begin(&image);
4275     p.setPen(QColor("#6F6F6F"));
4276     p.drawLine(-10, -10, -1, -1);
4277     p.setOpacity(0.5);
4278     p.drawText(5, 30, QLatin1String("Qt"));
4279     p.end();
4280
4281     QCOMPARE(image, copy);
4282 }
4283
4284 void tst_QPainter::QTBUG17053_zeroDashPattern()
4285 {
4286     QImage image(32, 32, QImage::Format_RGB32);
4287     image.fill(0xffffffff);
4288
4289     QImage original = image;
4290
4291     QVector<qreal> pattern;
4292     pattern << qreal(0) << qreal(0);
4293
4294     QPainter p(&image);
4295     QPen pen(Qt::black, 2.0);
4296     pen.setDashPattern(pattern);
4297
4298     p.setPen(pen);
4299     p.drawLine(0, 0, image.width(), image.height());
4300
4301     QCOMPARE(image, original);
4302 }
4303
4304 class TextDrawerThread : public QThread
4305 {
4306 public:
4307     void run();
4308     QImage rendering;
4309 };
4310
4311 void TextDrawerThread::run()
4312 {
4313     rendering = QImage(100, 100, QImage::Format_ARGB32_Premultiplied);
4314     rendering.fill(0);
4315     QPainter p(&rendering);
4316     p.fillRect(10, 10, 100, 100, Qt::blue);
4317     p.setPen(Qt::green);
4318     p.drawText(20, 20, "some text");
4319     p.end();
4320 }
4321
4322 void tst_QPainter::drawTextOutsideGuiThread()
4323 {
4324     if (!QFontDatabase::supportsThreadedFontRendering())
4325         QSKIP("No threaded font rendering");
4326
4327     QImage referenceRendering(100, 100, QImage::Format_ARGB32_Premultiplied);
4328     referenceRendering.fill(0);
4329     QPainter p(&referenceRendering);
4330     p.fillRect(10, 10, 100, 100, Qt::blue);
4331     p.setPen(Qt::green);
4332     p.drawText(20, 20, "some text");
4333     p.end();
4334
4335     TextDrawerThread t;
4336     t.start();
4337     t.wait();
4338
4339     QCOMPARE(referenceRendering, t.rendering);
4340 }
4341
4342 void tst_QPainter::drawTextWithComplexBrush()
4343 {
4344     QImage texture(10, 10, QImage::Format_ARGB32_Premultiplied);
4345     texture.fill(Qt::red);
4346
4347     QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
4348     image.fill(Qt::white);
4349     QPainter p(&image);
4350     QFont f = p.font();
4351     f.setPixelSize(70);
4352     p.setFont(f);
4353
4354     QBrush brush(Qt::white);
4355     brush.setTextureImage(texture);
4356     p.setPen(QPen(brush, 2));
4357
4358     p.drawText(10, 10, "Hello World");
4359
4360     int paintedPixels = getPaintedPixels(image, Qt::white);
4361     QVERIFY(paintedPixels > 0);
4362 }
4363
4364 void tst_QPainter::QTBUG26013_squareCapStroke()
4365 {
4366     QImage image(4, 4, QImage::Format_RGB32);
4367
4368     QPainter p(&image);
4369     p.setPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap));
4370
4371     for (int i = 0; i < 3; ++i) {
4372         qreal d = i / 3.0;
4373
4374         image.fill(0xffffffff);
4375
4376         p.drawLine(QLineF(0, d, 0, d + 2));
4377         p.drawLine(QLineF(1, d, 3, d));
4378
4379         // ensure that a horizontal line and a vertical line with square cap round up (downwards) at the same time
4380         QCOMPARE(image.pixel(0, 0), image.pixel(1, 0));
4381
4382         image.fill(0xffffffff);
4383
4384         p.drawLine(QLineF(d, 0, d + 2, 0));
4385         p.drawLine(QLineF(d, 1, d, 3));
4386
4387         // ensure that a vertical line and a horizontal line with square cap round up (to the right) at the same time
4388         QCOMPARE(image.pixel(0, 0), image.pixel(0, 1));
4389     }
4390 }
4391
4392 void tst_QPainter::QTBUG25153_drawLine()
4393 {
4394     QImage image(2, 2, QImage::Format_RGB32);
4395
4396     QVector<Qt::PenCapStyle> styles;
4397     styles << Qt::FlatCap << Qt::SquareCap << Qt::RoundCap;
4398
4399     foreach (Qt::PenCapStyle style, styles) {
4400         image.fill(0xffffffff);
4401         QPainter p(&image);
4402         p.setPen(QPen(Qt::black, 0, Qt::SolidLine, style));
4403         p.drawLine(QLineF(0, 0, 0, 0));
4404         p.end();
4405
4406         QCOMPARE(image.pixel(0, 0), 0xff000000);
4407         QCOMPARE(image.pixel(0, 1), 0xffffffff);
4408         QCOMPARE(image.pixel(1, 0), 0xffffffff);
4409     }
4410 }
4411
4412 QTEST_MAIN(tst_QPainter)
4413
4414 #include "tst_qpainter.moc"