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