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