1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
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
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
44 #include "../../shared/util.h"
47 #include <qapplication.h>
49 #include <qfontmetrics.h>
54 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
58 #include <q3painter.h>
61 #include <qpaintengine.h>
62 #include <qdesktopwidget.h>
71 #include <qgraphicsview.h>
72 #include <qgraphicsscene.h>
73 #include <qgraphicsproxywidget.h>
76 #if defined(Q_OS_SYMBIAN)
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)
90 class tst_QPainter : public QObject
96 virtual ~tst_QPainter();
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();
111 void drawBorderPixmap();
112 void drawPixmapFragments();
114 void drawLine_data();
116 void drawLine_clipped();
117 void drawLine_task121143();
118 void drawLine_task216948();
120 void drawLine_task190634();
121 void drawLine_task229459();
122 void drawLine_task234891();
124 void drawRect_data() { fillData(); }
133 void drawEllipse_data();
135 void drawClippedEllipse_data();
136 void drawClippedEllipse();
138 void drawPath_data();
143 void drawRoundRect_data() { fillData(); }
144 void drawRoundRect();
146 void qimageFormats_data();
147 void qimageFormats();
148 void textOnTransparentImage();
154 void combinedMatrix();
157 void disableEnableClipping();
159 void setEqualClipRegionAndPath_data();
160 void setEqualClipRegionAndPath();
162 void clipRectSaveRestore();
164 void clippedFillPath_data();
165 void clippedFillPath();
166 void clippedLines_data();
168 void clippedPolygon_data();
169 void clippedPolygon();
173 void clipBoundingRect();
175 void setOpacity_data();
178 void drawhelper_blend_untransformed_data();
179 void drawhelper_blend_untransformed();
180 void drawhelper_blend_tiled_untransformed_data();
181 void drawhelper_blend_tiled_untransformed();
183 void porterDuff_warning();
185 void drawhelper_blend_color();
187 void childWidgetViewport();
189 void fillRect_objectBoundingModeGradient();
190 void fillRect_stretchToDeviceMode();
193 void linearGradientSymmetry_data();
194 void linearGradientSymmetry();
195 void gradientInterpolation();
197 void fpe_pixmapTransform();
198 void fpe_zeroLengthLines();
199 void fpe_divByZero();
201 void fpe_steepSlopes_data();
202 void fpe_steepSlopes();
203 void fpe_rasterizeLine_task232012();
205 void fpe_radialGradients();
207 void rasterizer_asserts();
208 void rasterizer_negativeCoords();
210 void blendOverFlow_data();
211 void blendOverFlow();
213 void largeImagePainting_data();
214 void largeImagePainting();
216 void imageScaling_task206785();
218 void outlineFillConsistency();
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();
227 void drawText_subPixelPositionsInRaster_qtbug5053();
229 void drawImage_data();
234 void stateResetBetweenQPainters();
236 void imageCoordinateLimit();
237 void imageBlending_data();
238 void imageBlending();
239 void imageBlending_clipped();
241 void paintOnNullPixmap();
242 void checkCompositionMode();
246 void inactivePainter();
248 void extendedBlendModes();
254 void taskQT4444_dontOverflowDashOffset();
257 void setPenColorOnImage();
258 void setPenColorOnPixmap();
260 void QTBUG5939_attachPainterPrivate();
262 void drawPointScaled();
264 void QTBUG14614_gradientCacheRaceCondition();
265 void drawTextOpacity();
267 void QTBUG17053_zeroDashPattern();
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 );
277 // Testing get/set functions
278 void tst_QPainter::getSetCheck()
280 QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
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());
310 // const QPen & QPainter::pen()
311 // void QPainter::setPen(const QPen &)
314 QCOMPARE(var3, obj1.pen());
316 QCOMPARE(QPen(), obj1.pen());
318 // const QBrush & QPainter::brush()
319 // void QPainter::setBrush(const QBrush &)
320 QBrush var4(Qt::red);
322 QCOMPARE(var4, obj1.brush());
323 obj1.setBrush(QBrush());
324 QCOMPARE(QBrush(), obj1.brush());
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());
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());
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());
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)
357 tst_QPainter::tst_QPainter()
359 // QtTestCase sets this to false, but this turns off alpha pixmaps on Unix.
360 QApplication::setDesktopSettingsAware(TRUE);
363 tst_QPainter::~tst_QPainter()
367 void tst_QPainter::init()
371 void tst_QPainter::cleanup()
375 /* tests the clipping operations in qt_format_text, making sure
376 the clip rectangle after the call is the same as before
378 void tst_QPainter::qt_format_text_clip()
381 QSKIP( "Needs fixing...", SkipAll);
383 QWidget *w = new QWidget( 0 );
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,
396 QRegion clipreg = p.clipRegion();
397 bool hasClipping = p.hasClipping();
398 qreal tx = p.matrix().dx();
399 qreal ty = p.matrix().dy();
401 p.drawText( 10, 10, 100, 100, *m,
404 QVERIFY( clipreg == p.clipRegion() );
405 QVERIFY( hasClipping == p.hasClipping() );
406 QCOMPARE( tx, p.matrix().dx() );
407 QCOMPARE( ty, p.matrix().dy() );
409 p.setClipRect( QRect( 5, 5, 50, 50 ) );
410 clipreg = p.clipRegion();
411 hasClipping = p.hasClipping();
413 p.drawText( 10, 10, 100, 100, *m,
416 QVERIFY( clipreg == p.clipRegion() );
417 QVERIFY( hasClipping == p.hasClipping() );
418 QCOMPARE( tx, p.matrix().dx() );
419 QCOMPARE( ty, p.matrix().dy() );
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();
429 p.drawText( 10, 10, 100, 100, *m,
432 QVERIFY( clipreg == p.clipRegion() );
433 QVERIFY( hasClipping == p.hasClipping() );
434 QCOMPARE( tx, p.matrix().dx() );
435 QCOMPARE( ty, p.matrix().dy() );
437 p.setClipRect( QRect( 5, 5, 50, 50 ) );
438 clipreg = p.clipRegion();
439 hasClipping = p.hasClipping();
441 p.drawText( 10, 10, 100, 100, *m,
444 QVERIFY( clipreg == p.clipRegion() );
445 QVERIFY( hasClipping == p.hasClipping() );
446 QCOMPARE( tx, p.matrix().dx() );
447 QCOMPARE( ty, p.matrix().dy() );
451 QRegion clipreg = p.clipRegion();
452 bool hasClipping = p.hasClipping();
453 qreal tx = p.matrix().dx();
454 qreal ty = p.matrix().dy();
456 p.drawText( 10, 10, 100, 100, *m,
459 QVERIFY( clipreg == p.clipRegion() );
460 QVERIFY( hasClipping == p.hasClipping() );
461 QCOMPARE( tx, p.matrix().dx() );
462 QCOMPARE( ty, p.matrix().dy() );
464 p.setClipRect( QRect( 5, 5, 50, 50 ));
465 clipreg = p.clipRegion();
466 hasClipping = p.hasClipping();
468 p.drawText( 10, 10, 100, 100, *m,
471 QVERIFY( clipreg == p.clipRegion() );
472 QVERIFY( hasClipping == p.hasClipping() );
473 QCOMPARE( tx, p.matrix().dx() );
474 QCOMPARE( ty, p.matrix().dy() );
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();
484 p.drawText( 10, 10, 100, 100, *m,
487 QVERIFY( clipreg == p.clipRegion() );
488 QVERIFY( hasClipping == p.hasClipping() );
489 QCOMPARE( tx, p.matrix().dx() );
490 QCOMPARE( ty, p.matrix().dy() );
492 p.setClipRect(QRect( 5, 5, 50, 50 ));
493 clipreg = p.clipRegion();
494 hasClipping = p.hasClipping();
496 p.drawText( 10, 10, 100, 100, *m,
499 QVERIFY( clipreg == p.clipRegion() );
500 QVERIFY( hasClipping == p.hasClipping() );
501 QCOMPARE( tx, p.matrix().dx() );
502 QCOMPARE( ty, p.matrix().dy() );
509 /* tests the bounding rect calculations in qt_format_text, making sure
510 the bounding rect has a reasonable value.
512 void tst_QPainter::qt_format_text_boundingRect()
515 QSKIP( "Needs fixing...", SkipAll);
518 const char * strings[] = {
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",
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",
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,
545 for(int i = 5; i < 15; ++i) {
548 const char **str = strings;
552 QRect br = fm.boundingRect( 0, 0, 2000, 100, *m, QString::fromUtf8( *str ) );
553 QVERIFY( br.width() < 800 );
555 QRect br2 = fm.boundingRect( br.x(), br.y(), br.width(), br.height(), *m, QString::fromUtf8( *str ) );
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 ) );
567 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
569 QPrinter printer(QPrinter::HighResolution);
570 if (printer.printerName().isEmpty()) {
571 QSKIP( "No printers installed, skipping bounding rect test",
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());
591 const char * strings[] = {
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",
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",
613 int modes[] = { Qt::AlignVCenter,
622 for(int i = 5; i < 15; ++i) {
625 const char **str = strings;
629 QString s = QString::fromUtf8(*str);
630 QRect br = fm.boundingRect(0, 0, 1000, 1000, *m, s );
633 int expectedHeight = fm.height()+lines*fm.lineSpacing();
634 QCOMPARE(br.height(), expectedHeight);
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());
647 static const char* const maskSource_data[] = {
669 static const char* const maskResult_data[] = {
692 void tst_QPainter::drawPixmap_comp_data()
694 if (qApp->desktop()->depth() < 24) {
695 QSKIP("Test only works on 32 bit displays", SkipAll);
699 QTest::addColumn<uint>("dest");
700 QTest::addColumn<uint>("source");
702 QTest::newRow("0% on 0%, 1") << 0x00000000u<< 0x00000000u;
703 QTest::newRow("0% on 0%, 2") << 0x00007fffu << 0x00ff007fu;
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;
718 QRgb qt_compose_alpha(QRgb source, QRgb dest)
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);
723 int alpha = qMin(a2 + ((255 - a2) * a1 + 127) / 255, 255);
725 return qRgba(0, 0, 0, 0);
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),
734 /* Tests that drawing masked pixmaps works
736 void tst_QPainter::drawPixmap_comp()
739 QSKIP("Mac has other ideas about alpha composition", SkipAll);
743 QFETCH(uint, source);
745 QRgb expected = qt_compose_alpha(source, dest);
747 QColor c1(qRed(dest), qGreen(dest), qBlue(dest), qAlpha(dest));
748 QColor c2(qRed(source), qGreen(source), qBlue(source), qAlpha(source));
750 QPixmap destPm(10, 10), srcPm(10, 10);
754 #if defined(Q_WS_X11)
755 if (!destPm.x11PictureHandle())
756 QSKIP("Requires XRender support", SkipAll);
760 p.drawPixmap(0, 0, srcPm);
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) {
768 if (qAlpha(expected) == 0) {
769 diff = qAlpha(result.pixel(x, y)) != 0;
771 // Compensate for possible roundoff / platform fudge
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);
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));
790 void tst_QPainter::saveAndRestore_data()
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");
804 QPixmap pixmap(1, 1);
806 QFont font = p.font();
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();
816 QTest::newRow("Original") << font << pen << brush << backgroundColor << int(backgroundMode)
817 << brushOrigin << clipRegion << window << viewport;
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;
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;
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 );
837 void tst_QPainter::saveAndRestore()
839 QFETCH( QFont, font );
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 );
849 QPixmap pixmap(1, 1);
850 QPainter painter(&pixmap);
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();
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 );
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 );
891 QColor tst_QPainter::baseColor( int k, int intensity )
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 );
899 QImage tst_QPainter::getResImage( const QString &dir, const QString &addition, const QString &extension )
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());
910 QBitmap tst_QPainter::getBitmap( const QString &dir, const QString &filename, bool mask )
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());
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());
930 static int getPaintedPixels(const QImage &image, const QColor &background)
932 uint color = background.rgba();
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)
944 static QRect getPaintedSize(const QImage &image, const QColor &background)
946 // not the fastest but at least it works..
947 int xmin = image.width() + 1;
949 int ymin = image.height() +1;
952 uint color = background.rgba();
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 )
959 if ( pixel != color && x > xmax )
961 if ( pixel != color && y < ymin )
963 if ( pixel != color && y > ymax )
968 return QRect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
971 static QRect getPaintedSize(const QPixmap &pm, const QColor &background)
973 return getPaintedSize(pm.toImage(), background);
976 void tst_QPainter::initFrom()
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);
984 QFont font = widget->font();
985 font.setPointSize(26);
986 font.setItalic(true);
987 widget->setFont(font);
989 QPixmap pm(100, 100);
993 QCOMPARE(p.font(), font);
994 QCOMPARE(p.pen().color(), pal.color(QPalette::Foreground));
995 QCOMPARE(p.background(), pal.background());
1000 void tst_QPainter::drawBorderPixmap()
1003 src.fill(Qt::transparent);
1005 QImage pm(200,200,QImage::Format_RGB32);
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);
1012 void tst_QPainter::drawPixmapFragments()
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} };
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);
1028 QPainter p(&resPixmap);
1029 p.drawPixmapFragments(fragments, 4, origPixmap);
1032 QImage origImage = origPixmap.toImage().convertToFormat(QImage::Format_ARGB32);
1033 QImage resImage = resPixmap.toImage().convertToFormat(QImage::Format_ARGB32);
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));
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);
1055 void tst_QPainter::drawLine_data()
1057 QTest::addColumn<QLine>("line");
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);
1069 void tst_QPainter::drawLine()
1071 const int offset = 5;
1072 const int epsilon = 1; // allow for one pixel difference
1074 QFETCH(QLine, line);
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()));
1082 pixmapUnclipped.fill(Qt::white);
1083 QPainter p(&pixmapUnclipped);
1084 p.translate(offset, offset);
1085 p.setPen(QPen(Qt::black));
1089 const QRect painted = getPaintedSize(pixmapUnclipped, Qt::white);
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);
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()));
1106 const QRect clip = QRect(line.p1(), line.p2()).normalized();
1108 pixmapClipped.fill(Qt::white);
1109 QPainter p(&pixmapClipped);
1110 p.translate(offset, offset);
1111 p.setClipRect(clip);
1112 p.setPen(QPen(Qt::black));
1117 const QImage unclipped = pixmapUnclipped.toImage();
1118 const QImage clipped = pixmapClipped.toImage();
1119 QCOMPARE(unclipped, clipped);
1122 void tst_QPainter::drawLine_clipped()
1124 QImage image(16, 1, QImage::Format_ARGB32_Premultiplied);
1128 p.setPen(QPen(Qt::black, 10));
1130 // this should fill the whole image
1131 p.drawLine(-1, -1, 17, 1);
1134 for (int x = 0; x < 16; ++x)
1135 QCOMPARE(image.pixel(x, 0), 0xff000000);
1138 void tst_QPainter::drawLine_task121143()
1140 QPen pen(Qt::black);
1142 QImage image(5, 5, QImage::Format_ARGB32_Premultiplied);
1143 image.fill(0xffffffff);
1146 p.drawLine(QLine(0, 0+4, 0+4, 0));
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());
1154 QCOMPARE(image, expected);
1157 void tst_QPainter::drawLine_task190634()
1159 QPen pen(Qt::black, 3);
1161 QImage image(32, 32, QImage::Format_ARGB32_Premultiplied);
1163 p.fillRect(0, 0, image.width(), image.height(), Qt::white);
1166 p.drawLine(QLineF(2, -1.6, 10, -1.6));
1169 const uint *data = reinterpret_cast<uint *>(image.bits());
1171 for (int i = 0; i < image.width() * image.height(); ++i)
1172 QCOMPARE(data[i], 0xffffffff);
1175 p.fillRect(0, 0, image.width(), image.height(), Qt::white);
1178 p.drawLine(QLineF(-1.6, 2, -1.6, 10));
1181 data = reinterpret_cast<uint *>(image.bits());
1183 for (int i = 0; i < image.width() * image.height(); ++i)
1184 QCOMPARE(data[i], 0xffffffff);
1187 p.fillRect(0, 0, image.width(), image.height(), Qt::white);
1190 p.drawLine( QPoint(2,-2), QPoint(3,-5) );
1193 data = reinterpret_cast<uint *>(image.bits());
1195 for (int i = 0; i < image.width() * image.height(); ++i)
1196 QCOMPARE(data[i], 0xffffffff);
1199 void tst_QPainter::drawLine_task229459()
1201 QImage image(32, 32, QImage::Format_ARGB32_Premultiplied);
1203 QPen pen(Qt::black, 64);
1207 p.drawLine(-8, -8, 10000000, 10000000);
1210 QImage expected = image;
1211 expected.fill(0xff000000);
1213 QCOMPARE(image, expected);
1216 void tst_QPainter::drawLine_task234891()
1218 QImage img(100, 1000, QImage::Format_ARGB32_Premultiplied);
1220 QImage expected = img;
1223 p.setPen(QPen(QBrush(QColor(255,0,0)), 6));
1224 p.drawLine(QPointF(25000,100),QPointF(30000,105));
1226 p.setPen(QPen(QBrush(QColor(0,255,0)), 6));
1227 p.drawLine(QPointF(30000,150),QPointF(35000,155));
1229 p.setPen(QPen(QBrush(QColor(0,0,255)), 6));
1230 p.drawLine(QPointF(65000,200),QPointF(66000,205));
1232 QCOMPARE(expected, img);
1235 void tst_QPainter::drawLine_task216948()
1237 QImage img(1, 10, QImage::Format_ARGB32_Premultiplied);
1241 QLine line(10, 0, 10, 10);
1242 p.translate(-10, 0);
1246 for (int i = 0; i < img.height(); ++i)
1247 QCOMPARE(img.pixel(0, i), QColor(Qt::black).rgba());
1250 void tst_QPainter::drawRect()
1252 QFETCH(QRect, rect);
1253 QFETCH(bool, usePen);
1255 QPixmap pixmap(rect.x() + rect.width() + 10,
1256 rect.y() + rect.height() + 10);
1258 pixmap.fill(Qt::white);
1259 QPainter p(&pixmap);
1260 p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1261 p.setBrush(Qt::black);
1265 int increment = usePen ? 1 : 0;
1267 const QRect painted = getPaintedSize(pixmap, Qt::white);
1268 QCOMPARE(painted.width(), rect.width() + increment);
1269 QCOMPARE(painted.height(), rect.height() + increment);
1274 if (usePen && (rect.width() < 2 || rect.height() < 2))
1276 pixmap.fill(Qt::white);
1277 Q3Painter p(&pixmap);
1278 p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1279 p.setBrush(Qt::black);
1283 const QRect painted = getPaintedSize(pixmap, Qt::white);
1285 QCOMPARE(painted.width(), rect.width());
1286 QCOMPARE(painted.height(), rect.height());
1291 void tst_QPainter::drawRect2()
1293 QImage image(64, 64, QImage::Format_ARGB32_Premultiplied);
1295 image.fill(0xffffffff);
1297 QTransform transform(0.368567, 0, 0, 0, 0.368567, 0, 0.0289, 0.0289, 1);
1300 p.setTransform(transform);
1301 p.setBrush(Qt::red);
1302 p.setPen(Qt::NoPen);
1303 p.drawRect(QRect(14, 14, 39, 39));
1306 QRect fill = getPaintedSize(image, Qt::white);
1307 image.fill(0xffffffff);
1310 p.setTransform(transform);
1311 p.drawRect(QRect(14, 14, 39, 39));
1314 QRect stroke = getPaintedSize(image, Qt::white);
1315 QCOMPARE(stroke, fill.adjusted(0, 0, 1, 1));
1319 void tst_QPainter::fillRect()
1321 QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
1322 image.fill(QColor(0, 0, 0, 0).rgba());
1326 p.fillRect(0, 0, 100, 100, QColor(255, 0, 0, 127));
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(),
1334 p.setCompositionMode(QPainter::CompositionMode_SourceIn);
1335 p.fillRect(50, 0, 50, 100, QColor(0, 0, 255, 255));
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));
1343 void tst_QPainter::fillRect2()
1345 QRgb background = 0x0;
1347 QImage img(1, 20, QImage::Format_ARGB32_Premultiplied);
1348 img.fill(background);
1352 QRectF rect(0, 1, 1.2, 18);
1353 p.fillRect(rect, Qt::black);
1357 QCOMPARE(img.pixel(0, 0), background);
1358 QCOMPARE(img.pixel(0, img.height() - 1), background);
1360 QCOMPARE(img.pixel(0, 1), img.pixel(0, 2));
1361 QCOMPARE(img.pixel(0, img.height() - 2), img.pixel(0, img.height() - 3));
1364 void tst_QPainter::fillRect3()
1366 QImage img(1, 1, QImage::Format_ARGB32_Premultiplied);
1367 img.fill(QColor(Qt::black).rgba());
1370 p.setCompositionMode(QPainter::CompositionMode_Source);
1371 p.fillRect(img.rect(), Qt::transparent);
1374 QCOMPARE(img.pixel(0, 0), 0U);
1377 void tst_QPainter::fillRect4()
1379 QImage image(100, 1, QImage::Format_ARGB32_Premultiplied);
1382 QImage expected = image;
1383 expected.fill(0xffffffff);
1387 p.setPen(Qt::NoPen);
1389 for (int i = 0; i < 33; ++i)
1390 p.fillRect(QRectF(3 * i, 0, 3, 1), Qt::white);
1394 QCOMPARE(image, expected);
1397 void tst_QPainter::drawPath_data()
1399 QTest::addColumn<QPainterPath>("path");
1400 QTest::addColumn<QRect>("expectedBounds");
1401 QTest::addColumn<int>("expectedPixels");
1405 p.addRect(2, 2, 10, 10);
1406 QTest::newRow("int-aligned rect") << p << QRect(2, 2, 10, 10) << 10 * 10;
1411 p.addRect(2.25, 2.25, 10, 10);
1412 QTest::newRow("non-aligned rect") << p << QRect(2, 2, 10, 10) << 10 * 10;
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;
1423 p.addRect(2.5, 2.5, 10, 10);
1424 QTest::newRow("non-aligned rect 3") << p << QRect(3, 3, 10, 10) << 10 * 10;
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;
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;
1443 void tst_QPainter::drawPath()
1445 QFETCH(QPainterPath, path);
1446 QFETCH(QRect, expectedBounds);
1447 QFETCH(int, expectedPixels);
1449 const int offset = 2;
1451 QImage image(expectedBounds.width() + 2 * offset, expectedBounds.height() + 2 * offset,
1452 QImage::Format_ARGB32_Premultiplied);
1453 image.fill(QColor(Qt::white).rgb());
1456 p.setPen(Qt::NoPen);
1457 p.setBrush(Qt::black);
1458 p.translate(offset - expectedBounds.left(), offset - expectedBounds.top());
1462 const QRect paintedBounds = getPaintedSize(image, Qt::white);
1464 QCOMPARE(paintedBounds.x(), offset);
1465 QCOMPARE(paintedBounds.y(), offset);
1466 QCOMPARE(paintedBounds.width(), expectedBounds.width());
1467 QCOMPARE(paintedBounds.height(), expectedBounds.height());
1469 if (expectedPixels != -1) {
1470 int paintedPixels = getPaintedPixels(image, Qt::white);
1471 QCOMPARE(paintedPixels, expectedPixels);
1475 void tst_QPainter::drawPath2()
1479 for (int h = 5; h < 200; ++h) {
1480 QPainterPath p1, p2;
1487 const int offset = 2;
1489 QImage image(w + 2 * offset, h + 2 * offset,
1490 QImage::Format_ARGB32_Premultiplied);
1491 image.fill(QColor(Qt::white).rgb());
1494 p.setPen(Qt::NoPen);
1495 p.setBrush(Qt::black);
1496 p.translate(offset, offset);
1500 const int p1Pixels = getPaintedPixels(image, Qt::white);
1502 image.fill(QColor(Qt::white).rgb());
1504 p.setPen(Qt::NoPen);
1505 p.setBrush(Qt::black);
1506 p.translate(offset, offset);
1510 const int p2Pixels = getPaintedPixels(image, Qt::white);
1512 QCOMPARE(p1Pixels + p2Pixels, w * h);
1516 void tst_QPainter::drawPath3()
1518 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
1519 QImage imgA(400, 400, QImage::Format_RGB32);
1521 QImage imgA(100, 100, QImage::Format_RGB32);
1523 imgA.fill(0xffffff);
1527 for (int y = 0; y < imgA.height(); ++y) {
1528 for (int x = 0; x < imgA.width(); ++x) {
1530 imgA.setPixel(x, y, 0);
1531 path.addRect(x, y, 1, 1);
1537 p.setPen(Qt::NoPen);
1538 p.setBrush(Qt::black);
1543 QVERIFY(imgA == imgB);
1545 imgA.invertPixels();
1546 imgB.fill(0xffffff);
1549 p.setPen(Qt::NoPen);
1550 p.setBrush(Qt::black);
1552 QRectF rect(0, 0, imgA.width(), imgA.height());
1553 path.addRect(rect.adjusted(-10, -10, 10, 10));
1557 QVERIFY(imgA == imgB);
1559 path.setFillRule(Qt::WindingFill);
1560 imgB.fill(0xffffff);
1563 p.setPen(Qt::NoPen);
1564 p.setBrush(Qt::black);
1565 QRect clip = rect.adjusted(10, 10, -10, -10).toRect();
1566 p.setClipRect(clip);
1570 QCOMPARE(getPaintedPixels(imgB, Qt::white), clip.width() * clip.height());
1573 void tst_QPainter::drawEllipse_data()
1575 QTest::addColumn<QSize>("size");
1576 QTest::addColumn<bool>("usePen");
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;
1591 void tst_QPainter::drawEllipse()
1593 QFETCH(QSize, size);
1594 QFETCH(bool, usePen);
1596 const int offset = 10;
1597 QRect rect(QPoint(offset, offset), size);
1599 QImage image(size.width() + 2 * offset, size.height() + 2 * offset,
1600 QImage::Format_ARGB32_Premultiplied);
1601 image.fill(QColor(Qt::white).rgb());
1604 p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1605 p.setBrush(Qt::black);
1606 p.drawEllipse(rect);
1609 QPixmap pixmap = QPixmap::fromImage(image);
1611 const QRect painted = getPaintedSize(pixmap, Qt::white);
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));
1619 void tst_QPainter::drawClippedEllipse_data()
1621 QTest::addColumn<QRect>("rect");
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);
1638 void tst_QPainter::drawClippedEllipse()
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());
1649 image.fill(QColor(Qt::white).rgb());
1651 p.drawEllipse(rect);
1654 QPixmap pixmap = QPixmap::fromImage(image);
1655 const QRect painted = getPaintedSize(pixmap, Qt::white);
1657 QCOMPARE(painted.x(), expected.x());
1658 QCOMPARE(painted.y(), expected.y());
1659 QCOMPARE(painted.width(), expected.width());
1660 QCOMPARE(painted.height(), expected.height());
1664 void tst_QPainter::drawRoundRect()
1666 QFETCH(QRect, rect);
1667 QFETCH(bool, usePen);
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);
1680 QPixmap pixmap(rect.x() + rect.width() + 10,
1681 rect.y() + rect.height() + 10);
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);
1690 int increment = usePen ? 1 : 0;
1692 const QRect painted = getPaintedSize(pixmap, Qt::white);
1693 QCOMPARE(painted.width(), rect.width() + increment);
1694 QCOMPARE(painted.height(), rect.height() + increment);
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);
1706 const QRect painted = getPaintedSize(pixmap, Qt::white);
1708 QCOMPARE(painted.width(), rect.width());
1709 QCOMPARE(painted.height(), rect.height());
1714 Q_DECLARE_METATYPE(QImage::Format)
1716 void tst_QPainter::qimageFormats_data()
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;
1731 Tests that QPainter can paint on various QImage formats.
1733 void tst_QPainter::qimageFormats()
1735 QFETCH(QImage::Format, format);
1737 const QSize size(100, 100);
1738 QImage image(size, format);
1741 const QColor testColor(Qt::red);
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());
1749 void tst_QPainter::fillData()
1751 QTest::addColumn<QRect>("rect");
1752 QTest::addColumn<bool>("usePen");
1754 for (int w = 3; w < 50; w += 7) {
1755 for (int h = 3; h < 50; h += 11) {
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;
1767 Test that drawline works properly after setWindow has been called.
1769 void tst_QPainter::setWindow()
1771 QPixmap pixmap(600, 600);
1772 pixmap.fill(QColor(Qt::white));
1774 QPainter painter(&pixmap);
1775 painter.setWindow(0, 0, 3, 3);
1776 painter.drawLine(1, 1, 2, 2);
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
1783 void tst_QPainter::combinedMatrix()
1788 p.setWindow(0, 0, 1, 1);
1789 p.setViewport(32, 0, 32, 32);
1791 p.translate(0.5, 0.5);
1793 QMatrix cm = p.combinedMatrix();
1795 QPointF pt = QPointF(0, 0) * cm;
1797 QCOMPARE(pt.x(), 48.0);
1798 QCOMPARE(pt.y(), 16.0);
1801 void tst_QPainter::textOnTransparentImage()
1803 bool foundPixel = false;
1804 QImage image(10, 10, QImage::Format_ARGB32_Premultiplied);
1805 image.fill(qRgba(0, 0, 0, 0)); // transparent
1807 QPainter painter(&image);
1808 painter.setPen(QColor(255, 255, 255));
1809 painter.drawText(0, 10, "W");
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)
1815 QVERIFY(foundPixel);
1818 void tst_QPainter::renderHints()
1820 QImage img(1, 1, QImage::Format_RGB32);
1825 p.setRenderHints(QPainter::RenderHints(0xffffffff), false);
1826 QCOMPARE(p.renderHints(), QPainter::RenderHints(0));
1829 p.setRenderHint(QPainter::Antialiasing);
1830 QVERIFY(p.renderHints() & QPainter::Antialiasing);
1832 p.setRenderHint(QPainter::Antialiasing, false);
1833 QVERIFY(!(p.renderHints() & QPainter::Antialiasing));
1836 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
1837 QVERIFY(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform));
1839 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
1840 QVERIFY(!(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform)));
1843 int countPixels(const QImage &img, const QRgb &color)
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);
1854 template <typename T>
1855 void testClipping(QImage &img)
1859 a.addRect(QRect(2, 2, 4, 4));
1860 b.addRect(QRect(4, 4, 4, 4));
1864 p.setClipPath(b, Qt::UniteClip);
1866 p.setClipping(false);
1867 p.setPen(Qt::NoPen);
1868 p.setBrush(QColor(0xff0000));
1869 p.drawRect(T(0, 0, 10, 10));
1871 p.setClipping(true);
1872 p.setBrush(QColor(0x00ff00));
1873 p.drawRect(T(0, 0, 10, 10));
1875 QCOMPARE(countPixels(img, 0xff0000), 72);
1876 QCOMPARE(countPixels(img, 0x00ff00), 28);
1882 p.setClipPath(b, Qt::IntersectClip);
1884 p.setClipping(false);
1885 p.setPen(Qt::NoPen);
1886 p.setBrush(QColor(0xff0000));
1887 p.drawRect(T(0, 0, 10, 10));
1889 p.setClipping(true);
1890 p.setBrush(QColor(0x00ff00));
1891 p.drawRect(T(0, 0, 10, 10));
1893 QCOMPARE(countPixels(img, 0xff0000), 96);
1894 QCOMPARE(countPixels(img, 0x00ff00), 4);
1897 void tst_QPainter::disableEnableClipping()
1899 QImage img(10, 10, QImage::Format_RGB32);
1901 testClipping<QRectF>(img);
1902 testClipping<QRect>(img);
1905 void tst_QPainter::setClipRect()
1907 QImage img(10, 10, QImage::Format_RGB32);
1908 // simple test to let valgrind check for buffer overflow
1911 p.setClipRect(-10, -10, 100, 100);
1912 p.fillRect(-10, -10, 100, 100, QBrush(QColor(Qt::red)));
1915 // rects with negative width/height
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());
1930 This tests the two different clipping approaches in QRasterPaintEngine,
1931 one when using a QRegion and one when using a QPainterPath. They should
1934 void tst_QPainter::setEqualClipRegionAndPath_data()
1936 QTest::addColumn<QSize>("deviceSize");
1937 QTest::addColumn<QRegion>("region");
1939 QTest::newRow("empty") << QSize(100, 100) << QRegion();
1940 QTest::newRow("simple rect") << QSize(100, 100)
1941 << QRegion(QRect(5, 5, 10, 10));
1943 QVector<QRect> rects;
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;
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;
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;
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;
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;
1970 region = QRegion(QRect(0, 0, 200, 200), QRegion::Ellipse);
1972 QTest::newRow("ellipse") << QSize(190, 200) << region;
1974 region ^= QRect(50, 50, 50, 50);
1975 QTest::newRow("ellipse 2") << QSize(200, 200) << region;
1978 void tst_QPainter::setEqualClipRegionAndPath()
1980 QFETCH(QSize, deviceSize);
1981 QFETCH(QRegion, region);
1984 path.addRegion(region);
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);
1995 p.setClipRegion(region);
1996 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
2000 p.setClipPath(path);
2001 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
2006 img1.save("setEqualClipRegionAndPath_1.xpm", "XPM");
2007 img2.save("setEqualClipRegionAndPath_2.xpm", "XPM");
2010 QCOMPARE(img1, img2);
2014 img1.fill(0x12345678);
2015 img2.fill(0x12345678);
2020 p.setClipRegion(region);
2021 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
2026 p.setClipPath(path);
2027 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
2032 img1.save("setEqualClipRegionAndPath_1.xpm", "XPM");
2033 img2.save("setEqualClipRegionAndPath_2.xpm", "XPM");
2036 QCOMPARE(img1, img2);
2040 img1.fill(0x12345678);
2041 img2.fill(0x12345678);
2044 p.setClipRegion(region);
2045 p.setClipRegion(region, Qt::UniteClip);
2046 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
2050 p.setClipPath(path);
2051 p.setClipPath(path, Qt::UniteClip);
2052 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
2054 QCOMPARE(img1, img2);
2055 img1.fill(0x12345678);
2056 img2.fill(0x12345678);
2059 p.setClipPath(path);
2060 p.setClipRegion(region, Qt::UniteClip);
2061 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
2065 p.setClipRegion(region);
2066 p.setClipPath(path, Qt::UniteClip);
2067 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
2071 img1.save("setEqualClipRegionAndPath_1.xpm", "XPM");
2072 img2.save("setEqualClipRegionAndPath_2.xpm", "XPM");
2075 QCOMPARE(img1, img2);
2077 // simple intersectclip
2078 img1.fill(0x12345678);
2079 img2.fill(0x12345678);
2082 p.setClipRegion(region);
2083 p.setClipRegion(region, Qt::IntersectClip);
2084 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
2088 p.setClipPath(path);
2089 p.setClipPath(path, Qt::IntersectClip);
2090 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
2094 img1.save("setEqualClipRegionAndPath_1.png", "PNG");
2095 img2.save("setEqualClipRegionAndPath_2.png", "PNG");
2098 QCOMPARE(img1, img2);
2100 img1.fill(0x12345678);
2101 img2.fill(0x12345678);
2104 p.setClipPath(path);
2105 p.setClipRegion(region, Qt::IntersectClip);
2106 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
2110 p.setClipRegion(region);
2111 p.setClipPath(path, Qt::IntersectClip);
2112 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
2116 img1.save("setEqualClipRegionAndPath_1.xpm", "XPM");
2117 img2.save("setEqualClipRegionAndPath_2.xpm", "XPM");
2120 QCOMPARE(img1, img2);
2124 void tst_QPainter::clippedFillPath_data()
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");
2132 QLinearGradient gradient(QPoint(0, 0), QPoint(100, 100));
2133 gradient.setColorAt(0, Qt::red);
2134 gradient.setColorAt(1, Qt::blue);
2137 QPen pen2(QColor(223, 223, 0, 223));
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)
2146 QTest::newRow("simple rect 1") << QSize(100, 100) << path
2147 << QRect(15, 15, 50, 50)
2148 << QBrush(Qt::NoBrush)
2150 QTest::newRow("simple rect 2") << QSize(100, 100) << path
2151 << QRect(15, 15, 51, 51)
2152 << QBrush(Qt::NoBrush)
2154 QTest::newRow("simple rect 3") << QSize(100, 100) << path
2155 << QRect(15, 15, 51, 51)
2156 << QBrush(QColor(Qt::blue))
2158 QTest::newRow("simple rect 4") << QSize(100, 100) << path
2159 << QRect(15, 15, 51, 51)
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)
2169 QTest::newRow("ellipse 1") << QSize(100, 100) << path
2170 << QRect(15, 15, 50, 50)
2171 << QBrush(Qt::NoBrush)
2173 QTest::newRow("ellipse 2") << QSize(100, 100) << path
2174 << QRect(15, 15, 51, 51)
2175 << QBrush(Qt::NoBrush)
2177 QTest::newRow("ellipse 3") << QSize(100, 100) << path
2178 << QRect(15, 15, 51, 51)
2179 << QBrush(QColor(Qt::blue))
2181 QTest::newRow("ellipse 4") << QSize(100, 100) << path
2182 << QRect(15, 15, 51, 51)
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)
2192 QTest::newRow("round rect 1") << QSize(100, 100) << path
2193 << QRect(15, 15, 50, 50)
2194 << QBrush(Qt::NoBrush)
2196 QTest::newRow("round rect 2") << QSize(100, 100) << path
2197 << QRect(15, 15, 51, 51)
2198 << QBrush(Qt::NoBrush)
2200 QTest::newRow("round rect 3") << QSize(100, 100) << path
2201 << QRect(15, 15, 51, 51)
2202 << QBrush(QColor(Qt::blue))
2204 QTest::newRow("round rect 4") << QSize(100, 100) << path
2205 << QRect(15, 15, 51, 51)
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)
2217 QTest::newRow("cubic 1") << QSize(100, 100) << path
2218 << QRect(15, 15, 50, 50)
2219 << QBrush(Qt::NoBrush)
2221 QTest::newRow("cubic 2") << QSize(100, 100) << path
2222 << QRect(15, 15, 51, 51)
2223 << QBrush(Qt::NoBrush)
2225 QTest::newRow("cubic 3") << QSize(100, 100) << path
2226 << QRect(15, 15, 51, 51)
2227 << QBrush(QColor(Qt::blue))
2229 QTest::newRow("cubic 4") << QSize(100, 100) << path
2230 << QRect(15, 15, 51, 51)
2235 void tst_QPainter::clippedFillPath()
2237 QFETCH(QSize, imageSize);
2238 QFETCH(QPainterPath, path);
2239 QFETCH(QRect, clipRect);
2240 QPainterPath clipPath;
2241 clipPath.addRect(clipRect);
2242 QFETCH(QBrush, brush);
2245 const int width = imageSize.width();
2246 const int height = imageSize.height();
2248 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
2249 clippedRect.fill(0x12345678);
2251 QPainter painter(&clippedRect);
2252 painter.setPen(pen);
2253 painter.setBrush(brush);
2254 painter.setClipRect(clipRect);
2255 painter.drawPath(path);
2258 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2259 clippedPath.fill(0x12345678);
2261 QPainter painter(&clippedPath);
2262 painter.setPen(pen);
2263 painter.setBrush(brush);
2264 painter.setClipPath(clipPath);
2265 painter.drawPath(path);
2269 if (clippedRect != clippedPath) {
2270 clippedRect.save(QString("clippedRect.png"), "PNG");
2271 clippedPath.save(QString("clippedPath.png"), "PNG");
2274 QCOMPARE(clippedRect, clippedPath);
2276 // repeat with antialiasing
2278 clippedRect.fill(0x12345678);
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);
2288 clippedPath.fill(0x12345678);
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);
2299 if (clippedRect != clippedPath) {
2300 clippedRect.save(QString("clippedRect.png"), "PNG");
2301 clippedPath.save(QString("clippedPath.png"), "PNG");
2304 QCOMPARE(clippedRect, clippedPath);
2308 void tst_QPainter::clippedLines_data()
2310 QTest::addColumn<QSize>("imageSize");
2311 QTest::addColumn<QLineF>("line");
2312 QTest::addColumn<QRect>("clipRect");
2313 QTest::addColumn<QPen>("pen");
2315 QPen pen2(QColor(223, 223, 0, 223));
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);
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)
2338 QTest::newRow(qPrintable(desc.arg(1))) << QSize(100, 100) << line
2339 << QRect(15, 15, 50, 50)
2341 QTest::newRow(qPrintable(desc.arg(2))) << QSize(100, 100) << line
2342 << QRect(15, 15, 51, 51)
2344 QTest::newRow(qPrintable(desc.arg(3))) << QSize(100, 100) << line
2345 << QRect(15, 15, 51, 51)
2347 QTest::newRow(qPrintable(desc.arg(4))) << QSize(100, 100) << line
2348 << QRect(15, 15, 51, 51)
2353 void tst_QPainter::clippedLines()
2355 QFETCH(QSize, imageSize);
2356 QFETCH(QLineF, line);
2357 QFETCH(QRect, clipRect);
2358 QPainterPath clipPath;
2359 clipPath.addRect(clipRect);
2362 const int width = imageSize.width();
2363 const int height = imageSize.height();
2365 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
2366 clippedRect.fill(0x12345678);
2368 QPainter painter(&clippedRect);
2369 painter.setPen(pen);
2370 painter.setClipRect(clipRect);
2371 painter.drawLine(line);
2372 painter.drawLine(line.toLine());
2375 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2376 clippedPath.fill(0x12345678);
2378 QPainter painter(&clippedPath);
2379 painter.setPen(pen);
2380 painter.setClipPath(clipPath);
2381 painter.drawLine(line);
2382 painter.drawLine(line.toLine());
2386 if (clippedRect != clippedPath) {
2387 clippedRect.save(QString("clippedRect.png"), "PNG");
2388 clippedPath.save(QString("clippedPath.png"), "PNG");
2391 QCOMPARE(clippedRect, clippedPath);
2393 // repeat with antialiasing
2394 clippedRect.fill(0x12345678);
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());
2404 clippedPath.fill(0x12345678);
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());
2415 if (clippedRect != clippedPath) {
2416 clippedRect.save(QString("clippedRect.png"), "PNG");
2417 clippedPath.save(QString("clippedPath.png"), "PNG");
2420 QCOMPARE(clippedRect, clippedPath);
2423 void tst_QPainter::clippedPolygon_data()
2425 clippedFillPath_data();
2428 void tst_QPainter::clippedPolygon()
2430 QFETCH(QSize, imageSize);
2431 QFETCH(QPainterPath, path);
2432 QPolygonF polygon = path.toFillPolygon();
2433 QFETCH(QRect, clipRect);
2434 QPainterPath clipPath;
2435 clipPath.addRect(clipRect);
2437 QFETCH(QBrush, brush);
2439 const int width = imageSize.width();
2440 const int height = imageSize.height();
2442 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
2443 clippedRect.fill(0x12345678);
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());
2453 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2454 clippedPath.fill(0x12345678);
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());
2465 if (clippedRect != clippedPath) {
2466 clippedRect.save(QString("clippedRect.png"), "PNG");
2467 clippedPath.save(QString("clippedPath.png"), "PNG");
2470 QCOMPARE(clippedRect, clippedPath);
2472 // repeat with antialiasing
2474 clippedRect.fill(0x12345678);
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());
2485 clippedPath.fill(0x12345678);
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());
2497 if (clippedRect != clippedPath) {
2498 clippedRect.save(QString("clippedRect.png"), "PNG");
2499 clippedPath.save(QString("clippedPath.png"), "PNG");
2502 QCOMPARE(clippedRect, clippedPath);
2505 // this just draws some text that should be clipped in the raster
2507 void tst_QPainter::clippedText()
2509 for (char ch = 'A'; ch < 'Z'; ++ch) {
2513 QFontMetrics metrics(f);
2514 QRect textRect = metrics.boundingRect(QChar(ch));
2516 if (textRect.width() <= 8)
2518 if (textRect.height() <= 8)
2521 QRect imageRect = textRect.adjusted(4, 4, -4, -4);
2523 QImage image(imageRect.size(), QImage::Format_ARGB32_Premultiplied);
2525 image.fill(qRgba(255, 255, 255, 255));
2527 QPainter painter(&image);
2529 painter.setPen(Qt::black);
2531 painter.drawText(0, 0, QChar(ch));
2534 image.fill(qRgba(255, 255, 255, 255));
2536 QPainter painter(&image);
2538 painter.setPen(Qt::black);
2540 painter.drawText(-imageRect.topLeft(), QChar(ch));
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)
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
2552 QString::number(foundPixel);
2554 //image.save(QString("debug") + ch + ".xpm");
2557 QVERIFY(true); // reached, don't trigger any valgrind errors
2560 void tst_QPainter::setOpacity_data()
2562 QTest::addColumn<QImage::Format>("destFormat");
2563 QTest::addColumn<QImage::Format>("srcFormat");
2565 QTest::newRow("ARGB32P on ARGB32P") << QImage::Format_ARGB32_Premultiplied
2566 << QImage::Format_ARGB32_Premultiplied;
2568 QTest::newRow("ARGB32 on ARGB32") << QImage::Format_ARGB32
2569 << QImage::Format_ARGB32;
2571 QTest::newRow("RGB32 on RGB32") << QImage::Format_RGB32
2572 << QImage::Format_RGB32;
2574 QTest::newRow("RGB16 on RGB16") << QImage::Format_RGB16
2575 << QImage::Format_RGB16;
2577 QTest::newRow("ARGB8565_Premultiplied on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied
2578 << QImage::Format_ARGB8565_Premultiplied;
2580 QTest::newRow("RGB555 on RGB555") << QImage::Format_RGB555
2581 << QImage::Format_RGB555;
2583 QTest::newRow("RGB666 on RGB666") << QImage::Format_RGB666
2584 << QImage::Format_RGB666;
2586 QTest::newRow("ARGB8555_Premultiplied on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied
2587 << QImage::Format_ARGB8555_Premultiplied;
2589 QTest::newRow("RGB888 on RGB888") << QImage::Format_RGB888
2590 << QImage::Format_RGB888;
2592 QTest::newRow("RGB32 on RGB16") << QImage::Format_RGB16
2593 << QImage::Format_RGB32;
2595 QTest::newRow("RGB32 on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied
2596 << QImage::Format_RGB32;
2598 QTest::newRow("RGB32 on RGB666") << QImage::Format_RGB666
2599 << QImage::Format_RGB32;
2601 QTest::newRow("RGB32 on RGB555") << QImage::Format_RGB555
2602 << QImage::Format_RGB32;
2604 QTest::newRow("RGB32 on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied
2605 << QImage::Format_RGB32;
2607 QTest::newRow("RGB32 on RGB888") << QImage::Format_RGB888
2608 << QImage::Format_RGB32;
2610 QTest::newRow("RGB16 on RGB32") << QImage::Format_RGB32
2611 << QImage::Format_RGB16;
2613 QTest::newRow("ARGB8565_Premultiplied on RGB32") << QImage::Format_RGB32
2614 << QImage::Format_ARGB8565_Premultiplied;
2616 QTest::newRow("RGB666 on RGB32") << QImage::Format_RGB32
2617 << QImage::Format_RGB666;
2619 QTest::newRow("RGB555 on RGB32") << QImage::Format_RGB32
2620 << QImage::Format_RGB555;
2622 QTest::newRow("ARGB8555_Premultiplied on RGB32") << QImage::Format_RGB32
2623 << QImage::Format_ARGB8555_Premultiplied;
2625 QTest::newRow("RGB888 on RGB32") << QImage::Format_RGB32
2626 << QImage::Format_RGB888;
2628 QTest::newRow("RGB555 on RGB888") << QImage::Format_RGB888
2629 << QImage::Format_RGB555;
2631 QTest::newRow("RGB666 on RGB888") << QImage::Format_RGB888
2632 << QImage::Format_RGB666;
2634 QTest::newRow("RGB444 on RGB444") << QImage::Format_RGB444
2635 << QImage::Format_RGB444;
2638 void tst_QPainter::setOpacity()
2640 QFETCH(QImage::Format, destFormat);
2641 QFETCH(QImage::Format, srcFormat);
2643 const QSize imageSize(12, 12);
2644 const QRect imageRect(QPoint(0, 0), imageSize);
2645 QColor destColor = Qt::black;
2646 QColor srcColor = Qt::white;
2648 QImage dest(imageSize, destFormat);
2649 QImage src(imageSize, srcFormat);
2653 p.fillRect(imageRect, destColor);
2657 p.fillRect(imageRect, srcColor);
2662 p.drawImage(imageRect, src, imageRect);
2665 QImage actual = dest.convertToFormat(QImage::Format_RGB32);
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);
2677 void tst_QPainter::drawhelper_blend_untransformed_data()
2682 void tst_QPainter::drawhelper_blend_untransformed()
2684 QFETCH(QImage::Format, destFormat);
2685 QFETCH(QImage::Format, srcFormat);
2687 const int size = 128;
2688 const QSize imageSize(size, size);
2689 const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing
2691 QColor destColor(127, 127, 127);
2692 QColor srcColor(Qt::white);
2694 QImage dest(imageSize, destFormat);
2695 QImage src(imageSize, srcFormat);
2699 p.fillRect(paintRect, srcColor);
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) {
2706 p.fillRect(paintRect, destColor);
2708 p.setOpacity(opacity);
2709 p.drawImage(paintRect, src, paintRect);
2712 // sanity check: make sure all pixels are equal
2713 QImage expected(size - 2, size, destFormat);
2715 p.fillRect(0, 0, expected.width(), expected.height(),
2716 QColor(dest.pixel(1, 0)));
2719 const QImage subDest(dest.bits() + dest.depth() / 8,
2720 dest.width() - 2, dest.height(),
2721 dest.bytesPerLine(), dest.format());
2723 if (dest.format() == QImage::Format_ARGB8565_Premultiplied ||
2724 dest.format() == QImage::Format_ARGB8555_Premultiplied) {
2725 // Test skipped due to rounding errors...
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);
2740 QCOMPARE(subDest, expected);
2744 void tst_QPainter::drawhelper_blend_tiled_untransformed_data()
2749 void tst_QPainter::drawhelper_blend_tiled_untransformed()
2751 QFETCH(QImage::Format, destFormat);
2752 QFETCH(QImage::Format, srcFormat);
2754 const int size = 128;
2755 const QSize imageSize(size, size);
2756 const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing
2758 QColor destColor(127, 127, 127);
2759 QColor srcColor(Qt::white);
2761 QImage dest(imageSize, destFormat);
2762 QImage src(imageSize / 2, srcFormat);
2766 p.fillRect(QRect(QPoint(0, 0), imageSize/ 2), srcColor);
2769 const QBrush brush(src);
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) {
2775 p.fillRect(paintRect, destColor);
2777 p.setOpacity(opacity);
2778 p.fillRect(paintRect, brush);
2781 // sanity check: make sure all pixels are equal
2782 QImage expected(size - 2, size, destFormat);
2784 p.fillRect(0, 0, expected.width(), expected.height(),
2785 QColor(dest.pixel(1, 0)));
2788 const QImage subDest(dest.bits() + dest.depth() / 8,
2789 dest.width() - 2, dest.height(),
2790 dest.bytesPerLine(), dest.format());
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
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);
2809 QCOMPARE(subDest, expected);
2813 static QPaintEngine::PaintEngineFeatures no_porter_duff()
2815 QPaintEngine::PaintEngineFeatures features = QPaintEngine::AllFeatures;
2816 return features & ~QPaintEngine::PorterDuff;
2819 class DummyPaintEngine : public QPaintEngine, public QPaintDevice
2822 DummyPaintEngine() : QPaintEngine(no_porter_duff()) {}
2823 virtual bool begin(QPaintDevice *) { return true; }
2824 virtual bool end() { return true; }
2826 virtual void updateState(const QPaintEngineState &) {}
2827 virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
2829 virtual Type type() const { return User; }
2831 virtual QPaintEngine *paintEngine() const { return (QPaintEngine *)this; }
2833 virtual int metric(PaintDeviceMetric metric) const { Q_UNUSED(metric); return 0; };
2836 static bool success;
2838 void porterDuff_warningChecker(QtMsgType type, const char *msg)
2840 if (type == QtWarningMsg && msg == QLatin1String("QPainter::setCompositionMode: PorterDuff modes not supported on device"))
2844 void tst_QPainter::porterDuff_warning()
2846 QtMsgHandler old = qInstallMsgHandler(porterDuff_warningChecker);
2847 DummyPaintEngine dummy;
2851 p.setCompositionMode(QPainter::CompositionMode_Source);
2855 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
2859 p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
2862 QVERIFY(qInstallMsgHandler(old) == porterDuff_warningChecker);
2868 inline quint24(quint32 v)
2871 data[1] = qGreen(v);
2875 inline operator quint32 ()
2877 return qRgb(data[2], data[1], data[0]);
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]);
2887 void tst_QPainter::drawhelper_blend_color()
2889 QImage dest(32, 32, QImage::Format_ARGB8555_Premultiplied);
2890 dest.fill(0xff000000);
2894 p.fillRect(0, 0, dest.width(), dest.height(), QColor(255, 0, 0, 127));
2897 QImage expected(32, 32, QImage::Format_ARGB8555_Premultiplied);
2898 expected.fill(0xff3c007f);
2900 QCOMPARE(dest.pixel(1, 1), expected.pixel(1, 1));
2901 QCOMPARE(dest, expected);
2904 class ViewportTestWidget : public QWidget
2907 ViewportTestWidget(QWidget *parent = 0) : QWidget(parent), hasPainted(false) {}
2908 QSize sizeHint() const {
2909 return QSize(100, 100);
2916 void paintEvent(QPaintEvent *) {
2919 viewport = p.viewport();
2923 void tst_QPainter::childWidgetViewport()
2926 parent.setAutoFillBackground(true);
2927 parent.resize(200, 200);
2928 ViewportTestWidget child(&parent);
2929 child.setAutoFillBackground(true);
2932 qApp->processEvents();
2934 if (child.hasPainted) {
2935 QCOMPARE(child.viewport, QRect(QPoint(0, 0), child.sizeHint()));
2937 qWarning("Failed to ensure that paintEvent has been run. Could not run test.");
2941 void tst_QPainter::fillRect_objectBoundingModeGradient()
2943 QImage a(10, 10, QImage::Format_ARGB32_Premultiplied);
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);
2953 p.fillRect(QRect(0, 0, a.width(), a.height()), g);
2957 path.addRect(0, 0, a.width(), a.height());
2960 p.fillPath(path, g);
2966 void tst_QPainter::fillRect_stretchToDeviceMode()
2968 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2970 QLinearGradient g(QPoint(0, 0), QPoint(0, 1));
2971 g.setCoordinateMode(QGradient::StretchToDeviceMode);
2974 p.fillRect(img.rect(), g);
2977 for (int i = 1; i < img.height(); ++i)
2978 QVERIFY(img.pixel(0, i) != img.pixel(0, i-1));
2981 void tst_QPainter::monoImages()
2983 Qt::GlobalColor colorPairs[][2] = {
2984 { Qt::white, Qt::black },
2985 { Qt::color0, Qt::color1 },
2986 { Qt::red, Qt::blue }
2989 const int numColorPairs = sizeof(colorPairs) / sizeof(QRgb[2]);
2991 QImage transparent(2, 2, QImage::Format_ARGB32_Premultiplied);
2992 transparent.fill(0x0);
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)
3000 QImage img(2, 2, format);
3002 if (img.colorCount() > 0) {
3003 img.setColor(0, QColor(colorPairs[j][0]).rgba());
3004 img.setColor(1, QColor(colorPairs[j][1]).rgba());
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]);
3014 QImage original = img;
3017 p.drawImage(0, 0, transparent);
3020 // drawing a transparent image on top of another image
3021 // should not change the image
3022 QCOMPARE(original, img);
3024 if (img.colorCount() == 0)
3027 for (int k = 0; k < 2; ++k) {
3029 p.fillRect(0, 0, 2, 2, colorPairs[j][k]);
3032 QImage argb32p(2, 2, QImage::Format_ARGB32_Premultiplied);
3034 p.fillRect(0, 0, 2, 2, colorPairs[j][k]);
3037 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
3039 // drawing argb32p image on mono image
3041 p.drawImage(0, 0, argb32p);
3044 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
3046 // drawing mono image on argb32p image
3048 p.drawImage(0, 0, img);
3051 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
3057 #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_CC_MSVC) && !defined(Q_OS_SOLARIS) && !defined(Q_OS_SYMBIAN)
3060 static const QString fpeExceptionString(int exception)
3063 if (exception & FE_INEXACT)
3064 return QLatin1String("Inexact result");
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");
3077 class FpExceptionChecker
3080 FpExceptionChecker(int exceptionMask)
3081 : m_exceptionMask(exceptionMask)
3083 feclearexcept(m_exceptionMask);
3086 ~FpExceptionChecker()
3088 const int exceptions = fetestexcept(m_exceptionMask);
3089 QVERIFY2(!exceptions, qPrintable(QLatin1String("Floating point exception: ") + fpeExceptionString(exceptions)));
3093 int m_exceptionMask;
3096 void fpe_rasterizeLine_task232012()
3098 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
3099 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
3103 p.setBrush(Qt::black);
3104 p.drawRect(QRectF(0, 0, 5, 0));
3105 p.drawRect(QRectF(0, 0, 0, 5));
3108 void fpe_pixmapTransform()
3110 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
3112 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
3116 const qreal scaleFactor = 0.001;
3117 const int translateDistance = 1000000;
3120 p.setBrush(QBrush(Qt::red,Qt::Dense6Pattern));
3122 for (int i = 0; i < 2; ++i) {
3123 p.setRenderHint(QPainter::SmoothPixmapTransform, i);
3127 p.translate(translateDistance, 0);
3128 p.drawRect(-translateDistance, 0, 100, 100);
3131 p.scale(scaleFactor, scaleFactor);
3132 p.drawRect(QRectF(0, 0, 1 / scaleFactor, 1 / scaleFactor));
3136 void fpe_zeroLengthLines()
3138 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
3140 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
3144 p.setPen(QPen(Qt::black, 3));
3145 p.drawLine(64, 64, 64, 64);
3148 void fpe_divByZero()
3150 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
3152 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
3156 p.setRenderHint(QPainter::Antialiasing);
3158 p.drawRect(QRectF(10, 10, 100, 0));
3159 p.drawRect(QRectF(10, 10, 0, 100));
3161 p.drawRect(QRect(10, 10, 100, 0));
3162 p.drawRect(QRect(10, 10, 0, 100));
3164 p.fillRect(QRectF(10, 10, 100, 0), Qt::black);
3165 p.fillRect(QRectF(10, 10, 0, 100), Qt::black);
3167 p.fillRect(QRect(10, 10, 100, 0), Qt::black);
3168 p.fillRect(QRect(10, 10, 0, 100), Qt::black);
3171 void fpe_steepSlopes()
3173 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
3175 QImage img(1024, 1024, QImage::Format_ARGB32_Premultiplied);
3177 QFETCH(QTransform, transform);
3178 QFETCH(QLineF, line);
3179 QFETCH(bool, antialiased);
3183 p.setPen(QPen(Qt::black, 1));
3184 p.setRenderHint(QPainter::Antialiasing, antialiased);
3185 p.setTransform(transform);
3190 void fpe_radialGradients()
3192 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
3194 QImage img(21, 21, QImage::Format_ARGB32_Premultiplied);
3197 double m = img.width() * 0.5;
3200 p.setRenderHints(QPainter::Antialiasing);
3201 p.setPen(Qt::NoPen);
3202 p.setBrush(QRadialGradient(m, m, m));
3203 p.drawEllipse(img.rect());
3206 #define FPE_TEST(x) \
3207 void tst_QPainter::x() \
3212 #define FPE_TEST(x) \
3213 void tst_QPainter::x() \
3215 QSKIP("Floating point exception checking (fenv.h) not available", SkipAll); \
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)
3226 void tst_QPainter::fpe_steepSlopes_data()
3228 QTest::addColumn<QTransform>("transform");
3229 QTest::addColumn<QLineF>("line");
3230 QTest::addColumn<bool>("antialiased");
3233 const qreal dsin = 0.000014946676875461832484392500630665523431162000633776187896728515625;
3234 const qreal dcos = 0.9999999998882984630910186751862056553363800048828125;
3236 const QTransform transform = QTransform(QMatrix(dcos, dsin, -dsin, dcos, 64, 64));
3237 const QLineF line(2, 2, 2, 6);
3239 QTest::newRow("task 207147 aa") << transform << line << true;
3240 QTest::newRow("task 207147 no aa") << transform << line << false;
3244 QTransform transform;
3245 transform.rotate(0.0000001);
3246 const QLineF line(5, 5, 10, 5);
3248 QTest::newRow("task 166702 aa") << transform << line << true;
3249 QTest::newRow("task 166702 no aa") << transform << line << false;
3253 const QTransform transform;
3254 const QLineF line(2.5, 2.5, 2.5 + 1/256., 60000.5);
3256 QTest::newRow("steep line aa") << transform << line << true;
3257 QTest::newRow("steep line no aa") << transform << line << false;
3261 const QTransform transform;
3262 const QLineF line(2.5, 2.5, 2.5 + 1/256., 1024);
3264 QTest::newRow("steep line 2 aa") << transform << line << true;
3265 QTest::newRow("steep line 2 no aa") << transform << line << false;
3269 const QTransform transform;
3270 const QLineF line(2.5, 2.5, 2.5 + 1/64., 1024);
3272 QTest::newRow("steep line 3 aa") << transform << line << true;
3273 QTest::newRow("steep line 3 no aa") << transform << line << false;
3279 return rand() / (RAND_MAX + 1.0);
3282 QPointF randInRect(const QRectF &rect)
3284 const qreal x = rect.left() + rect.width() * randf();
3285 const qreal y = rect.top() + rect.height() * randf();
3287 return QPointF(x, y);
3290 void tst_QPainter::rasterizer_asserts()
3292 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3294 QRectF middle(QPointF(0, 0), img.size());
3295 QRectF left = middle.translated(-middle.width(), 0);
3296 QRectF right = middle.translated(middle.width(), 0);
3299 img.fill(Qt::white);
3300 p.setCompositionMode(QPainter::CompositionMode_Destination);
3301 for (int i = 0; i < 100000; ++i) {
3303 path.moveTo(randInRect(middle));
3304 path.lineTo(randInRect(left));
3305 path.lineTo(randInRect(right));
3307 p.fillPath(path, Qt::black);
3311 void tst_QPainter::rasterizer_negativeCoords()
3313 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3316 QImage original = img;
3320 p.fillRect(0, 0, 70, 50, Qt::black);
3322 // image should not have changed
3323 QCOMPARE(img.pixel(0, 0), 0x0U);
3324 QCOMPARE(img, original);
3327 void tst_QPainter::blendOverFlow_data()
3329 QTest::addColumn<QImage::Format>("format");
3330 QTest::addColumn<int>("width");
3331 QTest::addColumn<int>("height");
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;
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;
3344 void tst_QPainter::blendOverFlow()
3346 QFETCH(QImage::Format, format);
3348 QFETCH(int, height);
3350 QImage dest(width, height, format);
3351 QImage src(width, height, format);
3355 p.fillRect(0, 0, width, height, Qt::green);
3357 QImage expected = dest;
3361 p.setCompositionMode(QPainter::CompositionMode_Source);
3362 p.fillRect(0, 0, width, height, QColor(0, 255, 0, 6));
3367 p.drawImage(0, 0, src);
3370 QCOMPARE(dest.pixel(0, 0), expected.pixel(0, 0));
3371 QCOMPARE(dest, expected);
3374 void tst_QPainter::largeImagePainting_data()
3376 QTest::addColumn<int>("width");
3377 QTest::addColumn<int>("height");
3378 QTest::addColumn<bool>("antialiased");
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;
3386 void tst_QPainter::largeImagePainting()
3389 path.addRect(0, 0, 1, 1);
3390 path.addRect(2, 0, 1, 1);
3391 path.addRect(0, 2, 1, 1);
3394 QFETCH(int, height);
3395 QFETCH(bool, antialiased);
3397 QImage img(width, height, QImage::Format_ARGB32_Premultiplied);
3401 p.setPen(Qt::NoPen);
3402 p.setBrush(Qt::white);
3404 p.setRenderHint(QPainter::Antialiasing, antialiased);
3406 for (int i = 0; i < img.width(); i += 4) {
3413 for (int i = 4; i < img.height(); i += 4) {
3418 for (int i = 0; i < img.width(); ++i) {
3420 QCOMPARE(img.pixel(i, 0), 0x0U);
3422 QCOMPARE(img.pixel(i, 0), 0xffffffffU);
3425 for (int i = 1; i < img.height(); ++i) {
3427 QCOMPARE(img.pixel(0, i), 0x0U);
3429 QCOMPARE(img.pixel(0, i), 0xffffffffU);
3433 void tst_QPainter::imageScaling_task206785()
3435 QImage src(32, 2, QImage::Format_ARGB32_Premultiplied);
3436 src.fill(0xffffffff);
3438 QImage dst(128, 128, QImage::Format_ARGB32_Premultiplied);
3440 QImage expected(128, 128, QImage::Format_ARGB32_Premultiplied);
3441 expected.fill(0xffffffff);
3443 for (int i = 1; i < 5; ++i) {
3444 qreal scale = i / qreal(5);
3446 dst.fill(0xff000000);
3449 p.scale(dst.width() / qreal(src.width()), scale);
3451 for (int y = 0; y * scale < dst.height(); ++y)
3452 p.drawImage(0, y, src);
3456 QCOMPARE(dst, expected);
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))
3463 uint qHash(const QPoint &point)
3465 return qHash(qMakePair(point.x(), point.y()));
3468 bool verifyOutlineFillConsistency(const QImage &img, QRgb outside, QRgb inside, QRgb outline)
3470 if (img.pixel(img.width() / 2, img.height() / 2) != inside)
3473 int x = img.width() / 2;
3474 int y = img.height() / 2;
3476 while (img.pixel(++x, y) == inside)
3479 if (img.pixel(x, y) != outline)
3482 QQueue<QPoint> discovered;
3483 discovered.enqueue(QPoint(x, y));
3485 QVector<bool> visited(img.width() * img.height());
3486 visited.fill(false);
3488 while (!discovered.isEmpty()) {
3489 QPoint p = discovered.dequeue();
3490 QRgb pixel = img.pixel(p.x(), p.y());
3492 bool &v = visited[p.y() * img.width() + p.x()];
3497 if (pixel == outline) {
3498 FOR_EACH_NEIGHBOR_8 {
3499 QPoint x(p.x() + dx, p.y() + dy);
3500 discovered.enqueue(x);
3503 FOR_EACH_NEIGHBOR_4 {
3504 if ((dx == 0) == (dy == 0))
3506 QRgb neighbor = img.pixel(p.x() + dx, p.y() + dy);
3507 if ((pixel == inside && neighbor == outside) ||
3508 (pixel == outside && neighbor == inside))
3517 #undef FOR_EACH_NEIGHBOR_8
3518 #undef FOR_EACH_NEIGHBOR_4
3520 void tst_QPainter::outlineFillConsistency()
3522 QSKIP("currently broken...", SkipAll);
3525 QImage dst(256, 256, QImage::Format_ARGB32_Premultiplied);
3528 poly << QPointF(5, -100) << QPointF(-70, 20) << QPointF(95, 25);
3531 QBrush brush(Qt::black);
3533 QRgb background = 0xffffffff;
3534 for (int i = 0; i < 360; ++i) {
3535 dst.fill(background);
3538 p.translate(dst.width() / 2, dst.height() / 2);
3540 QPolygonF copy = poly;
3541 for (int j = 0; j < copy.size(); ++j)
3542 copy[j] = QTransform().rotate(i).map(copy[j]);
3546 p.drawPolygon(copy);
3550 if (!verifyOutlineFillConsistency(dst, background, p.brush().color().rgba(), p.pen().color().rgba()))
3551 dst.save(QString("outlineFillConsistency-%1.png").arg(i));
3554 QVERIFY(verifyOutlineFillConsistency(dst, background, brush.color().rgba(), pen.color().rgba()));
3558 void tst_QPainter::drawImage_task217400_data()
3560 QTest::addColumn<QImage::Format>("format");
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;
3570 void tst_QPainter::drawImage_task217400()
3572 QFETCH(QImage::Format, format);
3574 const QImage src = QImage(QString(SRCDIR) + "/task217400.png")
3575 .convertToFormat(format);
3576 QVERIFY(!src.isNull());
3578 QImage expected(src.size(), format);
3580 QPainter p(&expected);
3581 p.fillRect(0, 0, expected.width(), expected.height(), Qt::white);
3582 p.drawImage(0, 0, src);
3585 for (int i = 1; i <= 4; ++i) {
3586 QImage dest(src.width() + i, src.height(), format);
3589 p.fillRect(0, 0, dest.width(), dest.height(), Qt::white);
3590 p.drawImage(i, 0, src);
3593 const QImage result = dest.copy(i, 0, src.width(), src.height());
3596 if (result != expected) {
3598 result.save("result.png");
3599 expected.save("expected.png");
3602 QCOMPARE(result, expected);
3606 void tst_QPainter::drawImage_task258776()
3608 QImage src(16, 16, QImage::Format_RGB888);
3609 QImage dest(33, 33, QImage::Format_RGB888);
3611 dest.fill(0x0000ff);
3613 QPainter painter(&dest);
3614 painter.drawImage(QRectF(0.499, 0.499, 32, 32), src, QRectF(0, 0, 16, 16));
3617 QImage expected(33, 33, QImage::Format_RGB32);
3618 expected.fill(0xff0000);
3620 painter.begin(&expected);
3621 painter.drawImage(QRectF(0, 0, 32, 32), src);
3624 dest = dest.convertToFormat(QImage::Format_RGB32);
3626 dest.save("dest.png");
3627 expected.save("expected.png");
3628 QCOMPARE(dest, expected);
3631 void tst_QPainter::clipRectSaveRestore()
3633 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3637 p.setClipRect(QRect(0, 0, 10, 10));
3639 p.setClipRect(QRect(5, 5, 5, 5), Qt::IntersectClip);
3641 p.fillRect(0, 0, 64, 64, Qt::black);
3644 QCOMPARE(img.pixel(0, 0), QColor(Qt::black).rgba());
3647 void tst_QPainter::clippedImage()
3649 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
3652 QImage src(16, 16, QImage::Format_RGB32);
3653 src.fill(QColor(Qt::red).rgba());
3656 p.setClipRect(QRect(1, 1, 14, 14));
3657 p.drawImage(0, 0, src);
3660 QCOMPARE(img.pixel(0, 0), 0x0U);
3661 QCOMPARE(img.pixel(1, 1), src.pixel(1, 1));
3664 void tst_QPainter::stateResetBetweenQPainters()
3666 QImage img(16, 16, QImage::Format_ARGB32);
3670 p.setCompositionMode(QPainter::CompositionMode_Source);
3671 p.fillRect(0, 0, 16, 16, Qt::red);
3676 p2.fillRect(0, 0, 16, 16, QColor(0, 0, 255, 63));
3679 img.save("foo.png");
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
3686 void tst_QPainter::drawRect_task215378()
3688 QImage img(11, 11, QImage::Format_ARGB32_Premultiplied);
3689 img.fill(QColor(Qt::white).rgba());
3692 p.setPen(QColor(127, 127, 127, 127));
3693 p.drawRect(0, 0, 10, 10);
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));
3701 void tst_QPainter::drawRect_task247505()
3703 QImage a(10, 10, QImage::Format_ARGB32_Premultiplied);
3708 p.setPen(Qt::NoPen);
3709 p.setBrush(Qt::black);
3710 p.drawRect(QRectF(10, 0, -10, 10));
3713 p.setPen(Qt::NoPen);
3714 p.setBrush(Qt::black);
3715 p.drawRect(QRectF(0, 0, 10, 10));
3721 void tst_QPainter::drawImage_data()
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");
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)
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);
3740 QTest::newRow(qPrintable(description)) << (10 + odd_x) << 10 << (20 + odd_width) << 20
3741 << QImage::Format(srcFormat)
3742 << QImage::Format(dstFormat);
3749 bool verifyImage(const QImage &img, int x, int y, int w, int h, uint background)
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);
3767 void tst_QPainter::drawImage()
3773 QFETCH(QImage::Format, srcFormat);
3774 QFETCH(QImage::Format, dstFormat);
3776 QImage dst(40, 40, QImage::Format_RGB32);
3777 dst.fill(0xffffffff);
3779 dst = dst.convertToFormat(dstFormat);
3780 uint background = dst.pixel(0, 0);
3782 QImage src(w, h, QImage::Format_RGB32);
3783 src.fill(0xff000000);
3784 src = src.convertToFormat(srcFormat);
3787 p.drawImage(x, y, src);
3790 QVERIFY(verifyImage(dst, x, y, w, h, background));
3793 void tst_QPainter::imageCoordinateLimit()
3795 QImage img(64, 40000, QImage::Format_MonoLSB);
3797 p.drawText(10, 36000, QLatin1String("foo"));
3798 p.setPen(QPen(Qt::black, 2));
3799 p.drawLine(10, 0, 60, 40000);
3801 p.setRenderHint(QPainter::Antialiasing);
3802 p.drawLine(10, 0, 60, 40000);
3806 void tst_QPainter::imageBlending_data()
3808 QTest::addColumn<QImage::Format>("sourceFormat");
3809 QTest::addColumn<QImage::Format>("destFormat");
3810 QTest::addColumn<int>("error");
3812 int error_rgb565 = ((1<<3) + (1<<2) + (1<<3));
3813 QTest::newRow("rgb565_on_rgb565") << QImage::Format_RGB16
3814 << QImage::Format_RGB16
3816 QTest::newRow("argb8565_on_rgb565") << QImage::Format_ARGB8565_Premultiplied
3817 << QImage::Format_RGB16
3820 QTest::newRow("rgb32_on_rgb565") << QImage::Format_RGB32
3821 << QImage::Format_RGB16
3824 QTest::newRow("argb32pm_on_rgb565") << QImage::Format_ARGB32_Premultiplied
3825 << QImage::Format_RGB16
3829 int diffColor(quint32 ap, quint32 bp)
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);
3836 return qAbs(a) + qAbs(r) + qAbs(g) + qAbs(b);
3839 // this test assumes premultiplied pixels...
3841 void tst_QPainter::imageBlending()
3843 QFETCH(QImage::Format, sourceFormat);
3844 QFETCH(QImage::Format, destFormat);
3849 QImage orig_dest(6, 6, QImage::Format_ARGB32_Premultiplied);
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));
3855 dest = orig_dest.convertToFormat(destFormat);
3857 // An image like this: (r = red, m = magenta, b = light alpha blue, 0 = transparent)
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));
3874 source = orig_source.convertToFormat(sourceFormat);
3876 // An image like this: (0 = transparent, . = green at 0.5 alpha, g = opaque green.
3886 p.drawImage(0, 0, source);
3897 // the g pixels, always green..
3898 QVERIFY(diffColor(dest.pixel(2, 2), 0xff00ff00) <= error); // g
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
3913 QVERIFY(diffColor(dest.pixel(0, 0), 0xff000000) <= 0);
3914 QVERIFY(diffColor(dest.pixel(1, 1), 0xff007f00) <= error);
3918 void tst_QPainter::imageBlending_clipped()
3920 QImage src(20, 20, QImage::Format_RGB16);
3922 p.fillRect(src.rect(), Qt::red);
3925 QImage dst(40, 20, QImage::Format_RGB16);
3927 p.fillRect(dst.rect(), Qt::white);
3930 QImage expected = dst;
3933 p.setClipRect(QRect(23, 0, 20, 20));
3935 // should be completely clipped
3936 p.drawImage(QRectF(3, 0, 20, 20), src);
3939 // dst should be left unchanged
3940 QCOMPARE(dst, expected);
3943 void tst_QPainter::paintOnNullPixmap()
3945 QPixmap pix(16, 16);
3948 QPainter p(&textPixmap);
3949 p.drawPixmap(10, 10, pix);
3952 QPixmap textPixmap2(16,16);
3953 p.begin(&textPixmap2);
3957 void tst_QPainter::checkCompositionMode()
3959 QImage refImage(50,50,QImage::Format_ARGB32);
3960 QPainter painter(&refImage);
3961 painter.fillRect(QRect(0,0,50,50),Qt::blue);
3963 QImage testImage(50,50,QImage::Format_ARGB32);
3964 QPainter p(&testImage);
3965 p.fillRect(QRect(0,0,50,50),Qt::red);
3967 p.setCompositionMode(QPainter::CompositionMode_SourceOut);
3969 p.fillRect(QRect(0,0,50,50),Qt::blue);
3971 QCOMPARE(refImage.pixel(20,20),testImage.pixel(20,20));
3974 static QLinearGradient inverseGradient(QLinearGradient g)
3976 QLinearGradient g2 = g;
3978 QGradientStops stops = g.stops();
3980 QGradientStops inverse;
3981 foreach (QGradientStop stop, stops)
3982 inverse << QGradientStop(1 - stop.first, stop.second);
3984 g2.setStops(inverse);
3988 void tst_QPainter::linearGradientSymmetry_data()
3990 QTest::addColumn<QGradientStops>("stops");
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;
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;
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;
4017 void tst_QPainter::linearGradientSymmetry()
4019 QFETCH(QGradientStops, stops);
4021 QImage a(64, 8, QImage::Format_ARGB32_Premultiplied);
4022 QImage b(64, 8, QImage::Format_ARGB32_Premultiplied);
4027 QLinearGradient gradient(QRectF(b.rect()).topLeft(), QRectF(b.rect()).topRight());
4028 gradient.setStops(stops);
4031 pa.fillRect(a.rect(), gradient);
4035 pb.fillRect(b.rect(), inverseGradient(gradient));
4038 b = b.mirrored(true);
4042 void tst_QPainter::gradientInterpolation()
4044 QImage image(256, 8, QImage::Format_ARGB32_Premultiplied);
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);
4052 painter.begin(&image);
4053 painter.fillRect(image.rect(), gradient);
4056 const QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(3));
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
4065 gradient.setInterpolationMode(QGradient::ComponentInterpolation);
4068 painter.begin(&image);
4069 painter.fillRect(image.rect(), gradient);
4072 for (int i = 1; i < 256; ++i) {
4074 QVERIFY(qRed(line[i]) >= qBlue(line[i])); // red is dominant
4076 QVERIFY(qRed(line[i]) <= qBlue(line[i])); // blue is dominant
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
4085 void tst_QPainter::drawPolygon()
4087 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
4089 QPainterPathStroker stroker;
4090 stroker.setWidth(1.5);
4096 QPolygonF poly = stroker.createStroke(path).toFillPolygon();
4098 img.fill(0xffffffff);
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);
4108 QImage a = img.copy();
4110 img.fill(0xffffffff);
4112 p.setRenderHint(QPainter::Antialiasing);
4113 p.setBrush(Qt::red);
4114 p.setPen(Qt::NoPen);
4115 p.translate(64, 64);
4116 p.drawPolygon(poly);
4118 p.drawPolygon(poly);
4124 void tst_QPainter::inactivePainter()
4126 // This test succeeds if it doesn't segfault.
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);
4138 p.setBackground(QBrush(Qt::blue));
4141 p.setBrush(Qt::red);
4142 p.setBrush(Qt::NoBrush);
4143 p.setBrush(QBrush(Qt::white, Qt::DiagCrossPattern));
4146 p.setBackgroundMode(Qt::OpaqueMode);
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!"));
4152 p.setBrushOrigin(QPointF(12, 34));
4153 p.setBrushOrigin(QPoint(12, 34));
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);
4165 p.combinedTransform();
4167 p.compositionMode();
4168 p.setCompositionMode(QPainter::CompositionMode_Plus);
4172 p.deviceTransform();
4175 p.setFont(QFont(QLatin1String("Times"), 24));
4180 p.layoutDirection();
4181 p.setLayoutDirection(Qt::RightToLeft);
4187 p.setPen(QPen(Qt::red));
4188 p.setPen(Qt::green);
4189 p.setPen(Qt::NoPen);
4192 p.setRenderHint(QPainter::Antialiasing, true);
4193 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
4202 p.viewTransformEnabled();
4203 p.setViewTransformEnabled(true);
4206 p.setViewport(QRect(10, 10, 620, 460));
4209 p.setWindow(QRect(10, 10, 620, 460));
4212 p.setWorldMatrix(QMatrix().translate(43, 21), true);
4213 p.setWorldMatrixEnabled(true);
4216 p.setTransform(QTransform().translate(12, 34), true);
4219 p.setWorldTransform(QTransform().scale(0.5, 0.5), true);
4222 bool testCompositionMode(int src, int dst, int expected, QPainter::CompositionMode op, qreal opacity = 1.0)
4224 // The test image needs to be large enough to test SIMD code
4225 const QSize imageSize(100, 100);
4227 QImage actual(imageSize, QImage::Format_ARGB32_Premultiplied);
4228 actual.fill(QColor(dst, dst, dst).rgb());
4230 QPainter p(&actual);
4231 p.setCompositionMode(op);
4232 p.setOpacity(opacity);
4233 p.fillRect(QRect(QPoint(), imageSize), QColor(src, src, src));
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);
4241 QImage refImage(imageSize, QImage::Format_ARGB32_Premultiplied);
4242 refImage.fill(QColor(expected, expected, expected).rgb());
4243 return actual == refImage;
4247 void tst_QPainter::extendedBlendModes()
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
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));
4346 void tst_QPainter::zeroOpacity()
4348 QImage source(1, 1, QImage::Format_ARGB32_Premultiplied);
4349 source.fill(0xffffffff);
4351 QImage target(1, 1, QImage::Format_RGB32);
4352 target.fill(0xff000000);
4354 QPainter p(&target);
4356 p.drawImage(0, 0, source);
4359 QCOMPARE(target.pixel(0, 0), 0xff000000);
4362 void tst_QPainter::clippingBug()
4364 QImage img(32, 32, QImage::Format_ARGB32_Premultiplied);
4367 QImage expected = img;
4368 QPainter p(&expected);
4369 p.fillRect(1, 1, 30, 30, Qt::red);
4373 path.addRect(1, 1, 30, 30);
4374 path.addRect(1, 1, 30, 30);
4375 path.addRect(1, 1, 30, 30);
4378 p.setClipPath(path);
4379 p.fillRect(0, 0, 32, 32, Qt::red);
4382 QCOMPARE(img, expected);
4385 void tst_QPainter::emptyClip()
4387 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
4389 p.setRenderHints(QPainter::Antialiasing);
4390 p.setClipRect(0, 32, 64, 0);
4391 p.fillRect(0, 0, 64, 64, Qt::white);
4395 path.lineTo(64, 64);
4396 path.lineTo(40, 64);
4397 path.lineTo(40, 80);
4400 p.fillPath(path, Qt::green);
4403 void tst_QPainter::drawImage_1x1()
4405 QImage source(1, 1, QImage::Format_ARGB32_Premultiplied);
4406 source.fill(0xffffffff);
4408 QImage img(32, 32, QImage::Format_ARGB32_Premultiplied);
4409 img.fill(0xff000000);
4411 p.drawImage(QRectF(0.9, 0.9, 32, 32), source);
4414 QImage expected = img;
4415 expected.fill(0xff000000);
4417 p.fillRect(1, 1, 31, 31, Qt::white);
4420 QCOMPARE(img, expected);
4423 void tst_QPainter::taskQT4444_dontOverflowDashOffset()
4429 pen.setStyle(Qt::DashDotLine);
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);
4437 QImage crashImage(QSize(1000, 120), QImage::Format_ARGB32_Premultiplied);
4438 p.begin(&crashImage);
4440 p.drawLines(point, 2);
4443 QVERIFY(true); // Don't crash
4446 void tst_QPainter::painterBegin()
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);
4455 // Painting on null image should fail.
4456 QVERIFY(!p.begin(&nullImage));
4458 // Check that the painter is not messed up by using it on another image.
4459 QVERIFY(p.begin(&rgb32Image));
4462 // If painting on indexed8 image fails, the painter state should still be OK.
4463 if (p.begin(&indexed8Image))
4465 QVERIFY(p.begin(&rgb32Image));
4468 // Try opening a painter on the two different images.
4469 QVERIFY(p.begin(&rgb32Image));
4470 QVERIFY(!p.begin(&argb32Image));
4473 // Try opening two painters on the same image.
4474 QVERIFY(p.begin(&rgb32Image));
4476 QVERIFY(!q.begin(&rgb32Image));
4480 // Try ending an inactive painter.
4484 void tst_QPainter::setPenColor(QPainter& p)
4486 p.setPen(Qt::NoPen);
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);
4496 QCOMPARE(p.pen().color().name(), QString("#ff0000"));
4498 QPen newPen2(p.pen());
4499 newPen2.setStyle(Qt::SolidLine);
4502 QCOMPARE(p.pen().color().name(), QString("#ff0000"));
4505 void tst_QPainter::setPenColorOnImage()
4507 QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
4512 void tst_QPainter::setPenColorOnPixmap()
4514 QPixmap pix(10, 10);
4519 class TestProxy : public QGraphicsProxyWidget
4522 TestProxy() : QGraphicsProxyWidget() {}
4523 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
4525 QGraphicsProxyWidget::paint(painter, option, widget);
4526 deviceTransform = painter->deviceTransform();
4528 QTransform deviceTransform;
4531 class TestWidget : public QWidget
4535 TestWidget() : QWidget(), painted(false) {}
4536 void paintEvent(QPaintEvent *)
4539 deviceTransform = p.deviceTransform();
4540 worldTransform = p.worldTransform();
4543 QTransform deviceTransform;
4544 QTransform worldTransform;
4548 void tst_QPainter::QTBUG5939_attachPainterPrivate()
4550 QWidget *w = new QWidget();
4551 QGraphicsScene *scene = new QGraphicsScene();
4552 QGraphicsView *view = new QGraphicsView(scene, w);
4554 TestProxy *proxy = new TestProxy();
4555 TestWidget *widget = new TestWidget();
4556 proxy->setWidget(widget);
4557 scene->addItem(proxy);
4559 w->resize(scene->sceneRect().size().toSize());
4562 QTRY_VERIFY(widget->painted);
4564 QVERIFY(widget->worldTransform.isIdentity());
4565 QCOMPARE(widget->deviceTransform, proxy->deviceTransform);
4568 void tst_QPainter::clipBoundingRect()
4570 QPixmap pix(500, 500);
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)));
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)));
4590 // Test a basic path + region
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)));
4600 p.setClipRect(0, 0, 500, 500);
4601 p.translate(250, 250);
4602 for (int i=0; i<360; ++i) {
4604 p.setClipRect(-100, -100, 200, 200, Qt::IntersectClip);
4606 QVERIFY(p.clipBoundingRect().contains(QRectF(-100, -100, 200, 200)));
4607 QVERIFY(!p.clipBoundingRect().contains(QRectF(-250, -250, 500, 500)));
4611 void tst_QPainter::drawText_subPixelPositionsInRaster_qtbug5053()
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);
4616 QFontMetricsF fm(qApp->font());
4618 QImage baseLine(fm.width(QChar::fromLatin1('e')), fm.height(), QImage::Format_RGB32);
4619 baseLine.fill(Qt::white);
4621 QPainter p(&baseLine);
4622 p.drawText(0, fm.ascent(), QString::fromLatin1("e"));
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);
4631 QPainter p(&comparison);
4632 p.drawText(QPointF(i / 12.0, fm.ascent()), QString::fromLatin1("e"));
4635 if (comparison != baseLine) {
4636 foundDifferentRasterization = true;
4641 QVERIFY(foundDifferentRasterization);
4644 void tst_QPainter::drawPointScaled()
4646 QImage image(32, 32, QImage::Format_RGB32);
4647 image.fill(0xffffffff);
4655 pen.setColor(Qt::red);
4661 QCOMPARE(image.pixel(16, 16), 0xffff0000);
4664 class GradientProducer : public QThread
4670 void GradientProducer::run()
4672 QImage image(1, 1, QImage::Format_RGB32);
4675 for (int i = 0; i < 1000; ++i) {
4677 g.setColorAt(0, QColor(i % 256, 0, 0));
4678 g.setColorAt(1, Qt::white);
4680 p.fillRect(image.rect(), g);
4684 void tst_QPainter::QTBUG14614_gradientCacheRaceCondition()
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();
4694 void tst_QPainter::drawTextOpacity()
4696 QImage image(32, 32, QImage::Format_RGB32);
4697 image.fill(0xffffffff);
4700 p.setPen(QColor("#6F6F6F"));
4702 p.drawText(5, 30, QLatin1String("Qt"));
4705 QImage copy = image;
4706 image.fill(0xffffffff);
4709 p.setPen(QColor("#6F6F6F"));
4710 p.drawLine(-10, -10, -1, -1);
4712 p.drawText(5, 30, QLatin1String("Qt"));
4715 QCOMPARE(image, copy);
4718 void tst_QPainter::QTBUG17053_zeroDashPattern()
4720 QImage image(32, 32, QImage::Format_RGB32);
4721 image.fill(0xffffffff);
4723 QImage original = image;
4725 QVector<qreal> pattern;
4726 pattern << qreal(0) << qreal(0);
4729 QPen pen(Qt::black, 2.0);
4730 pen.setDashPattern(pattern);
4733 p.drawLine(0, 0, image.width(), image.height());
4735 QCOMPARE(image, original);
4738 QTEST_MAIN(tst_QPainter)
4740 #include "tst_qpainter.moc"