1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
46 #include <qdrawutil.h>
47 #include <qapplication.h>
50 #include <qfontmetrics.h>
55 #if !defined(Q_OS_WINCE)
61 #include <qpaintengine.h>
63 #include <qdesktopwidget.h>
76 #include <qgraphicsview.h>
77 #include <qgraphicsscene.h>
78 #include <qgraphicsproxywidget.h>
81 #include <qfontdatabase.h>
83 Q_DECLARE_METATYPE(QGradientStops)
84 Q_DECLARE_METATYPE(QLine)
85 Q_DECLARE_METATYPE(QRect)
86 Q_DECLARE_METATYPE(QSize)
87 Q_DECLARE_METATYPE(QPoint)
88 Q_DECLARE_METATYPE(QPainterPath)
90 class tst_QPainter : public QObject
96 virtual ~tst_QPainter();
102 void cleanupTestCase();
105 #ifndef QT_NO_WIDGETS
106 void drawPixmap_comp_data();
107 void drawPixmap_comp();
109 void saveAndRestore_data();
110 void saveAndRestore();
112 #ifndef QT_NO_WIDGETS
113 void drawBorderPixmap();
115 void drawPixmapFragments();
117 void drawLine_data();
119 void drawLine_clipped();
120 void drawLine_task121143();
121 void drawLine_task216948();
123 void drawLine_task190634();
124 void drawLine_task229459();
125 void drawLine_task234891();
127 void drawRect_data() { fillData(); }
136 void drawEllipse_data();
138 void drawClippedEllipse_data();
139 void drawClippedEllipse();
141 void drawPath_data();
146 void drawRoundRect_data() { fillData(); }
147 void drawRoundRect();
149 void qimageFormats_data();
150 void qimageFormats();
151 void textOnTransparentImage();
153 #ifndef QT_NO_WIDGETS
159 void combinedMatrix();
162 void disableEnableClipping();
164 void setEqualClipRegionAndPath_data();
165 void setEqualClipRegionAndPath();
167 void clipRectSaveRestore();
169 void clippedFillPath_data();
170 void clippedFillPath();
171 void clippedLines_data();
173 void clippedPolygon_data();
174 void clippedPolygon();
178 void clipBoundingRect();
180 void setOpacity_data();
183 void drawhelper_blend_untransformed_data();
184 void drawhelper_blend_untransformed();
185 void drawhelper_blend_tiled_untransformed_data();
186 void drawhelper_blend_tiled_untransformed();
188 void porterDuff_warning();
190 void drawhelper_blend_color();
192 #ifndef QT_NO_WIDGETS
193 void childWidgetViewport();
196 void fillRect_objectBoundingModeGradient();
197 void fillRect_stretchToDeviceMode();
200 void linearGradientSymmetry_data();
201 void linearGradientSymmetry();
202 void gradientInterpolation();
204 void fpe_pixmapTransform();
205 void fpe_zeroLengthLines();
206 void fpe_divByZero();
208 void fpe_steepSlopes_data();
209 void fpe_steepSlopes();
210 void fpe_rasterizeLine_task232012();
212 void fpe_radialGradients();
214 void rasterizer_asserts();
215 void rasterizer_negativeCoords();
217 void blendOverFlow_data();
218 void blendOverFlow();
220 void largeImagePainting_data();
221 void largeImagePainting();
223 void imageScaling_task206785();
225 void outlineFillConsistency();
227 void drawImage_task217400_data();
228 void drawImage_task217400();
229 void drawImage_1x1();
230 void drawImage_task258776();
231 void drawRect_task215378();
232 void drawRect_task247505();
234 void drawText_subPixelPositionsInRaster_qtbug5053();
236 void drawImage_data();
241 void stateResetBetweenQPainters();
243 void imageCoordinateLimit();
244 void imageBlending_data();
245 void imageBlending();
246 void imageBlending_clipped();
248 void paintOnNullPixmap();
249 void checkCompositionMode();
253 void inactivePainter();
255 void extendedBlendModes();
261 void taskQT4444_dontOverflowDashOffset();
264 void setPenColorOnImage();
265 void setPenColorOnPixmap();
267 #ifndef QT_NO_WIDGETS
268 void QTBUG5939_attachPainterPrivate();
271 void drawPointScaled();
273 void QTBUG14614_gradientCacheRaceCondition();
274 void drawTextOpacity();
276 void QTBUG17053_zeroDashPattern();
278 void drawTextOutsideGuiThread();
280 void drawTextWithComplexBrush();
281 void QTBUG26013_squareCapStroke();
282 void QTBUG25153_drawLine();
286 void setPenColor(QPainter& p);
287 QColor baseColor( int k, int intensity=255 );
288 QImage getResImage( const QString &dir, const QString &addition, const QString &extension );
289 QBitmap getBitmap( const QString &dir, const QString &filename, bool mask );
292 // Testing get/set functions
293 void tst_QPainter::getSetCheck()
295 QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
298 // CompositionMode QPainter::compositionMode()
299 // void QPainter::setCompositionMode(CompositionMode)
300 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceOver));
301 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceOver), obj1.compositionMode());
302 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOver));
303 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOver), obj1.compositionMode());
304 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Clear));
305 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Clear), obj1.compositionMode());
306 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Source));
307 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Source), obj1.compositionMode());
308 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Destination));
309 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Destination), obj1.compositionMode());
310 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceIn));
311 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceIn), obj1.compositionMode());
312 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationIn));
313 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationIn), obj1.compositionMode());
314 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceOut));
315 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceOut), obj1.compositionMode());
316 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOut));
317 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationOut), obj1.compositionMode());
318 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_SourceAtop));
319 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_SourceAtop), obj1.compositionMode());
320 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_DestinationAtop));
321 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_DestinationAtop), obj1.compositionMode());
322 obj1.setCompositionMode(QPainter::CompositionMode(QPainter::CompositionMode_Xor));
323 QCOMPARE(QPainter::CompositionMode(QPainter::CompositionMode_Xor), obj1.compositionMode());
325 // const QPen & QPainter::pen()
326 // void QPainter::setPen(const QPen &)
329 QCOMPARE(var3, obj1.pen());
331 QCOMPARE(QPen(), obj1.pen());
333 // const QBrush & QPainter::brush()
334 // void QPainter::setBrush(const QBrush &)
335 QBrush var4(Qt::red);
337 QCOMPARE(var4, obj1.brush());
338 obj1.setBrush(QBrush());
339 QCOMPARE(QBrush(), obj1.brush());
341 // const QBrush & QPainter::background()
342 // void QPainter::setBackground(const QBrush &)
343 QBrush var5(Qt::yellow);
344 obj1.setBackground(var5);
345 QCOMPARE(var5, obj1.background());
346 obj1.setBackground(QBrush());
347 QCOMPARE(QBrush(), obj1.background());
349 // bool QPainter::matrixEnabled()
350 // void QPainter::setMatrixEnabled(bool)
351 obj1.setMatrixEnabled(false);
352 QCOMPARE(false, obj1.matrixEnabled());
353 obj1.setMatrixEnabled(true);
354 QCOMPARE(true, obj1.matrixEnabled());
356 // bool QPainter::viewTransformEnabled()
357 // void QPainter::setViewTransformEnabled(bool)
358 obj1.setViewTransformEnabled(false);
359 QCOMPARE(false, obj1.viewTransformEnabled());
360 obj1.setViewTransformEnabled(true);
361 QCOMPARE(true, obj1.viewTransformEnabled());
364 Q_DECLARE_METATYPE(QPixmap)
365 Q_DECLARE_METATYPE(QPolygon)
366 Q_DECLARE_METATYPE(QBrush)
367 Q_DECLARE_METATYPE(QPen)
368 Q_DECLARE_METATYPE(QFont)
369 Q_DECLARE_METATYPE(QColor)
370 Q_DECLARE_METATYPE(QRegion)
372 tst_QPainter::tst_QPainter()
374 // QtTestCase sets this to false, but this turns off alpha pixmaps on Unix.
375 QGuiApplication::setDesktopSettingsAware(true);
378 tst_QPainter::~tst_QPainter()
382 void tst_QPainter::init()
386 void tst_QPainter::cleanup()
390 void tst_QPainter::cleanupTestCase()
392 QFile::remove(QLatin1String("dest.png"));
393 QFile::remove(QLatin1String("expected.png"));
394 QFile::remove(QLatin1String("foo.png"));
397 static const char* const maskSource_data[] = {
419 static const char* const maskResult_data[] = {
442 #ifndef QT_NO_WIDGETS
443 void tst_QPainter::drawPixmap_comp_data()
445 if (qApp->desktop()->depth() < 24)
446 QSKIP("Test only works on 32 bit displays");
448 QTest::addColumn<uint>("dest");
449 QTest::addColumn<uint>("source");
451 QTest::newRow("0% on 0%, 1") << 0x00000000u<< 0x00000000u;
452 QTest::newRow("0% on 0%, 2") << 0x00007fffu << 0x00ff007fu;
454 QTest::newRow("50% on a=0%") << 0x00000000u << 0x7fff0000u;
455 QTest::newRow("50% on a=50%") << 0x7f000000u << 0x7fff0000u;
456 QTest::newRow("50% on deadbeef") << 0xdeafbeefu << 0x7fff0000u;
457 QTest::newRow("deadbeef on a=0%") << 0x00000000u << 0xdeadbeefu;
458 QTest::newRow("deadbeef on a=50%") << 0x7f000000u << 0xdeadbeefu;
459 QTest::newRow("50% blue on 50% red") << 0x7fff0000u << 0x7f0000ffu;
460 QTest::newRow("50% blue on 50% green") << 0x7f00ff00u << 0x7f0000ffu;
461 QTest::newRow("50% red on 50% green") << 0x7f00ff00u << 0x7fff0000u;
462 QTest::newRow("0% on 50%") << 0x7fff00ffu << 0x00ffffffu;
463 QTest::newRow("100% on deadbeef") << 0xdeafbeefu << 0xffabcdefu;
464 QTest::newRow("100% on a=0%") << 0x00000000u << 0xffabcdefu;
467 QRgb qt_compose_alpha(QRgb source, QRgb dest)
469 int r1 = qRed(dest), g1 = qGreen(dest), b1 = qBlue(dest), a1 = qAlpha(dest);
470 int r2 = qRed(source), g2 = qGreen(source), b2 = qBlue(source), a2 = qAlpha(source);
472 int alpha = qMin(a2 + ((255 - a2) * a1 + 127) / 255, 255);
474 return qRgba(0, 0, 0, 0);
477 qMin((r2 * a2 + (255 - a2) * r1 * a1 / 255) / alpha, 255),
478 qMin((g2 * a2 + (255 - a2) * g1 * a1 / 255) / alpha, 255),
479 qMin((b2 * a2 + (255 - a2) * b1 * a1 / 255) / alpha, 255),
483 /* Tests that drawing masked pixmaps works
485 void tst_QPainter::drawPixmap_comp()
488 QSKIP("Mac has other ideas about alpha composition");
491 QFETCH(uint, source);
493 QRgb expected = qt_compose_alpha(source, dest);
495 QColor c1(qRed(dest), qGreen(dest), qBlue(dest), qAlpha(dest));
496 QColor c2(qRed(source), qGreen(source), qBlue(source), qAlpha(source));
498 QPixmap destPm(10, 10), srcPm(10, 10);
502 #if defined(Q_WS_X11)
503 if (!destPm.x11PictureHandle())
504 QSKIP("Requires XRender support");
508 p.drawPixmap(0, 0, srcPm);
511 QImage result = destPm.toImage().convertToFormat(QImage::Format_ARGB32);
512 bool different = false;
513 for (int y=0; y<result.height(); ++y)
514 for (int x=0; x<result.width(); ++x) {
516 if (qAlpha(expected) == 0) {
517 diff = qAlpha(result.pixel(x, y)) != 0;
519 // Compensate for possible roundoff / platform fudge
521 QRgb pix = result.pixel(x, y);
522 diff = (qAbs(qRed(pix) - qRed(expected)) > off)
523 || (qAbs(qGreen(pix) - qGreen(expected)) > off)
524 || (qAbs(qBlue(pix) - qBlue(expected)) > off)
525 || (qAbs(qAlpha(pix) - qAlpha(expected)) > off);
527 if (diff && !different)
528 qDebug( "Different at %d,%d pixel [%d,%d,%d,%d] expected [%d,%d,%d,%d]", x, y,
529 qRed(result.pixel(x, y)), qGreen(result.pixel(x, y)),
530 qBlue(result.pixel(x, y)), qAlpha(result.pixel(x, y)),
531 qRed(expected), qGreen(expected), qBlue(expected), qAlpha(expected));
539 void tst_QPainter::saveAndRestore_data()
541 QTest::addColumn<QFont>("font");
542 QTest::addColumn<QPen>("pen");
543 QTest::addColumn<QBrush>("brush");
544 QTest::addColumn<QColor>("backgroundColor");
545 QTest::addColumn<int>("backgroundMode");
546 QTest::addColumn<QPoint>("brushOrigin");
547 QTest::addColumn<QRegion>("clipRegion");
548 QTest::addColumn<QRect>("window");
549 QTest::addColumn<QRect>("viewport");
551 QPixmap pixmap(1, 1);
553 QFont font = p.font();
555 QBrush brush = p.brush();
556 QColor backgroundColor = p.background().color();
557 Qt::BGMode backgroundMode = p.backgroundMode();
558 QPoint brushOrigin = p.brushOrigin();
559 QRegion clipRegion = p.clipRegion();
560 QRect window = p.window();
561 QRect viewport = p.viewport();
563 QTest::newRow("Original") << font << pen << brush << backgroundColor << int(backgroundMode)
564 << brushOrigin << clipRegion << window << viewport;
567 font2.setPointSize( 24 );
568 QTest::newRow("Modified font.pointSize, brush, backgroundColor, backgroundMode")
569 << font2 << pen << QBrush(Qt::red) << QColor(Qt::blue) << int(Qt::TransparentMode)
570 << brushOrigin << clipRegion << window << viewport;
573 font2.setPixelSize( 20 );
574 QTest::newRow("Modified font.pixelSize, brushOrigin, pos")
575 << font2 << pen << brush << backgroundColor << int(backgroundMode)
576 << QPoint( 50, 32 ) << clipRegion << window << viewport;
578 QTest::newRow("Modified clipRegion, window, viewport")
579 << font << pen << brush << backgroundColor << int(backgroundMode)
580 << brushOrigin << clipRegion.subtracted(QRect(10,10,50,30))
581 << QRect(-500, -500, 500, 500 ) << QRect( 0, 0, 50, 50 );
584 void tst_QPainter::saveAndRestore()
586 QFETCH( QFont, font );
588 QFETCH( QBrush, brush );
589 QFETCH( QColor, backgroundColor );
590 QFETCH( int, backgroundMode );
591 QFETCH( QPoint, brushOrigin );
592 QFETCH( QRegion, clipRegion );
593 QFETCH( QRect, window );
594 QFETCH( QRect, viewport );
596 QPixmap pixmap(1, 1);
597 QPainter painter(&pixmap);
599 QFont font_org = painter.font();
600 QPen pen_org = painter.pen();
601 QBrush brush_org = painter.brush();
602 QColor backgroundColor_org = painter.background().color();
603 Qt::BGMode backgroundMode_org = painter.backgroundMode();
604 QPoint brushOrigin_org = painter.brushOrigin();
605 QRegion clipRegion_org = painter.clipRegion();
606 QRect window_org = painter.window();
607 QRect viewport_org = painter.viewport();
610 painter.setFont( font );
611 painter.setPen( QPen(pen) );
612 painter.setBrush( brush );
613 painter.setBackground( backgroundColor );
614 painter.setBackgroundMode( (Qt::BGMode)backgroundMode );
615 painter.setBrushOrigin( brushOrigin );
616 painter.setClipRegion( clipRegion );
617 painter.setWindow( window );
618 painter.setViewport( viewport );
621 QCOMPARE( painter.font(), font_org );
622 QCOMPARE( painter.font().pointSize(), font_org.pointSize() );
623 QCOMPARE( painter.font().pixelSize(), font_org.pixelSize() );
624 QCOMPARE( painter.pen(), pen_org );
625 QCOMPARE( painter.brush(), brush_org );
626 QCOMPARE( painter.background().color(), backgroundColor_org );
627 QCOMPARE( painter.backgroundMode(), backgroundMode_org );
628 QCOMPARE( painter.brushOrigin(), brushOrigin_org );
629 QCOMPARE( painter.clipRegion(), clipRegion_org );
630 QCOMPARE( painter.window(), window_org );
631 QCOMPARE( painter.viewport(), viewport_org );
638 QColor tst_QPainter::baseColor( int k, int intensity )
640 int r = ( k & 1 ) * intensity;
641 int g = ( (k>>1) & 1 ) * intensity;
642 int b = ( (k>>2) & 1 ) * intensity;
643 return QColor( r, g, b );
646 QImage tst_QPainter::getResImage( const QString &dir, const QString &addition, const QString &extension )
649 QString resFilename = dir + QString( "/res_%1." ).arg( addition ) + extension;
650 if ( !res.load( resFilename ) ) {
651 QWARN(QString("Could not load result data %s %1").arg(resFilename).toLatin1());
657 QBitmap tst_QPainter::getBitmap( const QString &dir, const QString &filename, bool mask )
660 QString bmFilename = dir + QString( "/%1.xbm" ).arg( filename );
661 if ( !bm.load( bmFilename ) ) {
662 QWARN(QString("Could not load bitmap '%1'").arg(bmFilename).toLatin1());
667 QString maskFilename = dir + QString( "/%1-mask.xbm" ).arg( filename );
668 if ( !mask.load( maskFilename ) ) {
669 QWARN(QString("Could not load mask '%1'").arg(maskFilename).toLatin1());
677 static int getPaintedPixels(const QImage &image, const QColor &background)
679 uint color = background.rgba();
683 for (int y = 0; y < image.height(); ++y)
684 for (int x = 0; x < image.width(); ++x)
685 if (image.pixel(x, y) != color)
691 static QRect getPaintedSize(const QImage &image, const QColor &background)
693 // not the fastest but at least it works..
694 int xmin = image.width() + 1;
696 int ymin = image.height() +1;
699 uint color = background.rgba();
701 for ( int y = 0; y < image.height(); ++y ) {
702 for ( int x = 0; x < image.width(); ++x ) {
703 QRgb pixel = image.pixel( x, y );
704 if ( pixel != color && x < xmin )
706 if ( pixel != color && x > xmax )
708 if ( pixel != color && y < ymin )
710 if ( pixel != color && y > ymax )
715 return QRect(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
718 static QRect getPaintedSize(const QPixmap &pm, const QColor &background)
720 return getPaintedSize(pm.toImage(), background);
723 #ifndef QT_NO_WIDGETS
724 void tst_QPainter::initFrom()
726 QWidget *widget = new QWidget();
727 QPalette pal = widget->palette();
728 pal.setColor(QPalette::Foreground, QColor(255, 0, 0));
729 pal.setBrush(QPalette::Background, QColor(0, 255, 0));
730 widget->setPalette(pal);
732 QFont font = widget->font();
733 font.setPointSize(26);
734 font.setItalic(true);
735 widget->setFont(font);
737 QPixmap pm(100, 100);
741 QCOMPARE(p.font(), font);
742 QCOMPARE(p.pen().color(), pal.color(QPalette::Foreground));
743 QCOMPARE(p.background(), pal.background());
748 void tst_QPainter::drawBorderPixmap()
751 src.fill(Qt::transparent);
753 QImage pm(200,200,QImage::Format_RGB32);
755 p.setTransform(QTransform(-1,0,0,-1,173.5,153.5));
756 qDrawBorderPixmap(&p, QRect(0,0,75,105), QMargins(39,39,39,39), src, QRect(0,0,79,79), QMargins(39,39,39,39),
757 QTileRules(Qt::StretchTile,Qt::StretchTile), 0);
761 void tst_QPainter::drawPixmapFragments()
763 QPixmap origPixmap(20, 20);
764 QPixmap resPixmap(20, 20);
765 QPainter::PixmapFragment fragments[4] = { {15, 15, 0, 0, 10, 10, 1, 1, 0, 1},
766 { 5, 15, 10, 0, 10, 10, 1, 1, 0, 1},
767 {15, 5, 0, 10, 10, 10, 1, 1, 0, 1},
768 { 5, 5, 10, 10, 10, 10, 1, 1, 0, 1} };
770 QPainter p(&origPixmap);
771 p.fillRect(0, 0, 10, 10, Qt::red);
772 p.fillRect(10, 0, 10, 10, Qt::green);
773 p.fillRect(0, 10, 10, 10, Qt::blue);
774 p.fillRect(10, 10, 10, 10, Qt::yellow);
777 QPainter p(&resPixmap);
778 p.drawPixmapFragments(fragments, 4, origPixmap);
781 QImage origImage = origPixmap.toImage().convertToFormat(QImage::Format_ARGB32);
782 QImage resImage = resPixmap.toImage().convertToFormat(QImage::Format_ARGB32);
784 QVERIFY(resImage.size() == resPixmap.size());
785 QVERIFY(resImage.pixel(5, 5) == origImage.pixel(15, 15));
786 QVERIFY(resImage.pixel(5, 15) == origImage.pixel(15, 5));
787 QVERIFY(resImage.pixel(15, 5) == origImage.pixel(5, 15));
788 QVERIFY(resImage.pixel(15, 15) == origImage.pixel(5, 5));
791 QPainter::PixmapFragment fragment = QPainter::PixmapFragment::create(QPointF(20, 20), QRectF(30, 30, 2, 2));
792 QVERIFY(fragment.x == 20);
793 QVERIFY(fragment.y == 20);
794 QVERIFY(fragment.sourceLeft == 30);
795 QVERIFY(fragment.sourceTop == 30);
796 QVERIFY(fragment.width == 2);
797 QVERIFY(fragment.height == 2);
798 QVERIFY(fragment.scaleX == 1);
799 QVERIFY(fragment.scaleY == 1);
800 QVERIFY(fragment.rotation == 0);
801 QVERIFY(fragment.opacity == 1);
804 void tst_QPainter::drawLine_data()
806 QTest::addColumn<QLine>("line");
808 QTest::newRow("0-45") << QLine(0, 20, 100, 0);
809 QTest::newRow("45-90") << QLine(0, 100, 20, 0);
810 QTest::newRow("90-135") << QLine(20, 100, 0, 0);
811 QTest::newRow("135-180") << QLine(100, 20, 0, 0);
812 QTest::newRow("180-225") << QLine(100, 0, 0, 20);
813 QTest::newRow("225-270") << QLine(20, 0, 0, 100);
814 QTest::newRow("270-315") << QLine(0, 0, 20, 100);
815 QTest::newRow("315-360") << QLine(0, 0, 100, 20);
818 void tst_QPainter::drawLine()
820 const int offset = 5;
821 const int epsilon = 1; // allow for one pixel difference
825 QPixmap pixmapUnclipped(qMin(line.x1(), line.x2())
826 + 2*offset + qAbs(line.dx()),
827 qMin(line.y1(), line.y2())
828 + 2*offset + qAbs(line.dy()));
831 pixmapUnclipped.fill(Qt::white);
832 QPainter p(&pixmapUnclipped);
833 p.setRenderHint(QPainter::Qt4CompatiblePainting);
834 p.translate(offset, offset);
835 p.setPen(QPen(Qt::black));
839 const QRect painted = getPaintedSize(pixmapUnclipped, Qt::white);
842 l.translate(offset, offset);
843 QVERIFY(qAbs(painted.width() - qAbs(l.dx())) <= epsilon);
844 QVERIFY(qAbs(painted.height() - qAbs(l.dy())) <= epsilon);
845 QVERIFY(qAbs(painted.top() - qMin(l.y1(), l.y2())) <= epsilon);
846 QVERIFY(qAbs(painted.left() - qMin(l.x1(), l.x2())) <= epsilon);
847 QVERIFY(qAbs(painted.bottom() - qMax(l.y1(), l.y2())) <= epsilon);
848 QVERIFY(qAbs(painted.right() - qMax(l.x1(), l.x2())) <= epsilon);
851 QPixmap pixmapClipped(qMin(line.x1(), line.x2())
852 + 2*offset + qAbs(line.dx()),
853 qMin(line.y1(), line.y2())
854 + 2*offset + qAbs(line.dy()));
856 const QRect clip = QRect(line.p1(), line.p2()).normalized();
858 pixmapClipped.fill(Qt::white);
859 QPainter p(&pixmapClipped);
860 p.setRenderHint(QPainter::Qt4CompatiblePainting);
861 p.translate(offset, offset);
863 p.setPen(QPen(Qt::black));
868 const QImage unclipped = pixmapUnclipped.toImage();
869 const QImage clipped = pixmapClipped.toImage();
870 QCOMPARE(unclipped, clipped);
873 void tst_QPainter::drawLine_clipped()
875 QImage image(16, 1, QImage::Format_ARGB32_Premultiplied);
879 p.setPen(QPen(Qt::black, 10));
881 // this should fill the whole image
882 p.drawLine(-1, -1, 17, 1);
885 for (int x = 0; x < 16; ++x)
886 QCOMPARE(image.pixel(x, 0), 0xff000000);
889 void tst_QPainter::drawLine_task121143()
893 QImage image(5, 5, QImage::Format_ARGB32_Premultiplied);
894 image.fill(0xffffffff);
897 p.setRenderHint(QPainter::Qt4CompatiblePainting);
898 p.drawLine(QLine(0, 0+4, 0+4, 0));
901 QImage expected(5, 5, QImage::Format_ARGB32_Premultiplied);
902 expected.fill(0xffffffff);
903 for (int x = 0; x < 5; ++x)
904 expected.setPixel(x, 5-x-1, pen.color().rgb());
906 QCOMPARE(image, expected);
909 void tst_QPainter::drawLine_task190634()
911 QPen pen(Qt::black, 3);
913 QImage image(32, 32, QImage::Format_ARGB32_Premultiplied);
915 p.fillRect(0, 0, image.width(), image.height(), Qt::white);
918 p.drawLine(QLineF(2, -1.6, 10, -1.6));
921 const uint *data = reinterpret_cast<uint *>(image.bits());
923 for (int i = 0; i < image.width() * image.height(); ++i)
924 QCOMPARE(data[i], 0xffffffff);
927 p.fillRect(0, 0, image.width(), image.height(), Qt::white);
930 p.drawLine(QLineF(-1.6, 2, -1.6, 10));
933 data = reinterpret_cast<uint *>(image.bits());
935 for (int i = 0; i < image.width() * image.height(); ++i)
936 QCOMPARE(data[i], 0xffffffff);
939 p.fillRect(0, 0, image.width(), image.height(), Qt::white);
942 p.drawLine( QPoint(2,-2), QPoint(3,-5) );
945 data = reinterpret_cast<uint *>(image.bits());
947 for (int i = 0; i < image.width() * image.height(); ++i)
948 QCOMPARE(data[i], 0xffffffff);
951 void tst_QPainter::drawLine_task229459()
953 QImage image(32, 32, QImage::Format_ARGB32_Premultiplied);
955 QPen pen(Qt::black, 64);
959 p.drawLine(-8, -8, 10000000, 10000000);
962 QImage expected = image;
963 expected.fill(0xff000000);
965 QCOMPARE(image, expected);
968 void tst_QPainter::drawLine_task234891()
970 QImage img(100, 1000, QImage::Format_ARGB32_Premultiplied);
972 QImage expected = img;
975 p.setPen(QPen(QBrush(QColor(255,0,0)), 6));
976 p.drawLine(QPointF(25000,100),QPointF(30000,105));
978 p.setPen(QPen(QBrush(QColor(0,255,0)), 6));
979 p.drawLine(QPointF(30000,150),QPointF(35000,155));
981 p.setPen(QPen(QBrush(QColor(0,0,255)), 6));
982 p.drawLine(QPointF(65000,200),QPointF(66000,205));
984 QCOMPARE(expected, img);
987 void tst_QPainter::drawLine_task216948()
989 QImage img(1, 10, QImage::Format_ARGB32_Premultiplied);
993 QLine line(10, 0, 10, 10);
998 for (int i = 0; i < img.height(); ++i)
999 QCOMPARE(img.pixel(0, i), QColor(Qt::black).rgba());
1002 void tst_QPainter::drawRect()
1004 QFETCH(QRect, rect);
1005 QFETCH(bool, usePen);
1007 QPixmap pixmap(rect.x() + rect.width() + 10,
1008 rect.y() + rect.height() + 10);
1010 pixmap.fill(Qt::white);
1011 QPainter p(&pixmap);
1012 p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1013 p.setBrush(Qt::black);
1017 int increment = usePen ? 1 : 0;
1019 const QRect painted = getPaintedSize(pixmap, Qt::white);
1020 QCOMPARE(painted.width(), rect.width() + increment);
1021 QCOMPARE(painted.height(), rect.height() + increment);
1025 void tst_QPainter::drawRect2()
1027 QImage image(64, 64, QImage::Format_ARGB32_Premultiplied);
1029 image.fill(0xffffffff);
1031 QTransform transform(0.368567, 0, 0, 0, 0.368567, 0, 0.0289, 0.0289, 1);
1034 p.setRenderHint(QPainter::Qt4CompatiblePainting);
1035 p.setTransform(transform);
1036 p.setBrush(Qt::red);
1037 p.setPen(Qt::NoPen);
1038 p.drawRect(QRect(14, 14, 39, 39));
1041 QRect fill = getPaintedSize(image, Qt::white);
1042 image.fill(0xffffffff);
1045 p.setRenderHint(QPainter::Qt4CompatiblePainting);
1046 p.setTransform(transform);
1047 p.drawRect(QRect(14, 14, 39, 39));
1050 QRect stroke = getPaintedSize(image, Qt::white);
1051 QCOMPARE(stroke.adjusted(1, 1, 0, 0), fill.adjusted(0, 0, 1, 1));
1055 void tst_QPainter::fillRect()
1057 QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
1058 image.fill(QColor(0, 0, 0, 0).rgba());
1062 p.fillRect(0, 0, 100, 100, QColor(255, 0, 0, 127));
1064 // pixmap.save("bla1.png", "PNG");
1065 QCOMPARE(getPaintedSize(image, QColor(0, 0, 0, 0)),
1066 QRect(0, 0, 100, 100));
1067 QCOMPARE(getPaintedSize(image, QColor(127, 0, 0, 127)).isValid(),
1070 p.setCompositionMode(QPainter::CompositionMode_SourceIn);
1071 p.fillRect(50, 0, 50, 100, QColor(0, 0, 255, 255));
1073 QCOMPARE(getPaintedSize(image, QColor(127, 0, 0, 127)),
1074 QRect(50, 0, 50, 100));
1075 QCOMPARE(getPaintedSize(image, QColor(0, 0, 127, 127)),
1076 QRect(0, 0, 50, 100));
1079 void tst_QPainter::fillRect2()
1081 QRgb background = 0x0;
1083 QImage img(1, 20, QImage::Format_ARGB32_Premultiplied);
1084 img.fill(background);
1088 QRectF rect(0, 1, 1.2, 18);
1089 p.fillRect(rect, Qt::black);
1093 QCOMPARE(img.pixel(0, 0), background);
1094 QCOMPARE(img.pixel(0, img.height() - 1), background);
1096 QCOMPARE(img.pixel(0, 1), img.pixel(0, 2));
1097 QCOMPARE(img.pixel(0, img.height() - 2), img.pixel(0, img.height() - 3));
1100 void tst_QPainter::fillRect3()
1102 QImage img(1, 1, QImage::Format_ARGB32_Premultiplied);
1103 img.fill(QColor(Qt::black).rgba());
1106 p.setCompositionMode(QPainter::CompositionMode_Source);
1107 p.fillRect(img.rect(), Qt::transparent);
1110 QCOMPARE(img.pixel(0, 0), 0U);
1113 void tst_QPainter::fillRect4()
1115 QImage image(100, 1, QImage::Format_ARGB32_Premultiplied);
1118 QImage expected = image;
1119 expected.fill(0xffffffff);
1123 p.setPen(Qt::NoPen);
1125 for (int i = 0; i < 33; ++i)
1126 p.fillRect(QRectF(3 * i, 0, 3, 1), Qt::white);
1130 QCOMPARE(image, expected);
1133 void tst_QPainter::drawPath_data()
1135 QTest::addColumn<QPainterPath>("path");
1136 QTest::addColumn<QRect>("expectedBounds");
1137 QTest::addColumn<int>("expectedPixels");
1141 p.addRect(2, 2, 10, 10);
1142 QTest::newRow("int-aligned rect") << p << QRect(2, 2, 10, 10) << 10 * 10;
1147 p.addRect(2.25, 2.25, 10, 10);
1148 QTest::newRow("non-aligned rect") << p << QRect(3, 3, 10, 10) << 10 * 10;
1153 p.addRect(2.25, 2.25, 10.5, 10.5);
1154 QTest::newRow("non-aligned rect 2") << p << QRect(3, 3, 10, 10) << 10 * 10;
1159 p.addRect(2.5, 2.5, 10, 10);
1160 QTest::newRow("non-aligned rect 3") << p << QRect(3, 3, 10, 10) << 10 * 10;
1165 p.addRect(2, 2, 10, 10);
1166 p.addRect(4, 4, 6, 6);
1167 QTest::newRow("rect-in-rect") << p << QRect(2, 2, 10, 10) << 10 * 10 - 6 * 6;
1172 p.addRect(2, 2, 10, 10);
1173 p.addRect(4, 4, 6, 6);
1174 p.addRect(6, 6, 2, 2);
1175 QTest::newRow("rect-in-rect-in-rect") << p << QRect(2, 2, 10, 10) << 10 * 10 - 6 * 6 + 2 * 2;
1179 void tst_QPainter::drawPath()
1181 QFETCH(QPainterPath, path);
1182 QFETCH(QRect, expectedBounds);
1183 QFETCH(int, expectedPixels);
1185 const int offset = 2;
1187 QImage image(expectedBounds.width() + 2 * offset, expectedBounds.height() + 2 * offset,
1188 QImage::Format_ARGB32_Premultiplied);
1189 image.fill(QColor(Qt::white).rgb());
1192 p.setRenderHint(QPainter::Qt4CompatiblePainting);
1193 p.setPen(Qt::NoPen);
1194 p.setBrush(Qt::black);
1195 p.translate(offset - expectedBounds.left(), offset - expectedBounds.top());
1199 const QRect paintedBounds = getPaintedSize(image, Qt::white);
1201 QCOMPARE(paintedBounds.x(), offset);
1202 QCOMPARE(paintedBounds.y(), offset);
1203 QCOMPARE(paintedBounds.width(), expectedBounds.width());
1204 QCOMPARE(paintedBounds.height(), expectedBounds.height());
1206 if (expectedPixels != -1) {
1207 int paintedPixels = getPaintedPixels(image, Qt::white);
1208 QCOMPARE(paintedPixels, expectedPixels);
1212 void tst_QPainter::drawPath2()
1216 for (int h = 5; h < 200; ++h) {
1217 QPainterPath p1, p2;
1224 const int offset = 2;
1226 QImage image(w + 2 * offset, h + 2 * offset,
1227 QImage::Format_ARGB32_Premultiplied);
1228 image.fill(QColor(Qt::white).rgb());
1231 p.setPen(Qt::NoPen);
1232 p.setBrush(Qt::black);
1233 p.translate(offset, offset);
1237 const int p1Pixels = getPaintedPixels(image, Qt::white);
1239 image.fill(QColor(Qt::white).rgb());
1241 p.setPen(Qt::NoPen);
1242 p.setBrush(Qt::black);
1243 p.translate(offset, offset);
1247 const int p2Pixels = getPaintedPixels(image, Qt::white);
1249 QCOMPARE(p1Pixels + p2Pixels, w * h);
1253 void tst_QPainter::drawPath3()
1255 QImage imgA(100, 100, QImage::Format_RGB32);
1256 imgA.fill(0xffffff);
1260 for (int y = 0; y < imgA.height(); ++y) {
1261 for (int x = 0; x < imgA.width(); ++x) {
1263 imgA.setPixel(x, y, 0);
1264 path.addRect(x, y, 1, 1);
1270 p.setPen(Qt::NoPen);
1271 p.setBrush(Qt::black);
1276 QVERIFY(imgA == imgB);
1278 imgA.invertPixels();
1279 imgB.fill(0xffffff);
1282 p.setPen(Qt::NoPen);
1283 p.setBrush(Qt::black);
1285 QRectF rect(0, 0, imgA.width(), imgA.height());
1286 path.addRect(rect.adjusted(-10, -10, 10, 10));
1290 QVERIFY(imgA == imgB);
1292 path.setFillRule(Qt::WindingFill);
1293 imgB.fill(0xffffff);
1296 p.setPen(Qt::NoPen);
1297 p.setBrush(Qt::black);
1298 QRect clip = rect.adjusted(10, 10, -10, -10).toRect();
1299 p.setClipRect(clip);
1303 QCOMPARE(getPaintedPixels(imgB, Qt::white), clip.width() * clip.height());
1306 void tst_QPainter::drawEllipse_data()
1308 QTest::addColumn<QSize>("size");
1309 QTest::addColumn<bool>("usePen");
1311 // The current drawEllipse algorithm (drawEllipse_midpoint_i in
1312 // qpaintengine_raster.cpp) draws ellipses that are too wide if the
1313 // ratio between width and hight is too large/small (task 114874). Those
1314 // ratios are therefore currently avoided.
1315 for (int w = 10; w < 128; w += 7) {
1316 for (int h = w/2; h < qMin(2*w, 128); h += 13) {
1317 QString s = QString("%1x%2").arg(w).arg(h);
1318 QTest::newRow(QString("%1 with pen").arg(s).toLatin1()) << QSize(w, h) << true;
1319 QTest::newRow(QString("%1 no pen").arg(s).toLatin1()) << QSize(w, h) << false;
1324 void tst_QPainter::drawEllipse()
1326 QFETCH(QSize, size);
1327 QFETCH(bool, usePen);
1329 const int offset = 10;
1330 QRect rect(QPoint(offset, offset), size);
1332 QImage image(size.width() + 2 * offset, size.height() + 2 * offset,
1333 QImage::Format_ARGB32_Premultiplied);
1334 image.fill(QColor(Qt::white).rgb());
1337 p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1338 p.setBrush(Qt::black);
1339 p.drawEllipse(rect);
1342 QPixmap pixmap = QPixmap::fromImage(image);
1344 const QRect painted = getPaintedSize(pixmap, Qt::white);
1346 QCOMPARE(painted.x(), rect.x());
1347 QCOMPARE(painted.y(), rect.y() + (usePen ? 0 : 1));
1348 QCOMPARE(painted.width(), size.width() + (usePen ? 1 : 0));
1349 QCOMPARE(painted.height(), size.height() + (usePen ? 1 : -1));
1352 void tst_QPainter::drawClippedEllipse_data()
1354 QTest::addColumn<QRect>("rect");
1356 for (int w = 20; w < 128; w += 7) {
1357 for (int h = w/2; h < qMin(2*w, 128); h += 13) {
1358 QString s = QString("%1x%2").arg(w).arg(h);
1359 QTest::newRow(QString("%1 top").arg(s).toLatin1()) << QRect(0, -h/2, w, h);
1360 QTest::newRow(QString("%1 topright").arg(s).toLatin1()) << QRect(w/2, -h/2, w, h);
1361 QTest::newRow(QString("%1 right").arg(s).toLatin1()) << QRect(w/2, 0, w, h);
1362 QTest::newRow(QString("%1 bottomright").arg(s).toLatin1()) << QRect(w/2, h/2, w, h);
1363 QTest::newRow(QString("%1 bottom").arg(s).toLatin1()) << QRect(0, h/2, w, h);
1364 QTest::newRow(QString("%1 bottomleft").arg(s).toLatin1()) << QRect(-w/2, h/2, w, h);
1365 QTest::newRow(QString("%1 left").arg(s).toLatin1()) << QRect(-w/2, 0, w, h);
1366 QTest::newRow(QString("%1 topleft").arg(s).toLatin1()) << QRect(-w/2, -h/2, w, h);
1371 void tst_QPainter::drawClippedEllipse()
1373 QFETCH(QRect, rect);
1374 if (sizeof(qreal) != sizeof(double))
1375 QSKIP("Test only works for qreal==double");
1376 QImage image(rect.width() + 1, rect.height() + 1,
1377 QImage::Format_ARGB32_Premultiplied);
1378 QRect expected = QRect(rect.x(), rect.y(), rect.width()+1, rect.height()+1)
1379 & QRect(0, 0, image.width(), image.height());
1382 image.fill(QColor(Qt::white).rgb());
1384 p.drawEllipse(rect);
1387 QPixmap pixmap = QPixmap::fromImage(image);
1388 const QRect painted = getPaintedSize(pixmap, Qt::white);
1390 QCOMPARE(painted.x(), expected.x());
1391 QCOMPARE(painted.y(), expected.y());
1392 QCOMPARE(painted.width(), expected.width());
1393 QCOMPARE(painted.height(), expected.height());
1397 void tst_QPainter::drawRoundRect()
1399 QFETCH(QRect, rect);
1400 QFETCH(bool, usePen);
1403 if (QTest::currentDataTag() == QByteArray("rect(6, 12, 3, 14) with pen") ||
1404 QTest::currentDataTag() == QByteArray("rect(6, 17, 3, 25) with pen") ||
1405 QTest::currentDataTag() == QByteArray("rect(10, 6, 10, 3) with pen") ||
1406 QTest::currentDataTag() == QByteArray("rect(10, 12, 10, 14) with pen") ||
1407 QTest::currentDataTag() == QByteArray("rect(13, 45, 17, 80) with pen") ||
1408 QTest::currentDataTag() == QByteArray("rect(13, 50, 17, 91) with pen") ||
1409 QTest::currentDataTag() == QByteArray("rect(17, 6, 24, 3) with pen") ||
1410 QTest::currentDataTag() == QByteArray("rect(24, 12, 38, 14) with pen"))
1411 QSKIP("The Mac paint engine is off-by-one on certain rect sizes");
1413 QPixmap pixmap(rect.x() + rect.width() + 10,
1414 rect.y() + rect.height() + 10);
1416 pixmap.fill(Qt::white);
1417 QPainter p(&pixmap);
1418 p.setRenderHint(QPainter::Qt4CompatiblePainting);
1419 p.setPen(usePen ? QPen(Qt::black) : QPen(Qt::NoPen));
1420 p.setBrush(Qt::black);
1421 p.drawRoundRect(rect);
1424 int increment = usePen ? 1 : 0;
1426 const QRect painted = getPaintedSize(pixmap, Qt::white);
1427 QCOMPARE(painted.width(), rect.width() + increment);
1428 QCOMPARE(painted.height(), rect.height() + increment);
1432 Q_DECLARE_METATYPE(QImage::Format)
1434 void tst_QPainter::qimageFormats_data()
1436 QTest::addColumn<QImage::Format>("format");
1437 QTest::newRow("QImage::Format_RGB32") << QImage::Format_RGB32;
1438 QTest::newRow("QImage::Format_ARGB32") << QImage::Format_ARGB32;
1439 QTest::newRow("QImage::Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
1440 QTest::newRow("QImage::Format_RGB16") << QImage::Format_RGB16;
1441 QTest::newRow("Qimage::Format_ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied;
1442 QTest::newRow("Qimage::Format_RGB666") << QImage::Format_RGB666;
1443 QTest::newRow("Qimage::Format_RGB555") << QImage::Format_RGB555;
1444 QTest::newRow("Qimage::Format_ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied;
1445 QTest::newRow("Qimage::Format_RGB888") << QImage::Format_RGB888;
1449 Tests that QPainter can paint on various QImage formats.
1451 void tst_QPainter::qimageFormats()
1453 QFETCH(QImage::Format, format);
1455 const QSize size(100, 100);
1456 QImage image(size, format);
1459 const QColor testColor(Qt::red);
1461 QVERIFY(p.isActive());
1462 p.setBrush(QBrush(testColor));
1463 p.drawRect(QRect(QPoint(0,0), size));
1464 QCOMPARE(image.pixel(50, 50), testColor.rgb());
1467 void tst_QPainter::fillData()
1469 QTest::addColumn<QRect>("rect");
1470 QTest::addColumn<bool>("usePen");
1472 for (int w = 3; w < 50; w += 7) {
1473 for (int h = 3; h < 50; h += 11) {
1476 QTest::newRow(QString("rect(%1, %2, %3, %4) with pen").arg(x).arg(y).arg(w).arg(h).toLatin1())
1477 << QRect(x, y, w, h) << true;
1478 QTest::newRow(QString("rect(%1, %2, %3, %4) no pen").arg(x).arg(y).arg(w).arg(h).toLatin1())
1479 << QRect(x, y, w, h) << false;
1485 Test that drawline works properly after setWindow has been called.
1487 void tst_QPainter::setWindow()
1489 QPixmap pixmap(600, 600);
1490 pixmap.fill(QColor(Qt::white));
1492 QPainter painter(&pixmap);
1493 painter.setWindow(0, 0, 3, 3);
1494 painter.drawLine(1, 1, 2, 2);
1496 const QRect painted = getPaintedSize(pixmap, Qt::white);
1497 QVERIFY(195 < painted.y() && painted.y() < 205); // correct value is around 200
1498 QVERIFY(195 < painted.height() && painted.height() < 205); // correct value is around 200
1501 void tst_QPainter::combinedMatrix()
1506 p.setWindow(0, 0, 1, 1);
1507 p.setViewport(32, 0, 32, 32);
1509 p.translate(0.5, 0.5);
1511 QMatrix cm = p.combinedMatrix();
1513 QPointF pt = QPointF(0, 0) * cm;
1515 QCOMPARE(pt.x(), 48.0);
1516 QCOMPARE(pt.y(), 16.0);
1519 void tst_QPainter::textOnTransparentImage()
1521 bool foundPixel = false;
1522 QImage image(10, 10, QImage::Format_ARGB32_Premultiplied);
1523 image.fill(qRgba(0, 0, 0, 0)); // transparent
1525 QPainter painter(&image);
1526 painter.setPen(QColor(255, 255, 255));
1527 painter.drawText(0, 10, "W");
1529 for (int x = 0; x < image.width(); ++x)
1530 for (int y = 0; y < image.height(); ++y)
1531 if (image.pixel(x, y) != 0)
1533 QVERIFY(foundPixel);
1536 void tst_QPainter::renderHints()
1538 QImage img(1, 1, QImage::Format_RGB32);
1543 p.setRenderHints(QPainter::RenderHints(0xffffffff), false);
1544 QCOMPARE(p.renderHints(), QPainter::RenderHints(0));
1547 p.setRenderHint(QPainter::Antialiasing);
1548 QVERIFY(p.renderHints() & QPainter::Antialiasing);
1550 p.setRenderHint(QPainter::Antialiasing, false);
1551 QVERIFY(!(p.renderHints() & QPainter::Antialiasing));
1554 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
1555 QVERIFY(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform));
1557 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
1558 QVERIFY(!(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform)));
1561 int countPixels(const QImage &img, const QRgb &color)
1564 for (int y = 0; y < img.height(); ++y) {
1565 for (int x = 0; x < img.width(); ++x) {
1566 count += ((img.pixel(x, y) & 0xffffff) == color);
1572 template <typename T>
1573 void testClipping(QImage &img)
1576 a.addRect(QRect(2, 2, 4, 4));
1577 b.addRect(QRect(4, 4, 4, 4));
1584 p.setClipPath(b, Qt::IntersectClip);
1586 p.setClipping(false);
1587 p.setPen(Qt::NoPen);
1588 p.setBrush(QColor(0xff0000));
1589 p.drawRect(T(0, 0, 10, 10));
1591 p.setClipping(true);
1592 p.setBrush(QColor(0x00ff00));
1593 p.drawRect(T(0, 0, 10, 10));
1595 QCOMPARE(countPixels(img, 0xff0000), 96);
1596 QCOMPARE(countPixels(img, 0x00ff00), 4);
1599 void tst_QPainter::disableEnableClipping()
1601 QImage img(10, 10, QImage::Format_RGB32);
1603 testClipping<QRectF>(img);
1604 testClipping<QRect>(img);
1607 void tst_QPainter::setClipRect()
1609 QImage img(10, 10, QImage::Format_RGB32);
1610 // simple test to let valgrind check for buffer overflow
1613 p.setClipRect(-10, -10, 100, 100);
1614 p.fillRect(-10, -10, 100, 100, QBrush(QColor(Qt::red)));
1617 // rects with negative width/height
1620 p.setClipRect(QRect(10, 10, -10, 10));
1621 QVERIFY(p.clipRegion().isEmpty());
1622 p.setClipRect(QRect(10, 10, 10, -10));
1623 QVERIFY(p.clipRegion().isEmpty());
1624 p.setClipRect(QRectF(10.5, 10.5, -10.5, 10.5));
1625 QVERIFY(p.clipRegion().isEmpty());
1626 p.setClipRect(QRectF(10.5, 10.5, 10.5, -10.5));
1627 QVERIFY(p.clipRegion().isEmpty());
1632 This tests the two different clipping approaches in QRasterPaintEngine,
1633 one when using a QRegion and one when using a QPainterPath. They should
1636 void tst_QPainter::setEqualClipRegionAndPath_data()
1638 QTest::addColumn<QSize>("deviceSize");
1639 QTest::addColumn<QRegion>("region");
1641 QTest::newRow("empty") << QSize(100, 100) << QRegion();
1642 QTest::newRow("simple rect") << QSize(100, 100)
1643 << QRegion(QRect(5, 5, 10, 10));
1645 QVector<QRect> rects;
1648 rects << QRect(5, 5, 10, 10) << QRect(20, 20, 10, 10);
1649 region.setRects(rects.constData(), rects.size());
1650 QTest::newRow("two rects") << QSize(100, 100) << region;
1653 rects << QRect(5, 5, 10, 10) << QRect(20, 5, 10, 10);
1654 region.setRects(rects.constData(), rects.size());
1655 QTest::newRow("two x-adjacent rects") << QSize(100, 100) << region;
1658 rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1659 region.setRects(rects.constData(), rects.size());
1660 QTest::newRow("two x-adjacent rects 2") << QSize(100, 100) << region;
1663 rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1664 region.setRects(rects.constData(), rects.size());
1665 QTest::newRow("two x-adjacent rects 3") << QSize(50, 50) << region;
1668 rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1669 region.setRects(rects.constData(), rects.size());
1670 QTest::newRow("two x-adjacent rects 4") << QSize(101, 101) << region;
1672 region = QRegion(QRect(0, 0, 200, 200), QRegion::Ellipse);
1674 QTest::newRow("ellipse") << QSize(190, 200) << region;
1676 region ^= QRect(50, 50, 50, 50);
1677 QTest::newRow("ellipse 2") << QSize(200, 200) << region;
1680 void tst_QPainter::setEqualClipRegionAndPath()
1682 QFETCH(QSize, deviceSize);
1683 QFETCH(QRegion, region);
1686 path.addRegion(region);
1688 QImage img1(deviceSize.width(), deviceSize.height(),
1689 QImage::Format_ARGB32);
1690 QImage img2(deviceSize.width(), deviceSize.height(),
1691 QImage::Format_ARGB32);
1692 img1.fill(0x12345678);
1693 img2.fill(0x12345678);
1697 p.setClipRegion(region);
1698 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1702 p.setClipPath(path);
1703 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1706 QCOMPARE(img1, img2);
1709 img1.fill(0x12345678);
1710 img2.fill(0x12345678);
1715 p.setClipRegion(region);
1716 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1721 p.setClipPath(path);
1722 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1725 QCOMPARE(img1, img2);
1727 img1.fill(0x12345678);
1728 img2.fill(0x12345678);
1730 // simple intersectclip
1731 img1.fill(0x12345678);
1732 img2.fill(0x12345678);
1735 p.setClipRegion(region);
1736 p.setClipRegion(region, Qt::IntersectClip);
1737 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1741 p.setClipPath(path);
1742 p.setClipPath(path, Qt::IntersectClip);
1743 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1745 QCOMPARE(img1, img2);
1747 img1.fill(0x12345678);
1748 img2.fill(0x12345678);
1751 p.setClipPath(path);
1752 p.setClipRegion(region, Qt::IntersectClip);
1753 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1757 p.setClipRegion(region);
1758 p.setClipPath(path, Qt::IntersectClip);
1759 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1761 QCOMPARE(img1, img2);
1765 void tst_QPainter::clippedFillPath_data()
1767 QTest::addColumn<QSize>("imageSize");
1768 QTest::addColumn<QPainterPath>("path");
1769 QTest::addColumn<QRect>("clipRect");
1770 QTest::addColumn<QBrush>("brush");
1771 QTest::addColumn<QPen>("pen");
1773 QLinearGradient gradient(QPoint(0, 0), QPoint(100, 100));
1774 gradient.setColorAt(0, Qt::red);
1775 gradient.setColorAt(1, Qt::blue);
1778 QPen pen2(QColor(223, 223, 0, 223));
1782 path.addRect(QRect(15, 15, 50, 50));
1783 QTest::newRow("simple rect 0") << QSize(100, 100) << path
1784 << QRect(15, 15, 49, 49)
1785 << QBrush(Qt::NoBrush)
1787 QTest::newRow("simple rect 1") << QSize(100, 100) << path
1788 << QRect(15, 15, 50, 50)
1789 << QBrush(Qt::NoBrush)
1791 QTest::newRow("simple rect 2") << QSize(100, 100) << path
1792 << QRect(15, 15, 51, 51)
1793 << QBrush(Qt::NoBrush)
1795 QTest::newRow("simple rect 3") << QSize(100, 100) << path
1796 << QRect(15, 15, 51, 51)
1797 << QBrush(QColor(Qt::blue))
1799 QTest::newRow("simple rect 4") << QSize(100, 100) << path
1800 << QRect(15, 15, 51, 51)
1804 path = QPainterPath();
1805 path.addEllipse(QRect(15, 15, 50, 50));
1806 QTest::newRow("ellipse 0") << QSize(100, 100) << path
1807 << QRect(15, 15, 49, 49)
1808 << QBrush(Qt::NoBrush)
1810 QTest::newRow("ellipse 1") << QSize(100, 100) << path
1811 << QRect(15, 15, 50, 50)
1812 << QBrush(Qt::NoBrush)
1814 QTest::newRow("ellipse 2") << QSize(100, 100) << path
1815 << QRect(15, 15, 51, 51)
1816 << QBrush(Qt::NoBrush)
1818 QTest::newRow("ellipse 3") << QSize(100, 100) << path
1819 << QRect(15, 15, 51, 51)
1820 << QBrush(QColor(Qt::blue))
1822 QTest::newRow("ellipse 4") << QSize(100, 100) << path
1823 << QRect(15, 15, 51, 51)
1827 path = QPainterPath();
1828 path.addRoundRect(QRect(15, 15, 50, 50), 20);
1829 QTest::newRow("round rect 0") << QSize(100, 100) << path
1830 << QRect(15, 15, 49, 49)
1831 << QBrush(Qt::NoBrush)
1833 QTest::newRow("round rect 1") << QSize(100, 100) << path
1834 << QRect(15, 15, 50, 50)
1835 << QBrush(Qt::NoBrush)
1837 QTest::newRow("round rect 2") << QSize(100, 100) << path
1838 << QRect(15, 15, 51, 51)
1839 << QBrush(Qt::NoBrush)
1841 QTest::newRow("round rect 3") << QSize(100, 100) << path
1842 << QRect(15, 15, 51, 51)
1843 << QBrush(QColor(Qt::blue))
1845 QTest::newRow("round rect 4") << QSize(100, 100) << path
1846 << QRect(15, 15, 51, 51)
1850 path = QPainterPath();
1851 path.moveTo(15, 50);
1852 path.cubicTo(40, 50, 40, 15, 65, 50);
1853 path.lineTo(15, 50);
1854 QTest::newRow("cubic 0") << QSize(100, 100) << path
1855 << QRect(15, 15, 49, 49)
1856 << QBrush(Qt::NoBrush)
1858 QTest::newRow("cubic 1") << QSize(100, 100) << path
1859 << QRect(15, 15, 50, 50)
1860 << QBrush(Qt::NoBrush)
1862 QTest::newRow("cubic 2") << QSize(100, 100) << path
1863 << QRect(15, 15, 51, 51)
1864 << QBrush(Qt::NoBrush)
1866 QTest::newRow("cubic 3") << QSize(100, 100) << path
1867 << QRect(15, 15, 51, 51)
1868 << QBrush(QColor(Qt::blue))
1870 QTest::newRow("cubic 4") << QSize(100, 100) << path
1871 << QRect(15, 15, 51, 51)
1876 void tst_QPainter::clippedFillPath()
1878 QFETCH(QSize, imageSize);
1879 QFETCH(QPainterPath, path);
1880 QFETCH(QRect, clipRect);
1881 QPainterPath clipPath;
1882 clipPath.addRect(clipRect);
1883 QFETCH(QBrush, brush);
1886 const int width = imageSize.width();
1887 const int height = imageSize.height();
1889 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
1890 clippedRect.fill(0x12345678);
1892 QPainter painter(&clippedRect);
1893 painter.setPen(pen);
1894 painter.setBrush(brush);
1895 painter.setClipRect(clipRect);
1896 painter.drawPath(path);
1899 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
1900 clippedPath.fill(0x12345678);
1902 QPainter painter(&clippedPath);
1903 painter.setPen(pen);
1904 painter.setBrush(brush);
1905 painter.setClipPath(clipPath);
1906 painter.drawPath(path);
1909 QCOMPARE(clippedRect, clippedPath);
1911 // repeat with antialiasing
1913 clippedRect.fill(0x12345678);
1915 QPainter painter(&clippedRect);
1916 painter.setRenderHint(QPainter::Antialiasing);
1917 painter.setPen(pen);
1918 painter.setBrush(brush);
1919 painter.setClipRect(clipRect);
1920 painter.drawPath(path);
1923 clippedPath.fill(0x12345678);
1925 QPainter painter(&clippedPath);
1926 painter.setRenderHint(QPainter::Antialiasing);
1927 painter.setPen(pen);
1928 painter.setBrush(brush);
1929 painter.setClipPath(clipPath);
1930 painter.drawPath(path);
1933 QCOMPARE(clippedRect, clippedPath);
1936 void tst_QPainter::clippedLines_data()
1938 QTest::addColumn<QSize>("imageSize");
1939 QTest::addColumn<QLineF>("line");
1940 QTest::addColumn<QRect>("clipRect");
1941 QTest::addColumn<QPen>("pen");
1943 QPen pen2(QColor(223, 223, 0, 223));
1946 QVector<QLineF> lines;
1947 lines << QLineF(15, 15, 65, 65)
1948 << QLineF(14, 14, 66, 66)
1949 << QLineF(16, 16, 64, 64)
1950 << QLineF(65, 65, 15, 15)
1951 << QLineF(66, 66, 14, 14)
1952 << QLineF(64, 64, 14, 14)
1953 << QLineF(15, 50, 15, 64)
1954 << QLineF(15, 50, 15, 65)
1955 << QLineF(15, 50, 15, 66)
1956 << QLineF(15, 50, 64, 50)
1957 << QLineF(15, 50, 65, 50)
1958 << QLineF(15, 50, 66, 50);
1960 foreach (QLineF line, lines) {
1961 QString desc = QString("line (%1, %2, %3, %4) %5").arg(line.x1())
1962 .arg(line.y1()).arg(line.x2()).arg(line.y2());
1963 QTest::newRow(qPrintable(desc.arg(0))) << QSize(100, 100) << line
1964 << QRect(15, 15, 49, 49)
1966 QTest::newRow(qPrintable(desc.arg(1))) << QSize(100, 100) << line
1967 << QRect(15, 15, 50, 50)
1969 QTest::newRow(qPrintable(desc.arg(2))) << QSize(100, 100) << line
1970 << QRect(15, 15, 51, 51)
1972 QTest::newRow(qPrintable(desc.arg(3))) << QSize(100, 100) << line
1973 << QRect(15, 15, 51, 51)
1975 QTest::newRow(qPrintable(desc.arg(4))) << QSize(100, 100) << line
1976 << QRect(15, 15, 51, 51)
1981 void tst_QPainter::clippedLines()
1983 QFETCH(QSize, imageSize);
1984 QFETCH(QLineF, line);
1985 QFETCH(QRect, clipRect);
1986 QPainterPath clipPath;
1987 clipPath.addRect(clipRect);
1990 const int width = imageSize.width();
1991 const int height = imageSize.height();
1993 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
1994 clippedRect.fill(0x12345678);
1996 QPainter painter(&clippedRect);
1997 painter.setPen(pen);
1998 painter.setClipRect(clipRect);
1999 painter.drawLine(line);
2000 painter.drawLine(line.toLine());
2003 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2004 clippedPath.fill(0x12345678);
2006 QPainter painter(&clippedPath);
2007 painter.setPen(pen);
2008 painter.setClipPath(clipPath);
2009 painter.drawLine(line);
2010 painter.drawLine(line.toLine());
2013 QCOMPARE(clippedRect, clippedPath);
2015 // repeat with antialiasing
2016 clippedRect.fill(0x12345678);
2018 QPainter painter(&clippedRect);
2019 painter.setRenderHint(QPainter::Antialiasing);
2020 painter.setPen(pen);
2021 painter.setClipRect(clipRect);
2022 painter.drawLine(line);
2023 painter.drawLine(line.toLine());
2026 clippedPath.fill(0x12345678);
2028 QPainter painter(&clippedPath);
2029 painter.setRenderHint(QPainter::Antialiasing);
2030 painter.setPen(pen);
2031 painter.setClipPath(clipPath);
2032 painter.drawLine(line);
2033 painter.drawLine(line.toLine());
2036 QCOMPARE(clippedRect, clippedPath);
2039 void tst_QPainter::clippedPolygon_data()
2041 clippedFillPath_data();
2044 void tst_QPainter::clippedPolygon()
2046 QFETCH(QSize, imageSize);
2047 QFETCH(QPainterPath, path);
2048 QPolygonF polygon = path.toFillPolygon();
2049 QFETCH(QRect, clipRect);
2050 QPainterPath clipPath;
2051 clipPath.addRect(clipRect);
2053 QFETCH(QBrush, brush);
2055 const int width = imageSize.width();
2056 const int height = imageSize.height();
2058 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
2059 clippedRect.fill(0x12345678);
2061 QPainter painter(&clippedRect);
2062 painter.setPen(pen);
2063 painter.setBrush(brush);
2064 painter.setClipRect(clipRect);
2065 painter.drawPolygon(polygon);
2066 painter.drawPolygon(polygon.toPolygon());
2069 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2070 clippedPath.fill(0x12345678);
2072 QPainter painter(&clippedPath);
2073 painter.setPen(pen);
2074 painter.setBrush(brush);
2075 painter.setClipRect(clipRect);
2076 painter.drawPolygon(polygon);
2077 painter.drawPolygon(polygon.toPolygon());
2080 QCOMPARE(clippedRect, clippedPath);
2082 // repeat with antialiasing
2084 clippedRect.fill(0x12345678);
2086 QPainter painter(&clippedRect);
2087 painter.setRenderHint(QPainter::Antialiasing);
2088 painter.setPen(pen);
2089 painter.setBrush(brush);
2090 painter.setClipRect(clipRect);
2091 painter.drawPolygon(polygon);
2092 painter.drawPolygon(polygon.toPolygon());
2095 clippedPath.fill(0x12345678);
2097 QPainter painter(&clippedPath);
2098 painter.setRenderHint(QPainter::Antialiasing);
2099 painter.setPen(pen);
2100 painter.setBrush(brush);
2101 painter.setClipRect(clipRect);
2102 painter.drawPolygon(polygon);
2103 painter.drawPolygon(polygon.toPolygon());
2106 QCOMPARE(clippedRect, clippedPath);
2109 // this just draws some text that should be clipped in the raster
2111 void tst_QPainter::clippedText()
2113 for (char ch = 'A'; ch < 'Z'; ++ch) {
2117 QFontMetrics metrics(f);
2118 QRect textRect = metrics.boundingRect(QChar(ch));
2120 if (textRect.width() <= 8)
2122 if (textRect.height() <= 8)
2125 QRect imageRect = textRect.adjusted(4, 4, -4, -4);
2127 QImage image(imageRect.size(), QImage::Format_ARGB32_Premultiplied);
2129 image.fill(qRgba(255, 255, 255, 255));
2131 QPainter painter(&image);
2133 painter.setPen(Qt::black);
2135 painter.drawText(0, 0, QChar(ch));
2138 image.fill(qRgba(255, 255, 255, 255));
2140 QPainter painter(&image);
2142 painter.setPen(Qt::black);
2144 painter.drawText(-imageRect.topLeft(), QChar(ch));
2147 bool foundPixel = false;
2148 for (int x = 0; x < image.width(); ++x)
2149 for (int y = 0; y < image.height(); ++y)
2150 if (image.pixel(x, y) != 0)
2152 // can't QVERIFY(foundPixel) as sometimes all pixels are clipped
2153 // away. For example for 'O'
2154 // just call /some/ function to prevent the compiler from optimizing
2156 QString::number(foundPixel);
2158 //image.save(QString("debug") + ch + ".xpm");
2161 QVERIFY(true); // reached, don't trigger any valgrind errors
2164 void tst_QPainter::setOpacity_data()
2166 QTest::addColumn<QImage::Format>("destFormat");
2167 QTest::addColumn<QImage::Format>("srcFormat");
2169 QTest::newRow("ARGB32P on ARGB32P") << QImage::Format_ARGB32_Premultiplied
2170 << QImage::Format_ARGB32_Premultiplied;
2172 QTest::newRow("ARGB32 on ARGB32") << QImage::Format_ARGB32
2173 << QImage::Format_ARGB32;
2175 QTest::newRow("RGB32 on RGB32") << QImage::Format_RGB32
2176 << QImage::Format_RGB32;
2178 QTest::newRow("RGB16 on RGB16") << QImage::Format_RGB16
2179 << QImage::Format_RGB16;
2181 QTest::newRow("ARGB8565_Premultiplied on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied
2182 << QImage::Format_ARGB8565_Premultiplied;
2184 QTest::newRow("RGB555 on RGB555") << QImage::Format_RGB555
2185 << QImage::Format_RGB555;
2187 QTest::newRow("RGB666 on RGB666") << QImage::Format_RGB666
2188 << QImage::Format_RGB666;
2190 QTest::newRow("ARGB8555_Premultiplied on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied
2191 << QImage::Format_ARGB8555_Premultiplied;
2193 QTest::newRow("RGB888 on RGB888") << QImage::Format_RGB888
2194 << QImage::Format_RGB888;
2196 QTest::newRow("RGB32 on RGB16") << QImage::Format_RGB16
2197 << QImage::Format_RGB32;
2199 QTest::newRow("RGB32 on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied
2200 << QImage::Format_RGB32;
2202 QTest::newRow("RGB32 on RGB666") << QImage::Format_RGB666
2203 << QImage::Format_RGB32;
2205 QTest::newRow("RGB32 on RGB555") << QImage::Format_RGB555
2206 << QImage::Format_RGB32;
2208 QTest::newRow("RGB32 on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied
2209 << QImage::Format_RGB32;
2211 QTest::newRow("RGB32 on RGB888") << QImage::Format_RGB888
2212 << QImage::Format_RGB32;
2214 QTest::newRow("RGB16 on RGB32") << QImage::Format_RGB32
2215 << QImage::Format_RGB16;
2217 QTest::newRow("ARGB8565_Premultiplied on RGB32") << QImage::Format_RGB32
2218 << QImage::Format_ARGB8565_Premultiplied;
2220 QTest::newRow("RGB666 on RGB32") << QImage::Format_RGB32
2221 << QImage::Format_RGB666;
2223 QTest::newRow("RGB555 on RGB32") << QImage::Format_RGB32
2224 << QImage::Format_RGB555;
2226 QTest::newRow("ARGB8555_Premultiplied on RGB32") << QImage::Format_RGB32
2227 << QImage::Format_ARGB8555_Premultiplied;
2229 QTest::newRow("RGB888 on RGB32") << QImage::Format_RGB32
2230 << QImage::Format_RGB888;
2232 QTest::newRow("RGB555 on RGB888") << QImage::Format_RGB888
2233 << QImage::Format_RGB555;
2235 QTest::newRow("RGB666 on RGB888") << QImage::Format_RGB888
2236 << QImage::Format_RGB666;
2238 QTest::newRow("RGB444 on RGB444") << QImage::Format_RGB444
2239 << QImage::Format_RGB444;
2242 void tst_QPainter::setOpacity()
2244 QFETCH(QImage::Format, destFormat);
2245 QFETCH(QImage::Format, srcFormat);
2247 const QSize imageSize(12, 12);
2248 const QRect imageRect(QPoint(0, 0), imageSize);
2249 QColor destColor = Qt::black;
2250 QColor srcColor = Qt::white;
2252 QImage dest(imageSize, destFormat);
2253 QImage src(imageSize, srcFormat);
2257 p.fillRect(imageRect, destColor);
2261 p.fillRect(imageRect, srcColor);
2266 p.drawImage(imageRect, src, imageRect);
2269 QImage actual = dest.convertToFormat(QImage::Format_RGB32);
2271 for (int y = 0; y < actual.height(); ++y) {
2272 QRgb *p = (QRgb *)actual.scanLine(y);
2273 for (int x = 0; x < actual.width(); ++x) {
2274 QVERIFY(qAbs(qRed(p[x]) - 127) <= 0xf);
2275 QVERIFY(qAbs(qGreen(p[x]) - 127) <= 0xf);
2276 QVERIFY(qAbs(qBlue(p[x]) - 127) <= 0xf);
2281 void tst_QPainter::drawhelper_blend_untransformed_data()
2286 void tst_QPainter::drawhelper_blend_untransformed()
2288 QFETCH(QImage::Format, destFormat);
2289 QFETCH(QImage::Format, srcFormat);
2291 const int size = 128;
2292 const QSize imageSize(size, size);
2293 const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing
2295 QColor destColor(127, 127, 127);
2296 QColor srcColor(Qt::white);
2298 QImage dest(imageSize, destFormat);
2299 QImage src(imageSize, srcFormat);
2303 p.fillRect(paintRect, srcColor);
2306 QList<qreal> opacities = (QList<qreal>() << 0.0 << 0.1 << 0.01 << 0.4
2307 << 0.5 << 0.6 << 0.9 << 1.0);
2308 foreach (qreal opacity, opacities) {
2310 p.fillRect(paintRect, destColor);
2312 p.setOpacity(opacity);
2313 p.drawImage(paintRect, src, paintRect);
2316 // sanity check: make sure all pixels are equal
2317 QImage expected(size - 2, size, destFormat);
2319 p.fillRect(0, 0, expected.width(), expected.height(),
2320 QColor(dest.pixel(1, 0)));
2323 const QImage subDest(dest.bits() + dest.depth() / 8,
2324 dest.width() - 2, dest.height(),
2325 dest.bytesPerLine(), dest.format());
2327 if (dest.format() == QImage::Format_ARGB8565_Premultiplied ||
2328 dest.format() == QImage::Format_ARGB8555_Premultiplied) {
2329 // Test skipped due to rounding errors...
2332 QCOMPARE(subDest, expected);
2336 void tst_QPainter::drawhelper_blend_tiled_untransformed_data()
2341 void tst_QPainter::drawhelper_blend_tiled_untransformed()
2343 QFETCH(QImage::Format, destFormat);
2344 QFETCH(QImage::Format, srcFormat);
2346 const int size = 128;
2347 const QSize imageSize(size, size);
2348 const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing
2350 QColor destColor(127, 127, 127);
2351 QColor srcColor(Qt::white);
2353 QImage dest(imageSize, destFormat);
2354 QImage src(imageSize / 2, srcFormat);
2358 p.fillRect(QRect(QPoint(0, 0), imageSize/ 2), srcColor);
2361 const QBrush brush(src);
2363 QList<qreal> opacities = (QList<qreal>() << 0.0 << 0.1 << 0.01 << 0.4
2364 << 0.5 << 0.6 << 0.9 << 1.0);
2365 foreach (qreal opacity, opacities) {
2367 p.fillRect(paintRect, destColor);
2369 p.setOpacity(opacity);
2370 p.fillRect(paintRect, brush);
2373 // sanity check: make sure all pixels are equal
2374 QImage expected(size - 2, size, destFormat);
2376 p.fillRect(0, 0, expected.width(), expected.height(),
2377 QColor(dest.pixel(1, 0)));
2380 const QImage subDest(dest.bits() + dest.depth() / 8,
2381 dest.width() - 2, dest.height(),
2382 dest.bytesPerLine(), dest.format());
2384 if (dest.format() == QImage::Format_ARGB8565_Premultiplied ||
2385 dest.format() == QImage::Format_ARGB8555_Premultiplied) {
2386 // Skipping test due to rounding errors. Test needs rewrite
2389 QCOMPARE(subDest, expected);
2393 static QPaintEngine::PaintEngineFeatures no_porter_duff()
2395 QPaintEngine::PaintEngineFeatures features = QPaintEngine::AllFeatures;
2396 return features & ~QPaintEngine::PorterDuff;
2399 class DummyPaintEngine : public QPaintEngine, public QPaintDevice
2402 DummyPaintEngine() : QPaintEngine(no_porter_duff()) {}
2403 virtual bool begin(QPaintDevice *) { return true; }
2404 virtual bool end() { return true; }
2406 virtual void updateState(const QPaintEngineState &) {}
2407 virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
2409 virtual Type type() const { return User; }
2411 virtual QPaintEngine *paintEngine() const { return (QPaintEngine *)this; }
2413 virtual int metric(PaintDeviceMetric metric) const { Q_UNUSED(metric); return 0; };
2416 static bool success;
2418 void porterDuff_warningChecker(QtMsgType type, const QMessageLogContext &, const QString &msg)
2420 if (type == QtWarningMsg && msg == QLatin1String("QPainter::setCompositionMode: PorterDuff modes not supported on device"))
2424 void tst_QPainter::porterDuff_warning()
2426 QtMessageHandler old = qInstallMessageHandler(porterDuff_warningChecker);
2427 DummyPaintEngine dummy;
2431 p.setCompositionMode(QPainter::CompositionMode_Source);
2435 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
2439 p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
2442 QVERIFY(qInstallMessageHandler(old) == porterDuff_warningChecker);
2448 inline quint24(quint32 v)
2451 data[1] = qGreen(v);
2455 inline operator quint32 ()
2457 return qRgb(data[2], data[1], data[0]);
2460 inline bool operator==(const quint24 &v) const {
2461 return (data[0] == v.data[0] && data[1] == v.data[1] && data[2] == v.data[2]);
2467 void tst_QPainter::drawhelper_blend_color()
2469 QImage dest(32, 32, QImage::Format_ARGB8555_Premultiplied);
2470 dest.fill(0xff000000);
2474 p.fillRect(0, 0, dest.width(), dest.height(), QColor(255, 0, 0, 127));
2477 QImage expected(32, 32, QImage::Format_ARGB8555_Premultiplied);
2478 expected.fill(0xff3c007f);
2480 QCOMPARE(dest.pixel(1, 1), expected.pixel(1, 1));
2481 QCOMPARE(dest, expected);
2484 #ifndef QT_NO_WIDGETS
2485 class ViewportTestWidget : public QWidget
2488 ViewportTestWidget(QWidget *parent = 0) : QWidget(parent), hasPainted(false) {}
2489 QSize sizeHint() const {
2490 return QSize(100, 100);
2497 void paintEvent(QPaintEvent *) {
2500 viewport = p.viewport();
2504 void tst_QPainter::childWidgetViewport()
2507 parent.setAutoFillBackground(true);
2508 parent.resize(200, 200);
2509 ViewportTestWidget child(&parent);
2510 child.setAutoFillBackground(true);
2513 qApp->processEvents();
2515 if (child.hasPainted) {
2516 QCOMPARE(child.viewport, QRect(QPoint(0, 0), child.sizeHint()));
2518 qWarning("Failed to ensure that paintEvent has been run. Could not run test.");
2523 void tst_QPainter::fillRect_objectBoundingModeGradient()
2525 QImage a(10, 10, QImage::Format_ARGB32_Premultiplied);
2529 QLinearGradient g(QPoint(0, 0), QPoint(0, 1));
2530 g.setColorAt(0, Qt::red);
2531 g.setColorAt(1, Qt::blue);
2532 g.setCoordinateMode(QGradient::ObjectBoundingMode);
2535 p.fillRect(QRect(0, 0, a.width(), a.height()), g);
2539 path.addRect(0, 0, a.width(), a.height());
2542 p.fillPath(path, g);
2548 void tst_QPainter::fillRect_stretchToDeviceMode()
2550 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2552 QLinearGradient g(QPoint(0, 0), QPoint(0, 1));
2553 g.setCoordinateMode(QGradient::StretchToDeviceMode);
2556 p.fillRect(img.rect(), g);
2559 for (int i = 1; i < img.height(); ++i)
2560 QVERIFY(img.pixel(0, i) != img.pixel(0, i-1));
2563 void tst_QPainter::monoImages()
2565 Qt::GlobalColor colorPairs[][2] = {
2566 { Qt::white, Qt::black },
2567 { Qt::color0, Qt::color1 },
2568 { Qt::red, Qt::blue }
2571 const int numColorPairs = sizeof(colorPairs) / sizeof(QRgb[2]);
2573 QImage transparent(2, 2, QImage::Format_ARGB32_Premultiplied);
2574 transparent.fill(0x0);
2576 for (int i = 1; i < QImage::NImageFormats; ++i) {
2577 for (int j = 0; j < numColorPairs; ++j) {
2578 const QImage::Format format = QImage::Format(i);
2579 if (format == QImage::Format_Indexed8)
2582 QImage img(2, 2, format);
2584 if (img.colorCount() > 0) {
2585 img.setColor(0, QColor(colorPairs[j][0]).rgba());
2586 img.setColor(1, QColor(colorPairs[j][1]).rgba());
2591 p.fillRect(0, 0, 2, 2, colorPairs[j][0]);
2592 p.fillRect(0, 0, 1, 1, colorPairs[j][1]);
2593 p.fillRect(1, 1, 1, 1, colorPairs[j][1]);
2596 QImage original = img;
2599 p.drawImage(0, 0, transparent);
2602 // drawing a transparent image on top of another image
2603 // should not change the image
2604 QCOMPARE(original, img);
2606 if (img.colorCount() == 0)
2609 for (int k = 0; k < 2; ++k) {
2611 p.fillRect(0, 0, 2, 2, colorPairs[j][k]);
2614 QImage argb32p(2, 2, QImage::Format_ARGB32_Premultiplied);
2616 p.fillRect(0, 0, 2, 2, colorPairs[j][k]);
2619 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2621 // drawing argb32p image on mono image
2623 p.drawImage(0, 0, argb32p);
2626 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2628 // drawing mono image on argb32p image
2630 p.drawImage(0, 0, img);
2633 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2639 #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_CC_MSVC) && !defined(Q_OS_SOLARIS) && !defined(__UCLIBC__)
2642 static const QString fpeExceptionString(int exception)
2645 if (exception & FE_INEXACT)
2646 return QLatin1String("Inexact result");
2648 if (exception & FE_UNDERFLOW)
2649 return QLatin1String("Underflow");
2650 if (exception & FE_OVERFLOW)
2651 return QLatin1String("Overflow");
2652 if (exception & FE_DIVBYZERO)
2653 return QLatin1String("Divide by zero");
2654 if (exception & FE_INVALID)
2655 return QLatin1String("Invalid operation");
2656 return QLatin1String("No exception");
2659 class FpExceptionChecker
2662 FpExceptionChecker(int exceptionMask)
2663 : m_exceptionMask(exceptionMask)
2665 feclearexcept(m_exceptionMask);
2668 ~FpExceptionChecker()
2670 const int exceptions = fetestexcept(m_exceptionMask);
2671 QVERIFY2(!exceptions, qPrintable(QLatin1String("Floating point exception: ") + fpeExceptionString(exceptions)));
2675 int m_exceptionMask;
2678 void fpe_rasterizeLine_task232012()
2680 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2681 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2685 p.setBrush(Qt::black);
2686 p.drawRect(QRectF(0, 0, 5, 0));
2687 p.drawRect(QRectF(0, 0, 0, 5));
2690 void fpe_pixmapTransform()
2692 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2694 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2698 const qreal scaleFactor = 0.001;
2699 const int translateDistance = 1000000;
2702 p.setBrush(QBrush(Qt::red,Qt::Dense6Pattern));
2704 for (int i = 0; i < 2; ++i) {
2705 p.setRenderHint(QPainter::SmoothPixmapTransform, i);
2709 p.translate(translateDistance, 0);
2710 p.drawRect(-translateDistance, 0, 100, 100);
2713 p.scale(scaleFactor, scaleFactor);
2714 p.drawRect(QRectF(0, 0, 1 / scaleFactor, 1 / scaleFactor));
2718 void fpe_zeroLengthLines()
2720 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2722 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2726 p.setPen(QPen(Qt::black, 3));
2727 p.drawLine(64, 64, 64, 64);
2730 void fpe_divByZero()
2732 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2734 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2738 p.setRenderHint(QPainter::Antialiasing);
2740 p.drawRect(QRectF(10, 10, 100, 0));
2741 p.drawRect(QRectF(10, 10, 0, 100));
2743 p.drawRect(QRect(10, 10, 100, 0));
2744 p.drawRect(QRect(10, 10, 0, 100));
2746 p.fillRect(QRectF(10, 10, 100, 0), Qt::black);
2747 p.fillRect(QRectF(10, 10, 0, 100), Qt::black);
2749 p.fillRect(QRect(10, 10, 100, 0), Qt::black);
2750 p.fillRect(QRect(10, 10, 0, 100), Qt::black);
2753 void fpe_steepSlopes()
2755 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2757 QImage img(1024, 1024, QImage::Format_ARGB32_Premultiplied);
2759 QFETCH(QTransform, transform);
2760 QFETCH(QLineF, line);
2761 QFETCH(bool, antialiased);
2765 p.setPen(QPen(Qt::black, 1));
2766 p.setRenderHint(QPainter::Antialiasing, antialiased);
2767 p.setTransform(transform);
2772 void fpe_radialGradients()
2774 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2776 QImage img(21, 21, QImage::Format_ARGB32_Premultiplied);
2779 double m = img.width() * 0.5;
2782 p.setRenderHints(QPainter::Antialiasing);
2783 p.setPen(Qt::NoPen);
2784 p.setBrush(QRadialGradient(m, m, m));
2785 p.drawEllipse(img.rect());
2788 #define FPE_TEST(x) \
2789 void tst_QPainter::x() \
2794 #define FPE_TEST(x) \
2795 void tst_QPainter::x() \
2797 QSKIP("Floating point exception checking (fenv.h) not available"); \
2801 FPE_TEST(fpe_rasterizeLine_task232012)
2802 FPE_TEST(fpe_pixmapTransform)
2803 FPE_TEST(fpe_zeroLengthLines)
2804 FPE_TEST(fpe_divByZero)
2805 FPE_TEST(fpe_steepSlopes)
2806 FPE_TEST(fpe_radialGradients)
2808 void tst_QPainter::fpe_steepSlopes_data()
2810 QTest::addColumn<QTransform>("transform");
2811 QTest::addColumn<QLineF>("line");
2812 QTest::addColumn<bool>("antialiased");
2815 const qreal dsin = 0.000014946676875461832484392500630665523431162000633776187896728515625;
2816 const qreal dcos = 0.9999999998882984630910186751862056553363800048828125;
2818 const QTransform transform = QTransform(QMatrix(dcos, dsin, -dsin, dcos, 64, 64));
2819 const QLineF line(2, 2, 2, 6);
2821 QTest::newRow("task 207147 aa") << transform << line << true;
2822 QTest::newRow("task 207147 no aa") << transform << line << false;
2826 QTransform transform;
2827 transform.rotate(0.0000001);
2828 const QLineF line(5, 5, 10, 5);
2830 QTest::newRow("task 166702 aa") << transform << line << true;
2831 QTest::newRow("task 166702 no aa") << transform << line << false;
2835 const QTransform transform;
2836 const QLineF line(2.5, 2.5, 2.5 + 1/256., 60000.5);
2838 QTest::newRow("steep line aa") << transform << line << true;
2839 QTest::newRow("steep line no aa") << transform << line << false;
2843 const QTransform transform;
2844 const QLineF line(2.5, 2.5, 2.5 + 1/256., 1024);
2846 QTest::newRow("steep line 2 aa") << transform << line << true;
2847 QTest::newRow("steep line 2 no aa") << transform << line << false;
2851 const QTransform transform;
2852 const QLineF line(2.5, 2.5, 2.5 + 1/64., 1024);
2854 QTest::newRow("steep line 3 aa") << transform << line << true;
2855 QTest::newRow("steep line 3 no aa") << transform << line << false;
2861 return rand() / (RAND_MAX + 1.0);
2864 QPointF randInRect(const QRectF &rect)
2866 const qreal x = rect.left() + rect.width() * randf();
2867 const qreal y = rect.top() + rect.height() * randf();
2869 return QPointF(x, y);
2872 void tst_QPainter::rasterizer_asserts()
2874 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2876 QRectF middle(QPointF(0, 0), img.size());
2877 QRectF left = middle.translated(-middle.width(), 0);
2878 QRectF right = middle.translated(middle.width(), 0);
2881 img.fill(Qt::white);
2882 p.setCompositionMode(QPainter::CompositionMode_Destination);
2883 for (int i = 0; i < 100000; ++i) {
2885 path.moveTo(randInRect(middle));
2886 path.lineTo(randInRect(left));
2887 path.lineTo(randInRect(right));
2889 p.fillPath(path, Qt::black);
2893 void tst_QPainter::rasterizer_negativeCoords()
2895 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2898 QImage original = img;
2902 p.fillRect(0, 0, 70, 50, Qt::black);
2904 // image should not have changed
2905 QCOMPARE(img.pixel(0, 0), 0x0U);
2906 QCOMPARE(img, original);
2909 void tst_QPainter::blendOverFlow_data()
2911 QTest::addColumn<QImage::Format>("format");
2912 QTest::addColumn<int>("width");
2913 QTest::addColumn<int>("height");
2915 QImage::Format format = QImage::Format_ARGB8555_Premultiplied;
2916 QTest::newRow("555,1,1") << format << 1 << 1;
2917 QTest::newRow("555,2,2") << format << 2 << 2;
2918 QTest::newRow("555,10,10") << format << 10 << 10;
2920 format = QImage::Format_ARGB8565_Premultiplied;
2921 QTest::newRow("565,1,1") << format << 1 << 1;
2922 QTest::newRow("565,2,2") << format << 2 << 2;
2923 QTest::newRow("565,10,10") << format << 10 << 10;
2926 void tst_QPainter::blendOverFlow()
2928 QFETCH(QImage::Format, format);
2930 QFETCH(int, height);
2932 QImage dest(width, height, format);
2933 QImage src(width, height, format);
2937 p.fillRect(0, 0, width, height, Qt::green);
2939 QImage expected = dest;
2943 p.setCompositionMode(QPainter::CompositionMode_Source);
2944 p.fillRect(0, 0, width, height, QColor(0, 255, 0, 6));
2949 p.drawImage(0, 0, src);
2952 QCOMPARE(dest.pixel(0, 0), expected.pixel(0, 0));
2953 QCOMPARE(dest, expected);
2956 void tst_QPainter::largeImagePainting_data()
2958 QTest::addColumn<int>("width");
2959 QTest::addColumn<int>("height");
2960 QTest::addColumn<bool>("antialiased");
2962 QTest::newRow("tall") << 1 << 32767 << false;
2963 QTest::newRow("tall aa") << 1 << 32767 << true;
2964 QTest::newRow("wide") << 32767 << 1 << false;
2965 QTest::newRow("wide aa") << 32767 << 1 << true;
2968 void tst_QPainter::largeImagePainting()
2971 path.addRect(0, 0, 1, 1);
2972 path.addRect(2, 0, 1, 1);
2973 path.addRect(0, 2, 1, 1);
2976 QFETCH(int, height);
2977 QFETCH(bool, antialiased);
2979 QImage img(width, height, QImage::Format_ARGB32_Premultiplied);
2983 p.setPen(Qt::NoPen);
2984 p.setBrush(Qt::white);
2986 p.setRenderHint(QPainter::Antialiasing, antialiased);
2988 for (int i = 0; i < img.width(); i += 4) {
2995 for (int i = 4; i < img.height(); i += 4) {
3000 for (int i = 0; i < img.width(); ++i) {
3002 QCOMPARE(img.pixel(i, 0), 0x0U);
3004 QCOMPARE(img.pixel(i, 0), 0xffffffffU);
3007 for (int i = 1; i < img.height(); ++i) {
3009 QCOMPARE(img.pixel(0, i), 0x0U);
3011 QCOMPARE(img.pixel(0, i), 0xffffffffU);
3015 void tst_QPainter::imageScaling_task206785()
3017 QImage src(32, 2, QImage::Format_ARGB32_Premultiplied);
3018 src.fill(0xffffffff);
3020 QImage dst(128, 128, QImage::Format_ARGB32_Premultiplied);
3022 QImage expected(128, 128, QImage::Format_ARGB32_Premultiplied);
3023 expected.fill(0xffffffff);
3025 for (int i = 1; i < 5; ++i) {
3026 qreal scale = i / qreal(5);
3028 dst.fill(0xff000000);
3031 p.scale(dst.width() / qreal(src.width()), scale);
3033 for (int y = 0; y * scale < dst.height(); ++y)
3034 p.drawImage(0, y, src);
3038 QCOMPARE(dst, expected);
3042 #define FOR_EACH_NEIGHBOR_8 for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if (dx != 0 || dy != 0)
3043 #define FOR_EACH_NEIGHBOR_4 for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if ((dx == 0) != (dy == 0))
3045 uint qHash(const QPoint &point)
3047 return qHash(qMakePair(point.x(), point.y()));
3050 bool verifyOutlineFillConsistency(const QImage &img, QRgb outside, QRgb inside, QRgb outline)
3052 if (img.pixel(img.width() / 2, img.height() / 2) != inside)
3055 int x = img.width() / 2;
3056 int y = img.height() / 2;
3058 while (img.pixel(++x, y) == inside)
3061 if (img.pixel(x, y) != outline)
3064 QQueue<QPoint> discovered;
3065 discovered.enqueue(QPoint(x, y));
3067 QVector<bool> visited(img.width() * img.height());
3068 visited.fill(false);
3070 while (!discovered.isEmpty()) {
3071 QPoint p = discovered.dequeue();
3072 QRgb pixel = img.pixel(p.x(), p.y());
3074 bool &v = visited[p.y() * img.width() + p.x()];
3079 if (pixel == outline) {
3080 FOR_EACH_NEIGHBOR_8 {
3081 QPoint x(p.x() + dx, p.y() + dy);
3082 discovered.enqueue(x);
3085 FOR_EACH_NEIGHBOR_4 {
3086 if ((dx == 0) == (dy == 0))
3088 QRgb neighbor = img.pixel(p.x() + dx, p.y() + dy);
3089 if ((pixel == inside && neighbor == outside) ||
3090 (pixel == outside && neighbor == inside))
3099 #undef FOR_EACH_NEIGHBOR_8
3100 #undef FOR_EACH_NEIGHBOR_4
3102 void tst_QPainter::outlineFillConsistency()
3104 QImage dst(256, 256, QImage::Format_ARGB32_Premultiplied);
3107 poly << QPointF(5, -100) << QPointF(-70, 20) << QPointF(95, 25);
3110 QBrush brush(Qt::black);
3112 QRgb background = 0xffffffff;
3113 for (int i = 0; i < 360; ++i) {
3114 dst.fill(background);
3117 p.translate(dst.width() / 2, dst.height() / 2);
3119 QPolygonF copy = poly;
3120 for (int j = 0; j < copy.size(); ++j)
3121 copy[j] = QTransform().rotate(i).map(copy[j]);
3125 p.drawPolygon(copy);
3128 QVERIFY(verifyOutlineFillConsistency(dst, background, brush.color().rgba(), pen.color().rgba()));
3132 void tst_QPainter::drawImage_task217400_data()
3134 QTest::addColumn<QImage::Format>("format");
3136 QTest::newRow("444") << QImage::Format_ARGB4444_Premultiplied;
3137 QTest::newRow("555") << QImage::Format_ARGB8555_Premultiplied;
3138 QTest::newRow("565") << QImage::Format_ARGB8565_Premultiplied;
3139 // QTest::newRow("666") << QImage::Format_ARGB6666_Premultiplied;
3140 QTest::newRow("888p") << QImage::Format_ARGB32_Premultiplied;
3141 QTest::newRow("888") << QImage::Format_ARGB32;
3144 void tst_QPainter::drawImage_task217400()
3146 QFETCH(QImage::Format, format);
3148 const QImage src = QImage(QFINDTESTDATA("task217400.png"))
3149 .convertToFormat(format);
3150 QVERIFY(!src.isNull());
3152 QImage expected(src.size(), format);
3154 QPainter p(&expected);
3155 p.fillRect(0, 0, expected.width(), expected.height(), Qt::white);
3156 p.drawImage(0, 0, src);
3159 for (int i = 1; i <= 4; ++i) {
3160 QImage dest(src.width() + i, src.height(), format);
3163 p.fillRect(0, 0, dest.width(), dest.height(), Qt::white);
3164 p.drawImage(i, 0, src);
3167 const QImage result = dest.copy(i, 0, src.width(), src.height());
3169 QCOMPARE(result, expected);
3173 void tst_QPainter::drawImage_task258776()
3175 QImage src(16, 16, QImage::Format_RGB888);
3176 QImage dest(33, 33, QImage::Format_RGB888);
3178 dest.fill(0xff0000);
3180 QPainter painter(&dest);
3181 painter.drawImage(QRectF(0.499, 0.499, 32, 32), src, QRectF(0, 0, 16, 16));
3184 QImage expected(33, 33, QImage::Format_RGB32);
3185 expected.fill(0xff0000);
3187 painter.begin(&expected);
3188 painter.drawImage(QRectF(0, 0, 32, 32), src);
3191 dest = dest.convertToFormat(QImage::Format_RGB32);
3193 dest.save("dest.png");
3194 expected.save("expected.png");
3195 QCOMPARE(dest, expected);
3198 void tst_QPainter::clipRectSaveRestore()
3200 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3204 p.setClipRect(QRect(0, 0, 10, 10));
3206 p.setClipRect(QRect(5, 5, 5, 5), Qt::IntersectClip);
3208 p.fillRect(0, 0, 64, 64, Qt::black);
3211 QCOMPARE(img.pixel(0, 0), QColor(Qt::black).rgba());
3214 void tst_QPainter::clippedImage()
3216 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
3219 QImage src(16, 16, QImage::Format_RGB32);
3220 src.fill(QColor(Qt::red).rgba());
3223 p.setClipRect(QRect(1, 1, 14, 14));
3224 p.drawImage(0, 0, src);
3227 QCOMPARE(img.pixel(0, 0), 0x0U);
3228 QCOMPARE(img.pixel(1, 1), src.pixel(1, 1));
3231 void tst_QPainter::stateResetBetweenQPainters()
3233 QImage img(16, 16, QImage::Format_ARGB32);
3237 p.setCompositionMode(QPainter::CompositionMode_Source);
3238 p.fillRect(0, 0, 16, 16, Qt::red);
3243 p2.fillRect(0, 0, 16, 16, QColor(0, 0, 255, 63));
3246 img.save("foo.png");
3248 QVERIFY(img.pixel(0, 0) != qRgba(0, 0, 255, 63));
3249 QVERIFY(qRed(img.pixel(0, 0)) > 0); // We didn't erase the red channel...
3250 QVERIFY(qBlue(img.pixel(0, 0)) < 255); // We blended the blue channel
3253 void tst_QPainter::drawRect_task215378()
3255 QImage img(11, 11, QImage::Format_ARGB32_Premultiplied);
3256 img.fill(QColor(Qt::white).rgba());
3259 p.setPen(QColor(127, 127, 127, 127));
3260 p.drawRect(0, 0, 10, 10);
3263 QCOMPARE(img.pixel(0, 0), img.pixel(1, 0));
3264 QCOMPARE(img.pixel(0, 0), img.pixel(0, 1));
3265 QVERIFY(img.pixel(0, 0) != img.pixel(1, 1));
3268 void tst_QPainter::drawRect_task247505()
3270 QImage a(10, 10, QImage::Format_ARGB32_Premultiplied);
3275 p.setPen(Qt::NoPen);
3276 p.setBrush(Qt::black);
3277 p.drawRect(QRectF(10, 0, -10, 10));
3280 p.setPen(Qt::NoPen);
3281 p.setBrush(Qt::black);
3282 p.drawRect(QRectF(0, 0, 10, 10));
3288 void tst_QPainter::drawImage_data()
3290 QTest::addColumn<int>("x");
3291 QTest::addColumn<int>("y");
3292 QTest::addColumn<int>("w");
3293 QTest::addColumn<int>("h");
3294 QTest::addColumn<QImage::Format>("srcFormat");
3295 QTest::addColumn<QImage::Format>("dstFormat");
3297 for (int srcFormat = QImage::Format_Mono; srcFormat < QImage::NImageFormats; ++srcFormat) {
3298 for (int dstFormat = QImage::Format_Mono; dstFormat < QImage::NImageFormats; ++dstFormat) {
3299 if (dstFormat == QImage::Format_Indexed8)
3301 for (int odd_x = 0; odd_x <= 1; ++odd_x) {
3302 for (int odd_width = 0; odd_width <= 1; ++odd_width) {
3303 QString description =
3304 QString("srcFormat %1, dstFormat %2, odd x: %3, odd width: %4")
3305 .arg(srcFormat).arg(dstFormat).arg(odd_x).arg(odd_width);
3307 QTest::newRow(qPrintable(description)) << (10 + odd_x) << 10 << (20 + odd_width) << 20
3308 << QImage::Format(srcFormat)
3309 << QImage::Format(dstFormat);
3316 bool verifyImage(const QImage &img, int x, int y, int w, int h, uint background)
3318 int imgWidth = img.width();
3319 int imgHeight = img.height();
3320 for (int i = 0; i < imgHeight; ++i) {
3321 for (int j = 0; j < imgWidth; ++j) {
3322 uint pixel = img.pixel(j, i);
3323 bool outside = j < x || j >= (x + w) || i < y || i >= (y + h);
3324 if (outside != (pixel == background)) {
3325 //printf("%d %d, expected %x, got %x, outside: %d\n", x, y, background, pixel, outside);
3334 void tst_QPainter::drawImage()
3340 QFETCH(QImage::Format, srcFormat);
3341 QFETCH(QImage::Format, dstFormat);
3343 QImage dst(40, 40, QImage::Format_RGB32);
3344 dst.fill(0xffffffff);
3346 dst = dst.convertToFormat(dstFormat);
3347 uint background = dst.pixel(0, 0);
3349 QImage src(w, h, QImage::Format_RGB32);
3350 src.fill(0xff000000);
3351 src = src.convertToFormat(srcFormat);
3354 p.drawImage(x, y, src);
3357 QVERIFY(verifyImage(dst, x, y, w, h, background));
3360 void tst_QPainter::imageCoordinateLimit()
3362 QImage img(64, 40000, QImage::Format_MonoLSB);
3364 p.drawText(10, 36000, QLatin1String("foo"));
3365 p.setPen(QPen(Qt::black, 2));
3366 p.drawLine(10, 0, 60, 40000);
3368 p.setRenderHint(QPainter::Antialiasing);
3369 p.drawLine(10, 0, 60, 40000);
3373 void tst_QPainter::imageBlending_data()
3375 QTest::addColumn<QImage::Format>("sourceFormat");
3376 QTest::addColumn<QImage::Format>("destFormat");
3377 QTest::addColumn<int>("error");
3379 int error_rgb565 = ((1<<3) + (1<<2) + (1<<3));
3380 QTest::newRow("rgb565_on_rgb565") << QImage::Format_RGB16
3381 << QImage::Format_RGB16
3383 QTest::newRow("argb8565_on_rgb565") << QImage::Format_ARGB8565_Premultiplied
3384 << QImage::Format_RGB16
3387 QTest::newRow("rgb32_on_rgb565") << QImage::Format_RGB32
3388 << QImage::Format_RGB16
3391 QTest::newRow("argb32pm_on_rgb565") << QImage::Format_ARGB32_Premultiplied
3392 << QImage::Format_RGB16
3396 int diffColor(quint32 ap, quint32 bp)
3398 int a = qAlpha(ap) - qAlpha(bp);
3399 int r = qRed(ap) - qRed(bp);
3400 int b = qBlue(ap) - qBlue(bp);
3401 int g = qBlue(ap) - qBlue(bp);
3403 return qAbs(a) + qAbs(r) + qAbs(g) + qAbs(b);
3406 // this test assumes premultiplied pixels...
3408 void tst_QPainter::imageBlending()
3410 QFETCH(QImage::Format, sourceFormat);
3411 QFETCH(QImage::Format, destFormat);
3416 QImage orig_dest(6, 6, QImage::Format_ARGB32_Premultiplied);
3418 QPainter p(&orig_dest);
3419 p.fillRect(0, 0, 6, 3, QColor::fromRgbF(1, 0, 0));
3420 p.fillRect(3, 0, 3, 6, QColor::fromRgbF(0, 0, 1, 0.5));
3422 dest = orig_dest.convertToFormat(destFormat);
3424 // An image like this: (r = red, m = magenta, b = light alpha blue, 0 = transparent)
3435 QImage orig_source(6, 6, QImage::Format_ARGB32_Premultiplied);
3436 orig_source.fill(0);
3437 QPainter p(&orig_source);
3438 p.fillRect(1, 1, 4, 4, QColor::fromRgbF(0, 1, 0, 0.5));
3439 p.fillRect(2, 2, 2, 2, QColor::fromRgbF(0, 1, 0));
3441 source = orig_source.convertToFormat(sourceFormat);
3443 // An image like this: (0 = transparent, . = green at 0.5 alpha, g = opaque green.
3453 p.drawImage(0, 0, source);
3464 // the g pixels, always green..
3465 QVERIFY(diffColor(dest.pixel(2, 2), 0xff00ff00) <= error); // g
3467 if (source.hasAlphaChannel()) {
3468 QVERIFY(diffColor(dest.pixel(0, 0), 0xffff0000) <= error); // r
3469 QVERIFY(diffColor(dest.pixel(5, 0), 0xff7f007f) <= error); // m
3470 QVERIFY(diffColor(dest.pixel(1, 1), 0xff7f7f00) <= error); // r.
3471 QVERIFY(diffColor(dest.pixel(4, 1), 0xff3f7f3f) <= error); // m.
3472 if (dest.hasAlphaChannel()) {
3473 QVERIFY(diffColor(dest.pixel(1, 3), 0x7f007f00) <= error); // .
3474 QVERIFY(diffColor(dest.pixel(4, 3), 0x7f007f3f) <= error); // b.
3475 QVERIFY(diffColor(dest.pixel(4, 3), 0x7f007f3f) <= error); // b.
3476 QVERIFY(diffColor(dest.pixel(4, 4), 0x7f00007f) <= error); // b
3477 QVERIFY(diffColor(dest.pixel(4, 0), 0) <= 0); // 0
3480 QVERIFY(diffColor(dest.pixel(0, 0), 0xff000000) <= 0);
3481 QVERIFY(diffColor(dest.pixel(1, 1), 0xff007f00) <= error);
3485 void tst_QPainter::imageBlending_clipped()
3487 QImage src(20, 20, QImage::Format_RGB16);
3489 p.fillRect(src.rect(), Qt::red);
3492 QImage dst(40, 20, QImage::Format_RGB16);
3494 p.fillRect(dst.rect(), Qt::white);
3497 QImage expected = dst;
3500 p.setClipRect(QRect(23, 0, 20, 20));
3502 // should be completely clipped
3503 p.drawImage(QRectF(3, 0, 20, 20), src);
3506 // dst should be left unchanged
3507 QCOMPARE(dst, expected);
3510 void tst_QPainter::paintOnNullPixmap()
3512 QPixmap pix(16, 16);
3515 QPainter p(&textPixmap);
3516 p.drawPixmap(10, 10, pix);
3519 QPixmap textPixmap2(16,16);
3520 p.begin(&textPixmap2);
3524 void tst_QPainter::checkCompositionMode()
3526 QImage refImage(50,50,QImage::Format_ARGB32);
3527 QPainter painter(&refImage);
3528 painter.fillRect(QRect(0,0,50,50),Qt::blue);
3530 QImage testImage(50,50,QImage::Format_ARGB32);
3531 QPainter p(&testImage);
3532 p.fillRect(QRect(0,0,50,50),Qt::red);
3534 p.setCompositionMode(QPainter::CompositionMode_SourceOut);
3536 p.fillRect(QRect(0,0,50,50),Qt::blue);
3538 QCOMPARE(refImage.pixel(20,20),testImage.pixel(20,20));
3541 static QLinearGradient inverseGradient(QLinearGradient g)
3543 QLinearGradient g2 = g;
3545 QGradientStops stops = g.stops();
3547 QGradientStops inverse;
3548 foreach (QGradientStop stop, stops)
3549 inverse << QGradientStop(1 - stop.first, stop.second);
3551 g2.setStops(inverse);
3555 void tst_QPainter::linearGradientSymmetry_data()
3557 QTest::addColumn<QGradientStops>("stops");
3559 if (sizeof(qreal) != sizeof(float)) {
3560 QGradientStops stops;
3561 stops << qMakePair(qreal(0.0), QColor(Qt::blue));
3562 stops << qMakePair(qreal(0.2), QColor(220, 220, 220, 0));
3563 stops << qMakePair(qreal(0.6), QColor(Qt::red));
3564 stops << qMakePair(qreal(0.9), QColor(220, 220, 220, 255));
3565 stops << qMakePair(qreal(1.0), QColor(Qt::black));
3566 QTest::newRow("multiple stops") << stops;
3570 QGradientStops stops;
3571 stops << qMakePair(qreal(0.0), QColor(Qt::blue));
3572 stops << qMakePair(qreal(1.0), QColor(Qt::black));
3573 QTest::newRow("two stops") << stops;
3576 if (sizeof(qreal) != sizeof(float)) {
3577 QGradientStops stops;
3578 stops << qMakePair(qreal(0.3), QColor(Qt::blue));
3579 stops << qMakePair(qreal(0.6), QColor(Qt::black));
3580 QTest::newRow("two stops 2") << stops;
3584 void tst_QPainter::linearGradientSymmetry()
3586 QFETCH(QGradientStops, stops);
3588 QImage a(64, 8, QImage::Format_ARGB32_Premultiplied);
3589 QImage b(64, 8, QImage::Format_ARGB32_Premultiplied);
3594 QLinearGradient gradient(QRectF(b.rect()).topLeft(), QRectF(b.rect()).topRight());
3595 gradient.setStops(stops);
3598 pa.fillRect(a.rect(), gradient);
3602 pb.fillRect(b.rect(), inverseGradient(gradient));
3605 b = b.mirrored(true);
3609 void tst_QPainter::gradientInterpolation()
3611 QImage image(256, 8, QImage::Format_ARGB32_Premultiplied);
3614 QLinearGradient gradient(QRectF(image.rect()).topLeft(), QRectF(image.rect()).topRight());
3615 gradient.setColorAt(0.0, QColor(255, 0, 0, 0));
3616 gradient.setColorAt(1.0, Qt::blue);
3619 painter.begin(&image);
3620 painter.fillRect(image.rect(), gradient);
3623 const QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(3));
3625 for (int i = 0; i < 256; ++i) {
3626 QCOMPARE(qAlpha(line[i]), qBlue(line[i])); // bright blue
3627 QVERIFY(qAbs(qAlpha(line[i]) - i) < 3); // linear alpha
3628 QCOMPARE(qRed(line[i]), 0); // no red component
3629 QCOMPARE(qGreen(line[i]), 0); // no green component
3632 gradient.setInterpolationMode(QGradient::ComponentInterpolation);
3635 painter.begin(&image);
3636 painter.fillRect(image.rect(), gradient);
3639 for (int i = 1; i < 256; ++i) {
3641 QVERIFY(qRed(line[i]) >= qBlue(line[i])); // red is dominant
3643 QVERIFY(qRed(line[i]) <= qBlue(line[i])); // blue is dominant
3645 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
3646 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
3647 QVERIFY(qAbs(qAlpha(line[i]) - i) < 3); // linear alpha
3648 QCOMPARE(qGreen(line[i]), 0); // no green component
3652 void tst_QPainter::drawPolygon()
3654 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
3656 QPainterPathStroker stroker;
3657 stroker.setWidth(1.5);
3663 QPolygonF poly = stroker.createStroke(path).toFillPolygon();
3665 img.fill(0xffffffff);
3667 p.setRenderHint(QPainter::Antialiasing);
3668 p.setBrush(Qt::red);
3669 p.setPen(Qt::NoPen);
3670 p.drawPolygon(poly);
3671 p.translate(64, 64);
3672 p.drawPolygon(poly);
3675 QImage a = img.copy();
3677 img.fill(0xffffffff);
3679 p.setRenderHint(QPainter::Antialiasing);
3680 p.setBrush(Qt::red);
3681 p.setPen(Qt::NoPen);
3682 p.translate(64, 64);
3683 p.drawPolygon(poly);
3685 p.drawPolygon(poly);
3691 void tst_QPainter::inactivePainter()
3693 // This test succeeds if it doesn't segfault.
3697 QRegion region(QRect(20, 20, 60, 40));
3698 QPolygonF polygon(QVector<QPointF>() << QPointF(0, 0) << QPointF(12, 0) << QPointF(8, 6));
3699 path.addPolygon(polygon);
3705 p.setBackground(QBrush(Qt::blue));
3708 p.setBrush(Qt::red);
3709 p.setBrush(Qt::NoBrush);
3710 p.setBrush(QBrush(Qt::white, Qt::DiagCrossPattern));
3713 p.setBackgroundMode(Qt::OpaqueMode);
3715 p.boundingRect(QRectF(0, 0, 100, 20), Qt::AlignCenter, QLatin1String("Hello, World!"));
3716 p.boundingRect(QRect(0, 0, 100, 20), Qt::AlignCenter, QLatin1String("Hello, World!"));
3719 p.setBrushOrigin(QPointF(12, 34));
3720 p.setBrushOrigin(QPoint(12, 34));
3725 p.setClipPath(path);
3726 p.setClipRect(QRectF(42, 42, 42, 42));
3727 p.setClipRect(QRect(42, 42, 42, 42));
3728 p.setClipRegion(region);
3729 p.setClipping(true);
3732 p.combinedTransform();
3734 p.compositionMode();
3735 p.setCompositionMode(QPainter::CompositionMode_Plus);
3739 p.deviceTransform();
3742 p.setFont(QFont(QLatin1String("Times"), 24));
3747 p.layoutDirection();
3748 p.setLayoutDirection(Qt::RightToLeft);
3754 p.setPen(QPen(Qt::red));
3755 p.setPen(Qt::green);
3756 p.setPen(Qt::NoPen);
3759 p.setRenderHint(QPainter::Antialiasing, true);
3760 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
3769 p.viewTransformEnabled();
3770 p.setViewTransformEnabled(true);
3773 p.setViewport(QRect(10, 10, 620, 460));
3776 p.setWindow(QRect(10, 10, 620, 460));
3779 p.setWorldMatrix(QMatrix().translate(43, 21), true);
3780 p.setWorldMatrixEnabled(true);
3783 p.setTransform(QTransform().translate(12, 34), true);
3786 p.setWorldTransform(QTransform().scale(0.5, 0.5), true);
3789 bool testCompositionMode(int src, int dst, int expected, QPainter::CompositionMode op, qreal opacity = 1.0)
3791 // The test image needs to be large enough to test SIMD code
3792 const QSize imageSize(100, 100);
3794 QImage actual(imageSize, QImage::Format_ARGB32_Premultiplied);
3795 actual.fill(QColor(dst, dst, dst).rgb());
3797 QPainter p(&actual);
3798 p.setCompositionMode(op);
3799 p.setOpacity(opacity);
3800 p.fillRect(QRect(QPoint(), imageSize), QColor(src, src, src));
3803 if (qRed(actual.pixel(0, 0)) != expected) {
3804 qDebug("Fail: mode %d, src[%d] dst [%d] actual [%d] expected [%d]", op,
3805 src, dst, qRed(actual.pixel(0, 0)), expected);
3808 QImage refImage(imageSize, QImage::Format_ARGB32_Premultiplied);
3809 refImage.fill(QColor(expected, expected, expected).rgb());
3810 return actual == refImage;
3814 void tst_QPainter::extendedBlendModes()
3816 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Plus));
3817 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Plus));
3818 QVERIFY(testCompositionMode(127, 128, 255, QPainter::CompositionMode_Plus));
3819 QVERIFY(testCompositionMode(127, 0, 127, QPainter::CompositionMode_Plus));
3820 QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Plus));
3821 QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Plus));
3822 QVERIFY(testCompositionMode( 0, 255, 255, QPainter::CompositionMode_Plus));
3823 QVERIFY(testCompositionMode(128, 128, 255, QPainter::CompositionMode_Plus));
3825 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Plus, 0.3));
3826 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Plus, 0.3));
3827 QVERIFY(testCompositionMode(127, 128, 165, QPainter::CompositionMode_Plus, 0.3));
3828 QVERIFY(testCompositionMode(127, 0, 37, QPainter::CompositionMode_Plus, 0.3));
3829 QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Plus, 0.3));
3830 QVERIFY(testCompositionMode(255, 0, 75, QPainter::CompositionMode_Plus, 0.3));
3831 QVERIFY(testCompositionMode( 0, 255, 255, QPainter::CompositionMode_Plus, 0.3));
3832 QVERIFY(testCompositionMode(128, 128, 166, QPainter::CompositionMode_Plus, 0.3));
3833 QVERIFY(testCompositionMode(186, 200, 255, QPainter::CompositionMode_Plus, 0.3));
3835 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Multiply));
3836 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Multiply));
3837 QVERIFY(testCompositionMode(127, 255, 127, QPainter::CompositionMode_Multiply));
3838 QVERIFY(testCompositionMode(255, 127, 127, QPainter::CompositionMode_Multiply));
3839 QVERIFY(testCompositionMode( 63, 255, 63, QPainter::CompositionMode_Multiply));
3840 QVERIFY(testCompositionMode(255, 63, 63, QPainter::CompositionMode_Multiply));
3841 QVERIFY(testCompositionMode(127, 127, 63, QPainter::CompositionMode_Multiply));
3843 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Screen));
3844 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Screen));
3845 QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Screen));
3846 QVERIFY(testCompositionMode(255, 63, 255, QPainter::CompositionMode_Screen));
3847 QVERIFY(testCompositionMode( 63, 0, 63, QPainter::CompositionMode_Screen));
3848 QVERIFY(testCompositionMode( 0, 63, 63, QPainter::CompositionMode_Screen));
3849 QVERIFY(testCompositionMode(127, 127, 191, QPainter::CompositionMode_Screen));
3851 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Overlay));
3852 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Overlay));
3853 QVERIFY(testCompositionMode( 63, 63, 31, QPainter::CompositionMode_Overlay));
3854 QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Overlay));
3856 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Darken));
3857 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Darken));
3858 QVERIFY(testCompositionMode( 63, 63, 63, QPainter::CompositionMode_Darken));
3859 QVERIFY(testCompositionMode( 63, 255, 63, QPainter::CompositionMode_Darken));
3860 QVERIFY(testCompositionMode(255, 63, 63, QPainter::CompositionMode_Darken));
3861 QVERIFY(testCompositionMode( 63, 127, 63, QPainter::CompositionMode_Darken));
3862 QVERIFY(testCompositionMode(127, 63, 63, QPainter::CompositionMode_Darken));
3864 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Lighten));
3865 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Lighten));
3866 QVERIFY(testCompositionMode( 63, 63, 63, QPainter::CompositionMode_Lighten));
3867 QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Lighten));
3868 QVERIFY(testCompositionMode(255, 63, 255, QPainter::CompositionMode_Lighten));
3869 QVERIFY(testCompositionMode( 63, 127, 127, QPainter::CompositionMode_Lighten));
3870 QVERIFY(testCompositionMode(127, 63, 127, QPainter::CompositionMode_Lighten));
3872 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_ColorDodge));
3873 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_ColorDodge));
3874 QVERIFY(testCompositionMode( 63, 127, 169, QPainter::CompositionMode_ColorDodge));
3875 QVERIFY(testCompositionMode(191, 127, 255, QPainter::CompositionMode_ColorDodge));
3876 QVERIFY(testCompositionMode(127, 191, 255, QPainter::CompositionMode_ColorDodge));
3878 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_ColorBurn));
3879 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_ColorBurn));
3880 QVERIFY(testCompositionMode(127, 127, 0, QPainter::CompositionMode_ColorBurn));
3881 QVERIFY(testCompositionMode(128, 128, 2, QPainter::CompositionMode_ColorBurn));
3882 QVERIFY(testCompositionMode(191, 127, 84, QPainter::CompositionMode_ColorBurn));
3884 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_HardLight));
3885 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_HardLight));
3886 QVERIFY(testCompositionMode(127, 127, 127, QPainter::CompositionMode_HardLight));
3887 QVERIFY(testCompositionMode( 63, 63, 31, QPainter::CompositionMode_HardLight));
3888 QVERIFY(testCompositionMode(127, 63, 63, QPainter::CompositionMode_HardLight));
3890 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_SoftLight));
3891 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_SoftLight));
3892 QVERIFY(testCompositionMode(127, 127, 126, QPainter::CompositionMode_SoftLight));
3893 QVERIFY(testCompositionMode( 63, 63, 39, QPainter::CompositionMode_SoftLight));
3894 QVERIFY(testCompositionMode(127, 63, 62, QPainter::CompositionMode_SoftLight));
3896 QVERIFY(testCompositionMode(255, 255, 0, QPainter::CompositionMode_Difference));
3897 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Difference));
3898 QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Difference));
3899 QVERIFY(testCompositionMode(127, 127, 0, QPainter::CompositionMode_Difference));
3900 QVERIFY(testCompositionMode(127, 128, 1, QPainter::CompositionMode_Difference));
3901 QVERIFY(testCompositionMode(127, 63, 64, QPainter::CompositionMode_Difference));
3902 QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Difference));
3904 QVERIFY(testCompositionMode(255, 255, 0, QPainter::CompositionMode_Exclusion));
3905 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Exclusion));
3906 QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Exclusion));
3907 QVERIFY(testCompositionMode(127, 127, 127, QPainter::CompositionMode_Exclusion));
3908 QVERIFY(testCompositionMode( 63, 127, 127, QPainter::CompositionMode_Exclusion));
3909 QVERIFY(testCompositionMode( 63, 63, 95, QPainter::CompositionMode_Exclusion));
3910 QVERIFY(testCompositionMode(191, 191, 96, QPainter::CompositionMode_Exclusion));
3913 void tst_QPainter::zeroOpacity()
3915 QImage source(1, 1, QImage::Format_ARGB32_Premultiplied);
3916 source.fill(0xffffffff);
3918 QImage target(1, 1, QImage::Format_RGB32);
3919 target.fill(0xff000000);
3921 QPainter p(&target);
3923 p.drawImage(0, 0, source);
3926 QCOMPARE(target.pixel(0, 0), 0xff000000);
3929 void tst_QPainter::clippingBug()
3931 QImage img(32, 32, QImage::Format_ARGB32_Premultiplied);
3934 QImage expected = img;
3935 QPainter p(&expected);
3936 p.fillRect(1, 1, 30, 30, Qt::red);
3940 path.addRect(1, 1, 30, 30);
3941 path.addRect(1, 1, 30, 30);
3942 path.addRect(1, 1, 30, 30);
3945 p.setClipPath(path);
3946 p.fillRect(0, 0, 32, 32, Qt::red);
3949 QCOMPARE(img, expected);
3952 void tst_QPainter::emptyClip()
3954 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3956 p.setRenderHints(QPainter::Antialiasing);
3957 p.setClipRect(0, 32, 64, 0);
3958 p.fillRect(0, 0, 64, 64, Qt::white);
3962 path.lineTo(64, 64);
3963 path.lineTo(40, 64);
3964 path.lineTo(40, 80);
3967 p.fillPath(path, Qt::green);
3970 void tst_QPainter::drawImage_1x1()
3972 QImage source(1, 1, QImage::Format_ARGB32_Premultiplied);
3973 source.fill(0xffffffff);
3975 QImage img(32, 32, QImage::Format_ARGB32_Premultiplied);
3976 img.fill(0xff000000);
3978 p.drawImage(QRectF(0.9, 0.9, 32, 32), source);
3981 QImage expected = img;
3982 expected.fill(0xff000000);
3984 p.fillRect(1, 1, 31, 31, Qt::white);
3987 QCOMPARE(img, expected);
3990 void tst_QPainter::taskQT4444_dontOverflowDashOffset()
3996 pen.setStyle(Qt::DashDotLine);
3999 point[0] = QPointF(182.50868749707968,347.78457234212630);
4000 point[1] = QPointF(182.50868749707968,107.22501998401277);
4001 point[2] = QPointF(182.50868749707968,107.22501998401277);
4002 point[3] = QPointF(520.46600762283651,107.22501998401277);
4004 QImage crashImage(QSize(1000, 120), QImage::Format_ARGB32_Premultiplied);
4005 p.begin(&crashImage);
4007 p.drawLines(point, 2);
4010 QVERIFY(true); // Don't crash
4013 void tst_QPainter::painterBegin()
4016 QImage indexed8Image(16, 16, QImage::Format_Indexed8);
4017 QImage rgb32Image(16, 16, QImage::Format_RGB32);
4018 QImage argb32Image(16, 16, QImage::Format_ARGB32_Premultiplied);
4022 // Painting on null image should fail.
4023 QVERIFY(!p.begin(&nullImage));
4025 // Check that the painter is not messed up by using it on another image.
4026 QVERIFY(p.begin(&rgb32Image));
4029 // If painting on indexed8 image fails, the painter state should still be OK.
4030 if (p.begin(&indexed8Image))
4032 QVERIFY(p.begin(&rgb32Image));
4035 // Try opening a painter on the two different images.
4036 QVERIFY(p.begin(&rgb32Image));
4037 QVERIFY(!p.begin(&argb32Image));
4040 // Try opening two painters on the same image.
4041 QVERIFY(p.begin(&rgb32Image));
4043 QVERIFY(!q.begin(&rgb32Image));
4047 // Try ending an inactive painter.
4051 void tst_QPainter::setPenColor(QPainter& p)
4053 p.setPen(Qt::NoPen);
4055 // Setting color, then style
4056 // Should work even though the pen is "NoPen with color", temporarily.
4057 QPen newPen(p.pen());
4058 newPen.setColor(Qt::red);
4059 QCOMPARE(p.pen().style(), newPen.style());
4060 QCOMPARE(p.pen().style(), Qt::NoPen);
4063 QCOMPARE(p.pen().color().name(), QString("#ff0000"));
4065 QPen newPen2(p.pen());
4066 newPen2.setStyle(Qt::SolidLine);
4069 QCOMPARE(p.pen().color().name(), QString("#ff0000"));
4072 void tst_QPainter::setPenColorOnImage()
4074 QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
4079 void tst_QPainter::setPenColorOnPixmap()
4081 QPixmap pix(10, 10);
4086 #ifndef QT_NO_WIDGETS
4087 class TestProxy : public QGraphicsProxyWidget
4090 TestProxy() : QGraphicsProxyWidget() {}
4091 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
4093 QGraphicsProxyWidget::paint(painter, option, widget);
4094 deviceTransform = painter->deviceTransform();
4096 QTransform deviceTransform;
4099 class TestWidget : public QWidget
4103 TestWidget() : QWidget(), painted(false) {}
4104 void paintEvent(QPaintEvent *)
4107 deviceTransform = p.deviceTransform();
4108 worldTransform = p.worldTransform();
4111 QTransform deviceTransform;
4112 QTransform worldTransform;
4116 void tst_QPainter::QTBUG5939_attachPainterPrivate()
4118 QWidget *w = new QWidget();
4119 QGraphicsScene *scene = new QGraphicsScene();
4120 QGraphicsView *view = new QGraphicsView(scene, w);
4122 TestProxy *proxy = new TestProxy();
4123 TestWidget *widget = new TestWidget();
4124 proxy->setWidget(widget);
4125 scene->addItem(proxy);
4127 w->resize(scene->sceneRect().size().toSize());
4130 QTRY_VERIFY(widget->painted);
4132 QVERIFY(widget->worldTransform.isIdentity());
4133 QCOMPARE(widget->deviceTransform, proxy->deviceTransform);
4137 void tst_QPainter::clipBoundingRect()
4139 QPixmap pix(500, 500);
4143 // Test a basic rectangle
4144 p.setClipRect(100, 100, 200, 100);
4145 QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4146 QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4147 p.setClipRect(120, 120, 20, 20, Qt::IntersectClip);
4148 QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4149 QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4151 // Test a basic float rectangle
4152 p.setClipRect(QRectF(100, 100, 200, 100));
4153 QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4154 QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4155 p.setClipRect(QRectF(120, 120, 20, 20), Qt::IntersectClip);
4156 QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4157 QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4159 // Test a basic path + region
4161 path.addRect(100, 100, 200, 100);
4162 p.setClipPath(path);
4163 QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4164 QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4165 p.setClipRegion(QRegion(120, 120, 20, 20), Qt::IntersectClip);
4166 QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4167 QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4169 p.setClipRect(0, 0, 500, 500);
4170 p.translate(250, 250);
4171 for (int i=0; i<360; ++i) {
4173 p.setClipRect(-100, -100, 200, 200, Qt::IntersectClip);
4175 QVERIFY(p.clipBoundingRect().contains(QRectF(-100, -100, 200, 200)));
4176 QVERIFY(!p.clipBoundingRect().contains(QRectF(-250, -250, 500, 500)));
4180 void tst_QPainter::drawText_subPixelPositionsInRaster_qtbug5053()
4182 #if !defined(Q_OS_MAC)
4183 QSKIP("Only Mac supports sub pixel positions in raster engine currently");
4185 QFontMetricsF fm(qApp->font());
4187 QImage baseLine(fm.width(QChar::fromLatin1('e')), fm.height(), QImage::Format_RGB32);
4188 baseLine.fill(Qt::white);
4190 QPainter p(&baseLine);
4191 p.setRenderHint(QPainter::Qt4CompatiblePainting);
4192 p.drawText(0, fm.ascent(), QString::fromLatin1("e"));
4195 bool foundDifferentRasterization = false;
4196 for (int i=1; i<12; ++i) {
4197 QImage comparison(baseLine.size(), QImage::Format_RGB32);
4198 comparison.fill(Qt::white);
4201 QPainter p(&comparison);
4202 p.setRenderHint(QPainter::Qt4CompatiblePainting);
4203 p.drawText(QPointF(i / 12.0, fm.ascent()), QString::fromLatin1("e"));
4206 if (comparison != baseLine) {
4207 foundDifferentRasterization = true;
4212 QVERIFY(foundDifferentRasterization);
4215 void tst_QPainter::drawPointScaled()
4217 QImage image(32, 32, QImage::Format_RGB32);
4218 image.fill(0xffffffff);
4226 pen.setColor(Qt::red);
4232 QCOMPARE(image.pixel(16, 16), 0xffff0000);
4235 class GradientProducer : public QThread
4241 void GradientProducer::run()
4243 QImage image(1, 1, QImage::Format_RGB32);
4246 for (int i = 0; i < 1000; ++i) {
4248 g.setColorAt(0, QColor(i % 256, 0, 0));
4249 g.setColorAt(1, Qt::white);
4251 p.fillRect(image.rect(), g);
4255 void tst_QPainter::QTBUG14614_gradientCacheRaceCondition()
4257 const int threadCount = 16;
4258 GradientProducer producers[threadCount];
4259 for (int i = 0; i < threadCount; ++i)
4260 producers[i].start();
4261 for (int i = 0; i < threadCount; ++i)
4262 producers[i].wait();
4265 void tst_QPainter::drawTextOpacity()
4267 QImage image(32, 32, QImage::Format_RGB32);
4268 image.fill(0xffffffff);
4271 p.setPen(QColor("#6F6F6F"));
4273 p.drawText(5, 30, QLatin1String("Qt"));
4276 QImage copy = image;
4277 image.fill(0xffffffff);
4280 p.setPen(QColor("#6F6F6F"));
4281 p.drawLine(-10, -10, -1, -1);
4283 p.drawText(5, 30, QLatin1String("Qt"));
4286 QCOMPARE(image, copy);
4289 void tst_QPainter::QTBUG17053_zeroDashPattern()
4291 QImage image(32, 32, QImage::Format_RGB32);
4292 image.fill(0xffffffff);
4294 QImage original = image;
4296 QVector<qreal> pattern;
4297 pattern << qreal(0) << qreal(0);
4300 QPen pen(Qt::black, 2.0);
4301 pen.setDashPattern(pattern);
4304 p.drawLine(0, 0, image.width(), image.height());
4306 QCOMPARE(image, original);
4309 class TextDrawerThread : public QThread
4316 void TextDrawerThread::run()
4318 rendering = QImage(100, 100, QImage::Format_ARGB32_Premultiplied);
4320 QPainter p(&rendering);
4321 p.fillRect(10, 10, 100, 100, Qt::blue);
4322 p.setPen(Qt::green);
4323 p.drawText(20, 20, "some text");
4327 void tst_QPainter::drawTextOutsideGuiThread()
4329 if (!QFontDatabase::supportsThreadedFontRendering())
4330 QSKIP("No threaded font rendering");
4332 QImage referenceRendering(100, 100, QImage::Format_ARGB32_Premultiplied);
4333 referenceRendering.fill(0);
4334 QPainter p(&referenceRendering);
4335 p.fillRect(10, 10, 100, 100, Qt::blue);
4336 p.setPen(Qt::green);
4337 p.drawText(20, 20, "some text");
4344 QCOMPARE(referenceRendering, t.rendering);
4347 void tst_QPainter::drawTextWithComplexBrush()
4349 QImage texture(10, 10, QImage::Format_ARGB32_Premultiplied);
4350 texture.fill(Qt::red);
4352 QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
4353 image.fill(Qt::white);
4359 QBrush brush(Qt::white);
4360 brush.setTextureImage(texture);
4361 p.setPen(QPen(brush, 2));
4363 p.drawText(10, 10, "Hello World");
4365 int paintedPixels = getPaintedPixels(image, Qt::white);
4366 QVERIFY(paintedPixels > 0);
4369 void tst_QPainter::QTBUG26013_squareCapStroke()
4371 QImage image(4, 4, QImage::Format_RGB32);
4374 p.setPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap));
4376 for (int i = 0; i < 3; ++i) {
4379 image.fill(0xffffffff);
4381 p.drawLine(QLineF(0, d, 0, d + 2));
4382 p.drawLine(QLineF(1, d, 3, d));
4384 // ensure that a horizontal line and a vertical line with square cap round up (downwards) at the same time
4385 QCOMPARE(image.pixel(0, 0), image.pixel(1, 0));
4387 image.fill(0xffffffff);
4389 p.drawLine(QLineF(d, 0, d + 2, 0));
4390 p.drawLine(QLineF(d, 1, d, 3));
4392 // ensure that a vertical line and a horizontal line with square cap round up (to the right) at the same time
4393 QCOMPARE(image.pixel(0, 0), image.pixel(0, 1));
4397 void tst_QPainter::QTBUG25153_drawLine()
4399 QImage image(2, 2, QImage::Format_RGB32);
4401 QVector<Qt::PenCapStyle> styles;
4402 styles << Qt::FlatCap << Qt::SquareCap << Qt::RoundCap;
4404 foreach (Qt::PenCapStyle style, styles) {
4405 image.fill(0xffffffff);
4407 p.setPen(QPen(Qt::black, 0, Qt::SolidLine, style));
4408 p.drawLine(QLineF(0, 0, 0, 0));
4411 QCOMPARE(image.pixel(0, 0), 0xff000000);
4412 QCOMPARE(image.pixel(0, 1), 0xffffffff);
4413 QCOMPARE(image.pixel(1, 0), 0xffffffff);
4417 QTEST_MAIN(tst_QPainter)
4419 #include "tst_qpainter.moc"