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.setRenderHint(QPainter::Qt4CompatiblePainting);
1494 painter.setWindow(0, 0, 3, 3);
1495 painter.drawLine(1, 1, 2, 2);
1497 const QRect painted = getPaintedSize(pixmap, Qt::white);
1498 QVERIFY(195 < painted.y() && painted.y() < 205); // correct value is around 200
1499 QVERIFY(195 < painted.height() && painted.height() < 205); // correct value is around 200
1502 void tst_QPainter::combinedMatrix()
1507 p.setWindow(0, 0, 1, 1);
1508 p.setViewport(32, 0, 32, 32);
1510 p.translate(0.5, 0.5);
1512 QMatrix cm = p.combinedMatrix();
1514 QPointF pt = QPointF(0, 0) * cm;
1516 QCOMPARE(pt.x(), 48.0);
1517 QCOMPARE(pt.y(), 16.0);
1520 void tst_QPainter::textOnTransparentImage()
1522 bool foundPixel = false;
1523 QImage image(10, 10, QImage::Format_ARGB32_Premultiplied);
1524 image.fill(qRgba(0, 0, 0, 0)); // transparent
1526 QPainter painter(&image);
1527 painter.setPen(QColor(255, 255, 255));
1528 painter.drawText(0, 10, "W");
1530 for (int x = 0; x < image.width(); ++x)
1531 for (int y = 0; y < image.height(); ++y)
1532 if (image.pixel(x, y) != 0)
1534 QVERIFY(foundPixel);
1537 void tst_QPainter::renderHints()
1539 QImage img(1, 1, QImage::Format_RGB32);
1544 p.setRenderHints(QPainter::RenderHints(0xffffffff), false);
1545 QCOMPARE(p.renderHints(), QPainter::RenderHints(0));
1548 p.setRenderHint(QPainter::Antialiasing);
1549 QVERIFY(p.renderHints() & QPainter::Antialiasing);
1551 p.setRenderHint(QPainter::Antialiasing, false);
1552 QVERIFY(!(p.renderHints() & QPainter::Antialiasing));
1555 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
1556 QVERIFY(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform));
1558 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
1559 QVERIFY(!(p.renderHints() & (QPainter::Antialiasing | QPainter::SmoothPixmapTransform)));
1562 int countPixels(const QImage &img, const QRgb &color)
1565 for (int y = 0; y < img.height(); ++y) {
1566 for (int x = 0; x < img.width(); ++x) {
1567 count += ((img.pixel(x, y) & 0xffffff) == color);
1573 template <typename T>
1574 void testClipping(QImage &img)
1577 a.addRect(QRect(2, 2, 4, 4));
1578 b.addRect(QRect(4, 4, 4, 4));
1585 p.setClipPath(b, Qt::IntersectClip);
1587 p.setClipping(false);
1588 p.setPen(Qt::NoPen);
1589 p.setBrush(QColor(0xff0000));
1590 p.drawRect(T(0, 0, 10, 10));
1592 p.setClipping(true);
1593 p.setBrush(QColor(0x00ff00));
1594 p.drawRect(T(0, 0, 10, 10));
1596 QCOMPARE(countPixels(img, 0xff0000), 96);
1597 QCOMPARE(countPixels(img, 0x00ff00), 4);
1600 void tst_QPainter::disableEnableClipping()
1602 QImage img(10, 10, QImage::Format_RGB32);
1604 testClipping<QRectF>(img);
1605 testClipping<QRect>(img);
1608 void tst_QPainter::setClipRect()
1610 QImage img(10, 10, QImage::Format_RGB32);
1611 // simple test to let valgrind check for buffer overflow
1614 p.setClipRect(-10, -10, 100, 100);
1615 p.fillRect(-10, -10, 100, 100, QBrush(QColor(Qt::red)));
1618 // rects with negative width/height
1621 p.setClipRect(QRect(10, 10, -10, 10));
1622 QVERIFY(p.clipRegion().isEmpty());
1623 p.setClipRect(QRect(10, 10, 10, -10));
1624 QVERIFY(p.clipRegion().isEmpty());
1625 p.setClipRect(QRectF(10.5, 10.5, -10.5, 10.5));
1626 QVERIFY(p.clipRegion().isEmpty());
1627 p.setClipRect(QRectF(10.5, 10.5, 10.5, -10.5));
1628 QVERIFY(p.clipRegion().isEmpty());
1633 This tests the two different clipping approaches in QRasterPaintEngine,
1634 one when using a QRegion and one when using a QPainterPath. They should
1637 void tst_QPainter::setEqualClipRegionAndPath_data()
1639 QTest::addColumn<QSize>("deviceSize");
1640 QTest::addColumn<QRegion>("region");
1642 QTest::newRow("empty") << QSize(100, 100) << QRegion();
1643 QTest::newRow("simple rect") << QSize(100, 100)
1644 << QRegion(QRect(5, 5, 10, 10));
1646 QVector<QRect> rects;
1649 rects << QRect(5, 5, 10, 10) << QRect(20, 20, 10, 10);
1650 region.setRects(rects.constData(), rects.size());
1651 QTest::newRow("two rects") << QSize(100, 100) << region;
1654 rects << QRect(5, 5, 10, 10) << QRect(20, 5, 10, 10);
1655 region.setRects(rects.constData(), rects.size());
1656 QTest::newRow("two x-adjacent rects") << QSize(100, 100) << region;
1659 rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1660 region.setRects(rects.constData(), rects.size());
1661 QTest::newRow("two x-adjacent rects 2") << QSize(100, 100) << region;
1664 rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1665 region.setRects(rects.constData(), rects.size());
1666 QTest::newRow("two x-adjacent rects 3") << QSize(50, 50) << region;
1669 rects << QRect(0, 0, 10, 100) << QRect(12, 0, 10, 100);
1670 region.setRects(rects.constData(), rects.size());
1671 QTest::newRow("two x-adjacent rects 4") << QSize(101, 101) << region;
1673 region = QRegion(QRect(0, 0, 200, 200), QRegion::Ellipse);
1675 QTest::newRow("ellipse") << QSize(190, 200) << region;
1677 region ^= QRect(50, 50, 50, 50);
1678 QTest::newRow("ellipse 2") << QSize(200, 200) << region;
1681 void tst_QPainter::setEqualClipRegionAndPath()
1683 QFETCH(QSize, deviceSize);
1684 QFETCH(QRegion, region);
1687 path.addRegion(region);
1689 QImage img1(deviceSize.width(), deviceSize.height(),
1690 QImage::Format_ARGB32);
1691 QImage img2(deviceSize.width(), deviceSize.height(),
1692 QImage::Format_ARGB32);
1693 img1.fill(0x12345678);
1694 img2.fill(0x12345678);
1698 p.setClipRegion(region);
1699 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1703 p.setClipPath(path);
1704 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1707 QCOMPARE(img1, img2);
1710 img1.fill(0x12345678);
1711 img2.fill(0x12345678);
1716 p.setClipRegion(region);
1717 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1722 p.setClipPath(path);
1723 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1726 QCOMPARE(img1, img2);
1728 img1.fill(0x12345678);
1729 img2.fill(0x12345678);
1731 // simple intersectclip
1732 img1.fill(0x12345678);
1733 img2.fill(0x12345678);
1736 p.setClipRegion(region);
1737 p.setClipRegion(region, Qt::IntersectClip);
1738 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1742 p.setClipPath(path);
1743 p.setClipPath(path, Qt::IntersectClip);
1744 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1746 QCOMPARE(img1, img2);
1748 img1.fill(0x12345678);
1749 img2.fill(0x12345678);
1752 p.setClipPath(path);
1753 p.setClipRegion(region, Qt::IntersectClip);
1754 p.fillRect(0, 0, img1.width(), img1.height(), QColor(Qt::red));
1758 p.setClipRegion(region);
1759 p.setClipPath(path, Qt::IntersectClip);
1760 p.fillRect(0, 0, img2.width(), img2.height(), QColor(Qt::red));
1762 QCOMPARE(img1, img2);
1766 void tst_QPainter::clippedFillPath_data()
1768 QTest::addColumn<QSize>("imageSize");
1769 QTest::addColumn<QPainterPath>("path");
1770 QTest::addColumn<QRect>("clipRect");
1771 QTest::addColumn<QBrush>("brush");
1772 QTest::addColumn<QPen>("pen");
1774 QLinearGradient gradient(QPoint(0, 0), QPoint(100, 100));
1775 gradient.setColorAt(0, Qt::red);
1776 gradient.setColorAt(1, Qt::blue);
1779 QPen pen2(QColor(223, 223, 0, 223));
1783 path.addRect(QRect(15, 15, 50, 50));
1784 QTest::newRow("simple rect 0") << QSize(100, 100) << path
1785 << QRect(15, 15, 49, 49)
1786 << QBrush(Qt::NoBrush)
1788 QTest::newRow("simple rect 1") << QSize(100, 100) << path
1789 << QRect(15, 15, 50, 50)
1790 << QBrush(Qt::NoBrush)
1792 QTest::newRow("simple rect 2") << QSize(100, 100) << path
1793 << QRect(15, 15, 51, 51)
1794 << QBrush(Qt::NoBrush)
1796 QTest::newRow("simple rect 3") << QSize(100, 100) << path
1797 << QRect(15, 15, 51, 51)
1798 << QBrush(QColor(Qt::blue))
1800 QTest::newRow("simple rect 4") << QSize(100, 100) << path
1801 << QRect(15, 15, 51, 51)
1805 path = QPainterPath();
1806 path.addEllipse(QRect(15, 15, 50, 50));
1807 QTest::newRow("ellipse 0") << QSize(100, 100) << path
1808 << QRect(15, 15, 49, 49)
1809 << QBrush(Qt::NoBrush)
1811 QTest::newRow("ellipse 1") << QSize(100, 100) << path
1812 << QRect(15, 15, 50, 50)
1813 << QBrush(Qt::NoBrush)
1815 QTest::newRow("ellipse 2") << QSize(100, 100) << path
1816 << QRect(15, 15, 51, 51)
1817 << QBrush(Qt::NoBrush)
1819 QTest::newRow("ellipse 3") << QSize(100, 100) << path
1820 << QRect(15, 15, 51, 51)
1821 << QBrush(QColor(Qt::blue))
1823 QTest::newRow("ellipse 4") << QSize(100, 100) << path
1824 << QRect(15, 15, 51, 51)
1828 path = QPainterPath();
1829 path.addRoundRect(QRect(15, 15, 50, 50), 20);
1830 QTest::newRow("round rect 0") << QSize(100, 100) << path
1831 << QRect(15, 15, 49, 49)
1832 << QBrush(Qt::NoBrush)
1834 QTest::newRow("round rect 1") << QSize(100, 100) << path
1835 << QRect(15, 15, 50, 50)
1836 << QBrush(Qt::NoBrush)
1838 QTest::newRow("round rect 2") << QSize(100, 100) << path
1839 << QRect(15, 15, 51, 51)
1840 << QBrush(Qt::NoBrush)
1842 QTest::newRow("round rect 3") << QSize(100, 100) << path
1843 << QRect(15, 15, 51, 51)
1844 << QBrush(QColor(Qt::blue))
1846 QTest::newRow("round rect 4") << QSize(100, 100) << path
1847 << QRect(15, 15, 51, 51)
1851 path = QPainterPath();
1852 path.moveTo(15, 50);
1853 path.cubicTo(40, 50, 40, 15, 65, 50);
1854 path.lineTo(15, 50);
1855 QTest::newRow("cubic 0") << QSize(100, 100) << path
1856 << QRect(15, 15, 49, 49)
1857 << QBrush(Qt::NoBrush)
1859 QTest::newRow("cubic 1") << QSize(100, 100) << path
1860 << QRect(15, 15, 50, 50)
1861 << QBrush(Qt::NoBrush)
1863 QTest::newRow("cubic 2") << QSize(100, 100) << path
1864 << QRect(15, 15, 51, 51)
1865 << QBrush(Qt::NoBrush)
1867 QTest::newRow("cubic 3") << QSize(100, 100) << path
1868 << QRect(15, 15, 51, 51)
1869 << QBrush(QColor(Qt::blue))
1871 QTest::newRow("cubic 4") << QSize(100, 100) << path
1872 << QRect(15, 15, 51, 51)
1877 void tst_QPainter::clippedFillPath()
1879 QFETCH(QSize, imageSize);
1880 QFETCH(QPainterPath, path);
1881 QFETCH(QRect, clipRect);
1882 QPainterPath clipPath;
1883 clipPath.addRect(clipRect);
1884 QFETCH(QBrush, brush);
1887 const int width = imageSize.width();
1888 const int height = imageSize.height();
1890 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
1891 clippedRect.fill(0x12345678);
1893 QPainter painter(&clippedRect);
1894 painter.setPen(pen);
1895 painter.setBrush(brush);
1896 painter.setClipRect(clipRect);
1897 painter.drawPath(path);
1900 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
1901 clippedPath.fill(0x12345678);
1903 QPainter painter(&clippedPath);
1904 painter.setPen(pen);
1905 painter.setBrush(brush);
1906 painter.setClipPath(clipPath);
1907 painter.drawPath(path);
1910 QCOMPARE(clippedRect, clippedPath);
1912 // repeat with antialiasing
1914 clippedRect.fill(0x12345678);
1916 QPainter painter(&clippedRect);
1917 painter.setRenderHint(QPainter::Antialiasing);
1918 painter.setPen(pen);
1919 painter.setBrush(brush);
1920 painter.setClipRect(clipRect);
1921 painter.drawPath(path);
1924 clippedPath.fill(0x12345678);
1926 QPainter painter(&clippedPath);
1927 painter.setRenderHint(QPainter::Antialiasing);
1928 painter.setPen(pen);
1929 painter.setBrush(brush);
1930 painter.setClipPath(clipPath);
1931 painter.drawPath(path);
1934 QCOMPARE(clippedRect, clippedPath);
1937 void tst_QPainter::clippedLines_data()
1939 QTest::addColumn<QSize>("imageSize");
1940 QTest::addColumn<QLineF>("line");
1941 QTest::addColumn<QRect>("clipRect");
1942 QTest::addColumn<QPen>("pen");
1944 QPen pen2(QColor(223, 223, 0, 223));
1947 QVector<QLineF> lines;
1948 lines << QLineF(15, 15, 65, 65)
1949 << QLineF(14, 14, 66, 66)
1950 << QLineF(16, 16, 64, 64)
1951 << QLineF(65, 65, 15, 15)
1952 << QLineF(66, 66, 14, 14)
1953 << QLineF(64, 64, 14, 14)
1954 << QLineF(15, 50, 15, 64)
1955 << QLineF(15, 50, 15, 65)
1956 << QLineF(15, 50, 15, 66)
1957 << QLineF(15, 50, 64, 50)
1958 << QLineF(15, 50, 65, 50)
1959 << QLineF(15, 50, 66, 50);
1961 foreach (QLineF line, lines) {
1962 QString desc = QString("line (%1, %2, %3, %4) %5").arg(line.x1())
1963 .arg(line.y1()).arg(line.x2()).arg(line.y2());
1964 QTest::newRow(qPrintable(desc.arg(0))) << QSize(100, 100) << line
1965 << QRect(15, 15, 49, 49)
1967 QTest::newRow(qPrintable(desc.arg(1))) << QSize(100, 100) << line
1968 << QRect(15, 15, 50, 50)
1970 QTest::newRow(qPrintable(desc.arg(2))) << QSize(100, 100) << line
1971 << QRect(15, 15, 51, 51)
1973 QTest::newRow(qPrintable(desc.arg(3))) << QSize(100, 100) << line
1974 << QRect(15, 15, 51, 51)
1976 QTest::newRow(qPrintable(desc.arg(4))) << QSize(100, 100) << line
1977 << QRect(15, 15, 51, 51)
1982 void tst_QPainter::clippedLines()
1984 QFETCH(QSize, imageSize);
1985 QFETCH(QLineF, line);
1986 QFETCH(QRect, clipRect);
1987 QPainterPath clipPath;
1988 clipPath.addRect(clipRect);
1991 const int width = imageSize.width();
1992 const int height = imageSize.height();
1994 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
1995 clippedRect.fill(0x12345678);
1997 QPainter painter(&clippedRect);
1998 painter.setPen(pen);
1999 painter.setClipRect(clipRect);
2000 painter.drawLine(line);
2001 painter.drawLine(line.toLine());
2004 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2005 clippedPath.fill(0x12345678);
2007 QPainter painter(&clippedPath);
2008 painter.setPen(pen);
2009 painter.setClipPath(clipPath);
2010 painter.drawLine(line);
2011 painter.drawLine(line.toLine());
2014 QCOMPARE(clippedRect, clippedPath);
2016 // repeat with antialiasing
2017 clippedRect.fill(0x12345678);
2019 QPainter painter(&clippedRect);
2020 painter.setRenderHint(QPainter::Antialiasing);
2021 painter.setPen(pen);
2022 painter.setClipRect(clipRect);
2023 painter.drawLine(line);
2024 painter.drawLine(line.toLine());
2027 clippedPath.fill(0x12345678);
2029 QPainter painter(&clippedPath);
2030 painter.setRenderHint(QPainter::Antialiasing);
2031 painter.setPen(pen);
2032 painter.setClipPath(clipPath);
2033 painter.drawLine(line);
2034 painter.drawLine(line.toLine());
2037 QCOMPARE(clippedRect, clippedPath);
2040 void tst_QPainter::clippedPolygon_data()
2042 clippedFillPath_data();
2045 void tst_QPainter::clippedPolygon()
2047 QFETCH(QSize, imageSize);
2048 QFETCH(QPainterPath, path);
2049 QPolygonF polygon = path.toFillPolygon();
2050 QFETCH(QRect, clipRect);
2051 QPainterPath clipPath;
2052 clipPath.addRect(clipRect);
2054 QFETCH(QBrush, brush);
2056 const int width = imageSize.width();
2057 const int height = imageSize.height();
2059 QImage clippedRect(width, height, QImage::Format_ARGB32_Premultiplied);
2060 clippedRect.fill(0x12345678);
2062 QPainter painter(&clippedRect);
2063 painter.setPen(pen);
2064 painter.setBrush(brush);
2065 painter.setClipRect(clipRect);
2066 painter.drawPolygon(polygon);
2067 painter.drawPolygon(polygon.toPolygon());
2070 QImage clippedPath(width, height, QImage::Format_ARGB32_Premultiplied);
2071 clippedPath.fill(0x12345678);
2073 QPainter painter(&clippedPath);
2074 painter.setPen(pen);
2075 painter.setBrush(brush);
2076 painter.setClipRect(clipRect);
2077 painter.drawPolygon(polygon);
2078 painter.drawPolygon(polygon.toPolygon());
2081 QCOMPARE(clippedRect, clippedPath);
2083 // repeat with antialiasing
2085 clippedRect.fill(0x12345678);
2087 QPainter painter(&clippedRect);
2088 painter.setRenderHint(QPainter::Antialiasing);
2089 painter.setPen(pen);
2090 painter.setBrush(brush);
2091 painter.setClipRect(clipRect);
2092 painter.drawPolygon(polygon);
2093 painter.drawPolygon(polygon.toPolygon());
2096 clippedPath.fill(0x12345678);
2098 QPainter painter(&clippedPath);
2099 painter.setRenderHint(QPainter::Antialiasing);
2100 painter.setPen(pen);
2101 painter.setBrush(brush);
2102 painter.setClipRect(clipRect);
2103 painter.drawPolygon(polygon);
2104 painter.drawPolygon(polygon.toPolygon());
2107 QCOMPARE(clippedRect, clippedPath);
2110 // this just draws some text that should be clipped in the raster
2112 void tst_QPainter::clippedText()
2114 for (char ch = 'A'; ch < 'Z'; ++ch) {
2118 QFontMetrics metrics(f);
2119 QRect textRect = metrics.boundingRect(QChar(ch));
2121 if (textRect.width() <= 8)
2123 if (textRect.height() <= 8)
2126 QRect imageRect = textRect.adjusted(4, 4, -4, -4);
2128 QImage image(imageRect.size(), QImage::Format_ARGB32_Premultiplied);
2130 image.fill(qRgba(255, 255, 255, 255));
2132 QPainter painter(&image);
2134 painter.setPen(Qt::black);
2136 painter.drawText(0, 0, QChar(ch));
2139 image.fill(qRgba(255, 255, 255, 255));
2141 QPainter painter(&image);
2143 painter.setPen(Qt::black);
2145 painter.drawText(-imageRect.topLeft(), QChar(ch));
2148 bool foundPixel = false;
2149 for (int x = 0; x < image.width(); ++x)
2150 for (int y = 0; y < image.height(); ++y)
2151 if (image.pixel(x, y) != 0)
2153 // can't QVERIFY(foundPixel) as sometimes all pixels are clipped
2154 // away. For example for 'O'
2155 // just call /some/ function to prevent the compiler from optimizing
2157 QString::number(foundPixel);
2159 //image.save(QString("debug") + ch + ".xpm");
2162 QVERIFY(true); // reached, don't trigger any valgrind errors
2165 void tst_QPainter::setOpacity_data()
2167 QTest::addColumn<QImage::Format>("destFormat");
2168 QTest::addColumn<QImage::Format>("srcFormat");
2170 QTest::newRow("ARGB32P on ARGB32P") << QImage::Format_ARGB32_Premultiplied
2171 << QImage::Format_ARGB32_Premultiplied;
2173 QTest::newRow("ARGB32 on ARGB32") << QImage::Format_ARGB32
2174 << QImage::Format_ARGB32;
2176 QTest::newRow("RGB32 on RGB32") << QImage::Format_RGB32
2177 << QImage::Format_RGB32;
2179 QTest::newRow("RGB16 on RGB16") << QImage::Format_RGB16
2180 << QImage::Format_RGB16;
2182 QTest::newRow("ARGB8565_Premultiplied on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied
2183 << QImage::Format_ARGB8565_Premultiplied;
2185 QTest::newRow("RGB555 on RGB555") << QImage::Format_RGB555
2186 << QImage::Format_RGB555;
2188 QTest::newRow("RGB666 on RGB666") << QImage::Format_RGB666
2189 << QImage::Format_RGB666;
2191 QTest::newRow("ARGB8555_Premultiplied on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied
2192 << QImage::Format_ARGB8555_Premultiplied;
2194 QTest::newRow("RGB888 on RGB888") << QImage::Format_RGB888
2195 << QImage::Format_RGB888;
2197 QTest::newRow("RGB32 on RGB16") << QImage::Format_RGB16
2198 << QImage::Format_RGB32;
2200 QTest::newRow("RGB32 on ARGB8565_Premultiplied") << QImage::Format_ARGB8565_Premultiplied
2201 << QImage::Format_RGB32;
2203 QTest::newRow("RGB32 on RGB666") << QImage::Format_RGB666
2204 << QImage::Format_RGB32;
2206 QTest::newRow("RGB32 on RGB555") << QImage::Format_RGB555
2207 << QImage::Format_RGB32;
2209 QTest::newRow("RGB32 on ARGB8555_Premultiplied") << QImage::Format_ARGB8555_Premultiplied
2210 << QImage::Format_RGB32;
2212 QTest::newRow("RGB32 on RGB888") << QImage::Format_RGB888
2213 << QImage::Format_RGB32;
2215 QTest::newRow("RGB16 on RGB32") << QImage::Format_RGB32
2216 << QImage::Format_RGB16;
2218 QTest::newRow("ARGB8565_Premultiplied on RGB32") << QImage::Format_RGB32
2219 << QImage::Format_ARGB8565_Premultiplied;
2221 QTest::newRow("RGB666 on RGB32") << QImage::Format_RGB32
2222 << QImage::Format_RGB666;
2224 QTest::newRow("RGB555 on RGB32") << QImage::Format_RGB32
2225 << QImage::Format_RGB555;
2227 QTest::newRow("ARGB8555_Premultiplied on RGB32") << QImage::Format_RGB32
2228 << QImage::Format_ARGB8555_Premultiplied;
2230 QTest::newRow("RGB888 on RGB32") << QImage::Format_RGB32
2231 << QImage::Format_RGB888;
2233 QTest::newRow("RGB555 on RGB888") << QImage::Format_RGB888
2234 << QImage::Format_RGB555;
2236 QTest::newRow("RGB666 on RGB888") << QImage::Format_RGB888
2237 << QImage::Format_RGB666;
2239 QTest::newRow("RGB444 on RGB444") << QImage::Format_RGB444
2240 << QImage::Format_RGB444;
2243 void tst_QPainter::setOpacity()
2245 QFETCH(QImage::Format, destFormat);
2246 QFETCH(QImage::Format, srcFormat);
2248 const QSize imageSize(12, 12);
2249 const QRect imageRect(QPoint(0, 0), imageSize);
2250 QColor destColor = Qt::black;
2251 QColor srcColor = Qt::white;
2253 QImage dest(imageSize, destFormat);
2254 QImage src(imageSize, srcFormat);
2258 p.fillRect(imageRect, destColor);
2262 p.fillRect(imageRect, srcColor);
2267 p.drawImage(imageRect, src, imageRect);
2270 QImage actual = dest.convertToFormat(QImage::Format_RGB32);
2272 for (int y = 0; y < actual.height(); ++y) {
2273 QRgb *p = (QRgb *)actual.scanLine(y);
2274 for (int x = 0; x < actual.width(); ++x) {
2275 QVERIFY(qAbs(qRed(p[x]) - 127) <= 0xf);
2276 QVERIFY(qAbs(qGreen(p[x]) - 127) <= 0xf);
2277 QVERIFY(qAbs(qBlue(p[x]) - 127) <= 0xf);
2282 void tst_QPainter::drawhelper_blend_untransformed_data()
2287 void tst_QPainter::drawhelper_blend_untransformed()
2289 QFETCH(QImage::Format, destFormat);
2290 QFETCH(QImage::Format, srcFormat);
2292 const int size = 128;
2293 const QSize imageSize(size, size);
2294 const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing
2296 QColor destColor(127, 127, 127);
2297 QColor srcColor(Qt::white);
2299 QImage dest(imageSize, destFormat);
2300 QImage src(imageSize, srcFormat);
2304 p.fillRect(paintRect, srcColor);
2307 QList<qreal> opacities = (QList<qreal>() << 0.0 << 0.1 << 0.01 << 0.4
2308 << 0.5 << 0.6 << 0.9 << 1.0);
2309 foreach (qreal opacity, opacities) {
2311 p.fillRect(paintRect, destColor);
2313 p.setOpacity(opacity);
2314 p.drawImage(paintRect, src, paintRect);
2317 // sanity check: make sure all pixels are equal
2318 QImage expected(size - 2, size, destFormat);
2320 p.fillRect(0, 0, expected.width(), expected.height(),
2321 QColor(dest.pixel(1, 0)));
2324 const QImage subDest(dest.bits() + dest.depth() / 8,
2325 dest.width() - 2, dest.height(),
2326 dest.bytesPerLine(), dest.format());
2328 if (dest.format() == QImage::Format_ARGB8565_Premultiplied ||
2329 dest.format() == QImage::Format_ARGB8555_Premultiplied) {
2330 // Test skipped due to rounding errors...
2333 QCOMPARE(subDest, expected);
2337 void tst_QPainter::drawhelper_blend_tiled_untransformed_data()
2342 void tst_QPainter::drawhelper_blend_tiled_untransformed()
2344 QFETCH(QImage::Format, destFormat);
2345 QFETCH(QImage::Format, srcFormat);
2347 const int size = 128;
2348 const QSize imageSize(size, size);
2349 const QRect paintRect(1, 0, size - 2, size); // needs alignment and tailing
2351 QColor destColor(127, 127, 127);
2352 QColor srcColor(Qt::white);
2354 QImage dest(imageSize, destFormat);
2355 QImage src(imageSize / 2, srcFormat);
2359 p.fillRect(QRect(QPoint(0, 0), imageSize/ 2), srcColor);
2362 const QBrush brush(src);
2364 QList<qreal> opacities = (QList<qreal>() << 0.0 << 0.1 << 0.01 << 0.4
2365 << 0.5 << 0.6 << 0.9 << 1.0);
2366 foreach (qreal opacity, opacities) {
2368 p.fillRect(paintRect, destColor);
2370 p.setOpacity(opacity);
2371 p.fillRect(paintRect, brush);
2374 // sanity check: make sure all pixels are equal
2375 QImage expected(size - 2, size, destFormat);
2377 p.fillRect(0, 0, expected.width(), expected.height(),
2378 QColor(dest.pixel(1, 0)));
2381 const QImage subDest(dest.bits() + dest.depth() / 8,
2382 dest.width() - 2, dest.height(),
2383 dest.bytesPerLine(), dest.format());
2385 if (dest.format() == QImage::Format_ARGB8565_Premultiplied ||
2386 dest.format() == QImage::Format_ARGB8555_Premultiplied) {
2387 // Skipping test due to rounding errors. Test needs rewrite
2390 QCOMPARE(subDest, expected);
2394 static QPaintEngine::PaintEngineFeatures no_porter_duff()
2396 QPaintEngine::PaintEngineFeatures features = QPaintEngine::AllFeatures;
2397 return features & ~QPaintEngine::PorterDuff;
2400 class DummyPaintEngine : public QPaintEngine, public QPaintDevice
2403 DummyPaintEngine() : QPaintEngine(no_porter_duff()) {}
2404 virtual bool begin(QPaintDevice *) { return true; }
2405 virtual bool end() { return true; }
2407 virtual void updateState(const QPaintEngineState &) {}
2408 virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
2410 virtual Type type() const { return User; }
2412 virtual QPaintEngine *paintEngine() const { return (QPaintEngine *)this; }
2414 virtual int metric(PaintDeviceMetric metric) const { Q_UNUSED(metric); return 0; };
2417 static bool success;
2419 void porterDuff_warningChecker(QtMsgType type, const QMessageLogContext &, const QString &msg)
2421 if (type == QtWarningMsg && msg == QLatin1String("QPainter::setCompositionMode: PorterDuff modes not supported on device"))
2425 void tst_QPainter::porterDuff_warning()
2427 QtMessageHandler old = qInstallMessageHandler(porterDuff_warningChecker);
2428 DummyPaintEngine dummy;
2432 p.setCompositionMode(QPainter::CompositionMode_Source);
2436 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
2440 p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
2443 QVERIFY(qInstallMessageHandler(old) == porterDuff_warningChecker);
2449 inline quint24(quint32 v)
2452 data[1] = qGreen(v);
2456 inline operator quint32 ()
2458 return qRgb(data[2], data[1], data[0]);
2461 inline bool operator==(const quint24 &v) const {
2462 return (data[0] == v.data[0] && data[1] == v.data[1] && data[2] == v.data[2]);
2468 void tst_QPainter::drawhelper_blend_color()
2470 QImage dest(32, 32, QImage::Format_ARGB8555_Premultiplied);
2471 dest.fill(0xff000000);
2475 p.fillRect(0, 0, dest.width(), dest.height(), QColor(255, 0, 0, 127));
2478 QImage expected(32, 32, QImage::Format_ARGB8555_Premultiplied);
2479 expected.fill(0xff3c007f);
2481 QCOMPARE(dest.pixel(1, 1), expected.pixel(1, 1));
2482 QCOMPARE(dest, expected);
2485 #ifndef QT_NO_WIDGETS
2486 class ViewportTestWidget : public QWidget
2489 ViewportTestWidget(QWidget *parent = 0) : QWidget(parent), hasPainted(false) {}
2490 QSize sizeHint() const {
2491 return QSize(100, 100);
2498 void paintEvent(QPaintEvent *) {
2501 viewport = p.viewport();
2505 void tst_QPainter::childWidgetViewport()
2508 parent.setAutoFillBackground(true);
2509 parent.resize(200, 200);
2510 ViewportTestWidget child(&parent);
2511 child.setAutoFillBackground(true);
2514 qApp->processEvents();
2516 if (child.hasPainted) {
2517 QCOMPARE(child.viewport, QRect(QPoint(0, 0), child.sizeHint()));
2519 qWarning("Failed to ensure that paintEvent has been run. Could not run test.");
2524 void tst_QPainter::fillRect_objectBoundingModeGradient()
2526 QImage a(10, 10, QImage::Format_ARGB32_Premultiplied);
2530 QLinearGradient g(QPoint(0, 0), QPoint(0, 1));
2531 g.setColorAt(0, Qt::red);
2532 g.setColorAt(1, Qt::blue);
2533 g.setCoordinateMode(QGradient::ObjectBoundingMode);
2536 p.fillRect(QRect(0, 0, a.width(), a.height()), g);
2540 path.addRect(0, 0, a.width(), a.height());
2543 p.fillPath(path, g);
2549 void tst_QPainter::fillRect_stretchToDeviceMode()
2551 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2553 QLinearGradient g(QPoint(0, 0), QPoint(0, 1));
2554 g.setCoordinateMode(QGradient::StretchToDeviceMode);
2557 p.fillRect(img.rect(), g);
2560 for (int i = 1; i < img.height(); ++i)
2561 QVERIFY(img.pixel(0, i) != img.pixel(0, i-1));
2564 void tst_QPainter::monoImages()
2566 Qt::GlobalColor colorPairs[][2] = {
2567 { Qt::white, Qt::black },
2568 { Qt::color0, Qt::color1 },
2569 { Qt::red, Qt::blue }
2572 const int numColorPairs = sizeof(colorPairs) / sizeof(QRgb[2]);
2574 QImage transparent(2, 2, QImage::Format_ARGB32_Premultiplied);
2575 transparent.fill(0x0);
2577 for (int i = 1; i < QImage::NImageFormats; ++i) {
2578 for (int j = 0; j < numColorPairs; ++j) {
2579 const QImage::Format format = QImage::Format(i);
2580 if (format == QImage::Format_Indexed8)
2583 QImage img(2, 2, format);
2585 if (img.colorCount() > 0) {
2586 img.setColor(0, QColor(colorPairs[j][0]).rgba());
2587 img.setColor(1, QColor(colorPairs[j][1]).rgba());
2592 p.fillRect(0, 0, 2, 2, colorPairs[j][0]);
2593 p.fillRect(0, 0, 1, 1, colorPairs[j][1]);
2594 p.fillRect(1, 1, 1, 1, colorPairs[j][1]);
2597 QImage original = img;
2600 p.drawImage(0, 0, transparent);
2603 // drawing a transparent image on top of another image
2604 // should not change the image
2605 QCOMPARE(original, img);
2607 if (img.colorCount() == 0)
2610 for (int k = 0; k < 2; ++k) {
2612 p.fillRect(0, 0, 2, 2, colorPairs[j][k]);
2615 QImage argb32p(2, 2, QImage::Format_ARGB32_Premultiplied);
2617 p.fillRect(0, 0, 2, 2, colorPairs[j][k]);
2620 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2622 // drawing argb32p image on mono image
2624 p.drawImage(0, 0, argb32p);
2627 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2629 // drawing mono image on argb32p image
2631 p.drawImage(0, 0, img);
2634 QCOMPARE(argb32p, img.convertToFormat(argb32p.format()));
2640 #if !defined(Q_OS_IRIX) && !defined(Q_OS_AIX) && !defined(Q_CC_MSVC) && !defined(Q_OS_SOLARIS) && !defined(__UCLIBC__)
2643 static const QString fpeExceptionString(int exception)
2646 if (exception & FE_INEXACT)
2647 return QLatin1String("Inexact result");
2649 if (exception & FE_UNDERFLOW)
2650 return QLatin1String("Underflow");
2651 if (exception & FE_OVERFLOW)
2652 return QLatin1String("Overflow");
2653 if (exception & FE_DIVBYZERO)
2654 return QLatin1String("Divide by zero");
2655 if (exception & FE_INVALID)
2656 return QLatin1String("Invalid operation");
2657 return QLatin1String("No exception");
2660 class FpExceptionChecker
2663 FpExceptionChecker(int exceptionMask)
2664 : m_exceptionMask(exceptionMask)
2666 feclearexcept(m_exceptionMask);
2669 ~FpExceptionChecker()
2671 const int exceptions = fetestexcept(m_exceptionMask);
2672 QVERIFY2(!exceptions, qPrintable(QLatin1String("Floating point exception: ") + fpeExceptionString(exceptions)));
2676 int m_exceptionMask;
2679 void fpe_rasterizeLine_task232012()
2681 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2682 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2686 p.setBrush(Qt::black);
2687 p.drawRect(QRectF(0, 0, 5, 0));
2688 p.drawRect(QRectF(0, 0, 0, 5));
2691 void fpe_pixmapTransform()
2693 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2695 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2699 const qreal scaleFactor = 0.001;
2700 const int translateDistance = 1000000;
2703 p.setBrush(QBrush(Qt::red,Qt::Dense6Pattern));
2705 for (int i = 0; i < 2; ++i) {
2706 p.setRenderHint(QPainter::SmoothPixmapTransform, i);
2710 p.translate(translateDistance, 0);
2711 p.drawRect(-translateDistance, 0, 100, 100);
2714 p.scale(scaleFactor, scaleFactor);
2715 p.drawRect(QRectF(0, 0, 1 / scaleFactor, 1 / scaleFactor));
2719 void fpe_zeroLengthLines()
2721 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2723 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2727 p.setPen(QPen(Qt::black, 3));
2728 p.drawLine(64, 64, 64, 64);
2731 void fpe_divByZero()
2733 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2735 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
2739 p.setRenderHint(QPainter::Antialiasing);
2741 p.drawRect(QRectF(10, 10, 100, 0));
2742 p.drawRect(QRectF(10, 10, 0, 100));
2744 p.drawRect(QRect(10, 10, 100, 0));
2745 p.drawRect(QRect(10, 10, 0, 100));
2747 p.fillRect(QRectF(10, 10, 100, 0), Qt::black);
2748 p.fillRect(QRectF(10, 10, 0, 100), Qt::black);
2750 p.fillRect(QRect(10, 10, 100, 0), Qt::black);
2751 p.fillRect(QRect(10, 10, 0, 100), Qt::black);
2754 void fpe_steepSlopes()
2756 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2758 QImage img(1024, 1024, QImage::Format_ARGB32_Premultiplied);
2760 QFETCH(QTransform, transform);
2761 QFETCH(QLineF, line);
2762 QFETCH(bool, antialiased);
2766 p.setPen(QPen(Qt::black, 1));
2767 p.setRenderHint(QPainter::Antialiasing, antialiased);
2768 p.setTransform(transform);
2773 void fpe_radialGradients()
2775 FpExceptionChecker checker(FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
2777 QImage img(21, 21, QImage::Format_ARGB32_Premultiplied);
2780 double m = img.width() * 0.5;
2783 p.setRenderHints(QPainter::Antialiasing);
2784 p.setPen(Qt::NoPen);
2785 p.setBrush(QRadialGradient(m, m, m));
2786 p.drawEllipse(img.rect());
2789 #define FPE_TEST(x) \
2790 void tst_QPainter::x() \
2795 #define FPE_TEST(x) \
2796 void tst_QPainter::x() \
2798 QSKIP("Floating point exception checking (fenv.h) not available"); \
2802 FPE_TEST(fpe_rasterizeLine_task232012)
2803 FPE_TEST(fpe_pixmapTransform)
2804 FPE_TEST(fpe_zeroLengthLines)
2805 FPE_TEST(fpe_divByZero)
2806 FPE_TEST(fpe_steepSlopes)
2807 FPE_TEST(fpe_radialGradients)
2809 void tst_QPainter::fpe_steepSlopes_data()
2811 QTest::addColumn<QTransform>("transform");
2812 QTest::addColumn<QLineF>("line");
2813 QTest::addColumn<bool>("antialiased");
2816 const qreal dsin = 0.000014946676875461832484392500630665523431162000633776187896728515625;
2817 const qreal dcos = 0.9999999998882984630910186751862056553363800048828125;
2819 const QTransform transform = QTransform(QMatrix(dcos, dsin, -dsin, dcos, 64, 64));
2820 const QLineF line(2, 2, 2, 6);
2822 QTest::newRow("task 207147 aa") << transform << line << true;
2823 QTest::newRow("task 207147 no aa") << transform << line << false;
2827 QTransform transform;
2828 transform.rotate(0.0000001);
2829 const QLineF line(5, 5, 10, 5);
2831 QTest::newRow("task 166702 aa") << transform << line << true;
2832 QTest::newRow("task 166702 no aa") << transform << line << false;
2836 const QTransform transform;
2837 const QLineF line(2.5, 2.5, 2.5 + 1/256., 60000.5);
2839 QTest::newRow("steep line aa") << transform << line << true;
2840 QTest::newRow("steep line no aa") << transform << line << false;
2844 const QTransform transform;
2845 const QLineF line(2.5, 2.5, 2.5 + 1/256., 1024);
2847 QTest::newRow("steep line 2 aa") << transform << line << true;
2848 QTest::newRow("steep line 2 no aa") << transform << line << false;
2852 const QTransform transform;
2853 const QLineF line(2.5, 2.5, 2.5 + 1/64., 1024);
2855 QTest::newRow("steep line 3 aa") << transform << line << true;
2856 QTest::newRow("steep line 3 no aa") << transform << line << false;
2862 return rand() / (RAND_MAX + 1.0);
2865 QPointF randInRect(const QRectF &rect)
2867 const qreal x = rect.left() + rect.width() * randf();
2868 const qreal y = rect.top() + rect.height() * randf();
2870 return QPointF(x, y);
2873 void tst_QPainter::rasterizer_asserts()
2875 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2877 QRectF middle(QPointF(0, 0), img.size());
2878 QRectF left = middle.translated(-middle.width(), 0);
2879 QRectF right = middle.translated(middle.width(), 0);
2882 img.fill(Qt::white);
2883 p.setCompositionMode(QPainter::CompositionMode_Destination);
2884 for (int i = 0; i < 100000; ++i) {
2886 path.moveTo(randInRect(middle));
2887 path.lineTo(randInRect(left));
2888 path.lineTo(randInRect(right));
2890 p.fillPath(path, Qt::black);
2894 void tst_QPainter::rasterizer_negativeCoords()
2896 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
2899 QImage original = img;
2903 p.fillRect(0, 0, 70, 50, Qt::black);
2905 // image should not have changed
2906 QCOMPARE(img.pixel(0, 0), 0x0U);
2907 QCOMPARE(img, original);
2910 void tst_QPainter::blendOverFlow_data()
2912 QTest::addColumn<QImage::Format>("format");
2913 QTest::addColumn<int>("width");
2914 QTest::addColumn<int>("height");
2916 QImage::Format format = QImage::Format_ARGB8555_Premultiplied;
2917 QTest::newRow("555,1,1") << format << 1 << 1;
2918 QTest::newRow("555,2,2") << format << 2 << 2;
2919 QTest::newRow("555,10,10") << format << 10 << 10;
2921 format = QImage::Format_ARGB8565_Premultiplied;
2922 QTest::newRow("565,1,1") << format << 1 << 1;
2923 QTest::newRow("565,2,2") << format << 2 << 2;
2924 QTest::newRow("565,10,10") << format << 10 << 10;
2927 void tst_QPainter::blendOverFlow()
2929 QFETCH(QImage::Format, format);
2931 QFETCH(int, height);
2933 QImage dest(width, height, format);
2934 QImage src(width, height, format);
2938 p.fillRect(0, 0, width, height, Qt::green);
2940 QImage expected = dest;
2944 p.setCompositionMode(QPainter::CompositionMode_Source);
2945 p.fillRect(0, 0, width, height, QColor(0, 255, 0, 6));
2950 p.drawImage(0, 0, src);
2953 QCOMPARE(dest.pixel(0, 0), expected.pixel(0, 0));
2954 QCOMPARE(dest, expected);
2957 void tst_QPainter::largeImagePainting_data()
2959 QTest::addColumn<int>("width");
2960 QTest::addColumn<int>("height");
2961 QTest::addColumn<bool>("antialiased");
2963 QTest::newRow("tall") << 1 << 32767 << false;
2964 QTest::newRow("tall aa") << 1 << 32767 << true;
2965 QTest::newRow("wide") << 32767 << 1 << false;
2966 QTest::newRow("wide aa") << 32767 << 1 << true;
2969 void tst_QPainter::largeImagePainting()
2972 path.addRect(0, 0, 1, 1);
2973 path.addRect(2, 0, 1, 1);
2974 path.addRect(0, 2, 1, 1);
2977 QFETCH(int, height);
2978 QFETCH(bool, antialiased);
2980 QImage img(width, height, QImage::Format_ARGB32_Premultiplied);
2984 p.setPen(Qt::NoPen);
2985 p.setBrush(Qt::white);
2987 p.setRenderHint(QPainter::Antialiasing, antialiased);
2989 for (int i = 0; i < img.width(); i += 4) {
2996 for (int i = 4; i < img.height(); i += 4) {
3001 for (int i = 0; i < img.width(); ++i) {
3003 QCOMPARE(img.pixel(i, 0), 0x0U);
3005 QCOMPARE(img.pixel(i, 0), 0xffffffffU);
3008 for (int i = 1; i < img.height(); ++i) {
3010 QCOMPARE(img.pixel(0, i), 0x0U);
3012 QCOMPARE(img.pixel(0, i), 0xffffffffU);
3016 void tst_QPainter::imageScaling_task206785()
3018 QImage src(32, 2, QImage::Format_ARGB32_Premultiplied);
3019 src.fill(0xffffffff);
3021 QImage dst(128, 128, QImage::Format_ARGB32_Premultiplied);
3023 QImage expected(128, 128, QImage::Format_ARGB32_Premultiplied);
3024 expected.fill(0xffffffff);
3026 for (int i = 1; i < 5; ++i) {
3027 qreal scale = i / qreal(5);
3029 dst.fill(0xff000000);
3032 p.scale(dst.width() / qreal(src.width()), scale);
3034 for (int y = 0; y * scale < dst.height(); ++y)
3035 p.drawImage(0, y, src);
3039 QCOMPARE(dst, expected);
3043 #define FOR_EACH_NEIGHBOR_8 for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if (dx != 0 || dy != 0)
3044 #define FOR_EACH_NEIGHBOR_4 for (int dx = -1; dx <= 1; ++dx) for (int dy = -1; dy <= 1; ++dy) if ((dx == 0) != (dy == 0))
3046 uint qHash(const QPoint &point)
3048 return qHash(qMakePair(point.x(), point.y()));
3051 bool verifyOutlineFillConsistency(const QImage &img, QRgb outside, QRgb inside, QRgb outline)
3053 if (img.pixel(img.width() / 2, img.height() / 2) != inside)
3056 int x = img.width() / 2;
3057 int y = img.height() / 2;
3059 while (img.pixel(++x, y) == inside)
3062 if (img.pixel(x, y) != outline)
3065 QQueue<QPoint> discovered;
3066 discovered.enqueue(QPoint(x, y));
3068 QVector<bool> visited(img.width() * img.height());
3069 visited.fill(false);
3071 while (!discovered.isEmpty()) {
3072 QPoint p = discovered.dequeue();
3073 QRgb pixel = img.pixel(p.x(), p.y());
3075 bool &v = visited[p.y() * img.width() + p.x()];
3080 if (pixel == outline) {
3081 FOR_EACH_NEIGHBOR_8 {
3082 QPoint x(p.x() + dx, p.y() + dy);
3083 discovered.enqueue(x);
3086 FOR_EACH_NEIGHBOR_4 {
3087 if ((dx == 0) == (dy == 0))
3089 QRgb neighbor = img.pixel(p.x() + dx, p.y() + dy);
3090 if ((pixel == inside && neighbor == outside) ||
3091 (pixel == outside && neighbor == inside))
3100 #undef FOR_EACH_NEIGHBOR_8
3101 #undef FOR_EACH_NEIGHBOR_4
3103 void tst_QPainter::outlineFillConsistency()
3105 QImage dst(256, 256, QImage::Format_ARGB32_Premultiplied);
3108 poly << QPointF(5, -100) << QPointF(-70, 20) << QPointF(95, 25);
3111 QBrush brush(Qt::black);
3113 QRgb background = 0xffffffff;
3114 for (int i = 0; i < 360; ++i) {
3115 dst.fill(background);
3118 p.translate(dst.width() / 2, dst.height() / 2);
3120 QPolygonF copy = poly;
3121 for (int j = 0; j < copy.size(); ++j)
3122 copy[j] = QTransform().rotate(i).map(copy[j]);
3126 p.drawPolygon(copy);
3129 QVERIFY(verifyOutlineFillConsistency(dst, background, brush.color().rgba(), pen.color().rgba()));
3133 void tst_QPainter::drawImage_task217400_data()
3135 QTest::addColumn<QImage::Format>("format");
3137 QTest::newRow("444") << QImage::Format_ARGB4444_Premultiplied;
3138 QTest::newRow("555") << QImage::Format_ARGB8555_Premultiplied;
3139 QTest::newRow("565") << QImage::Format_ARGB8565_Premultiplied;
3140 // QTest::newRow("666") << QImage::Format_ARGB6666_Premultiplied;
3141 QTest::newRow("888p") << QImage::Format_ARGB32_Premultiplied;
3142 QTest::newRow("888") << QImage::Format_ARGB32;
3145 void tst_QPainter::drawImage_task217400()
3147 QFETCH(QImage::Format, format);
3149 const QImage src = QImage(QFINDTESTDATA("task217400.png"))
3150 .convertToFormat(format);
3151 QVERIFY(!src.isNull());
3153 QImage expected(src.size(), format);
3155 QPainter p(&expected);
3156 p.fillRect(0, 0, expected.width(), expected.height(), Qt::white);
3157 p.drawImage(0, 0, src);
3160 for (int i = 1; i <= 4; ++i) {
3161 QImage dest(src.width() + i, src.height(), format);
3164 p.fillRect(0, 0, dest.width(), dest.height(), Qt::white);
3165 p.drawImage(i, 0, src);
3168 const QImage result = dest.copy(i, 0, src.width(), src.height());
3170 QCOMPARE(result, expected);
3174 void tst_QPainter::drawImage_task258776()
3176 QImage src(16, 16, QImage::Format_RGB888);
3177 QImage dest(33, 33, QImage::Format_RGB888);
3179 dest.fill(0xff0000);
3181 QPainter painter(&dest);
3182 painter.drawImage(QRectF(0.499, 0.499, 32, 32), src, QRectF(0, 0, 16, 16));
3185 QImage expected(33, 33, QImage::Format_RGB32);
3186 expected.fill(0xff0000);
3188 painter.begin(&expected);
3189 painter.drawImage(QRectF(0, 0, 32, 32), src);
3192 dest = dest.convertToFormat(QImage::Format_RGB32);
3194 dest.save("dest.png");
3195 expected.save("expected.png");
3196 QCOMPARE(dest, expected);
3199 void tst_QPainter::clipRectSaveRestore()
3201 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3205 p.setClipRect(QRect(0, 0, 10, 10));
3207 p.setClipRect(QRect(5, 5, 5, 5), Qt::IntersectClip);
3209 p.fillRect(0, 0, 64, 64, Qt::black);
3212 QCOMPARE(img.pixel(0, 0), QColor(Qt::black).rgba());
3215 void tst_QPainter::clippedImage()
3217 QImage img(16, 16, QImage::Format_ARGB32_Premultiplied);
3220 QImage src(16, 16, QImage::Format_RGB32);
3221 src.fill(QColor(Qt::red).rgba());
3224 p.setClipRect(QRect(1, 1, 14, 14));
3225 p.drawImage(0, 0, src);
3228 QCOMPARE(img.pixel(0, 0), 0x0U);
3229 QCOMPARE(img.pixel(1, 1), src.pixel(1, 1));
3232 void tst_QPainter::stateResetBetweenQPainters()
3234 QImage img(16, 16, QImage::Format_ARGB32);
3238 p.setCompositionMode(QPainter::CompositionMode_Source);
3239 p.fillRect(0, 0, 16, 16, Qt::red);
3244 p2.fillRect(0, 0, 16, 16, QColor(0, 0, 255, 63));
3247 img.save("foo.png");
3249 QVERIFY(img.pixel(0, 0) != qRgba(0, 0, 255, 63));
3250 QVERIFY(qRed(img.pixel(0, 0)) > 0); // We didn't erase the red channel...
3251 QVERIFY(qBlue(img.pixel(0, 0)) < 255); // We blended the blue channel
3254 void tst_QPainter::drawRect_task215378()
3256 QImage img(11, 11, QImage::Format_ARGB32_Premultiplied);
3257 img.fill(QColor(Qt::white).rgba());
3260 p.setPen(QColor(127, 127, 127, 127));
3261 p.drawRect(0, 0, 10, 10);
3264 QCOMPARE(img.pixel(0, 0), img.pixel(1, 0));
3265 QCOMPARE(img.pixel(0, 0), img.pixel(0, 1));
3266 QVERIFY(img.pixel(0, 0) != img.pixel(1, 1));
3269 void tst_QPainter::drawRect_task247505()
3271 QImage a(10, 10, QImage::Format_ARGB32_Premultiplied);
3276 p.setPen(Qt::NoPen);
3277 p.setBrush(Qt::black);
3278 p.drawRect(QRectF(10, 0, -10, 10));
3281 p.setPen(Qt::NoPen);
3282 p.setBrush(Qt::black);
3283 p.drawRect(QRectF(0, 0, 10, 10));
3289 void tst_QPainter::drawImage_data()
3291 QTest::addColumn<int>("x");
3292 QTest::addColumn<int>("y");
3293 QTest::addColumn<int>("w");
3294 QTest::addColumn<int>("h");
3295 QTest::addColumn<QImage::Format>("srcFormat");
3296 QTest::addColumn<QImage::Format>("dstFormat");
3298 for (int srcFormat = QImage::Format_Mono; srcFormat < QImage::NImageFormats; ++srcFormat) {
3299 for (int dstFormat = QImage::Format_Mono; dstFormat < QImage::NImageFormats; ++dstFormat) {
3300 if (dstFormat == QImage::Format_Indexed8)
3302 for (int odd_x = 0; odd_x <= 1; ++odd_x) {
3303 for (int odd_width = 0; odd_width <= 1; ++odd_width) {
3304 QString description =
3305 QString("srcFormat %1, dstFormat %2, odd x: %3, odd width: %4")
3306 .arg(srcFormat).arg(dstFormat).arg(odd_x).arg(odd_width);
3308 QTest::newRow(qPrintable(description)) << (10 + odd_x) << 10 << (20 + odd_width) << 20
3309 << QImage::Format(srcFormat)
3310 << QImage::Format(dstFormat);
3317 bool verifyImage(const QImage &img, int x, int y, int w, int h, uint background)
3319 int imgWidth = img.width();
3320 int imgHeight = img.height();
3321 for (int i = 0; i < imgHeight; ++i) {
3322 for (int j = 0; j < imgWidth; ++j) {
3323 uint pixel = img.pixel(j, i);
3324 bool outside = j < x || j >= (x + w) || i < y || i >= (y + h);
3325 if (outside != (pixel == background)) {
3326 //printf("%d %d, expected %x, got %x, outside: %d\n", x, y, background, pixel, outside);
3335 void tst_QPainter::drawImage()
3341 QFETCH(QImage::Format, srcFormat);
3342 QFETCH(QImage::Format, dstFormat);
3344 QImage dst(40, 40, QImage::Format_RGB32);
3345 dst.fill(0xffffffff);
3347 dst = dst.convertToFormat(dstFormat);
3348 uint background = dst.pixel(0, 0);
3350 QImage src(w, h, QImage::Format_RGB32);
3351 src.fill(0xff000000);
3352 src = src.convertToFormat(srcFormat);
3355 p.drawImage(x, y, src);
3358 QVERIFY(verifyImage(dst, x, y, w, h, background));
3361 void tst_QPainter::imageCoordinateLimit()
3363 QImage img(64, 40000, QImage::Format_MonoLSB);
3365 p.drawText(10, 36000, QLatin1String("foo"));
3366 p.setPen(QPen(Qt::black, 2));
3367 p.drawLine(10, 0, 60, 40000);
3369 p.setRenderHint(QPainter::Antialiasing);
3370 p.drawLine(10, 0, 60, 40000);
3374 void tst_QPainter::imageBlending_data()
3376 QTest::addColumn<QImage::Format>("sourceFormat");
3377 QTest::addColumn<QImage::Format>("destFormat");
3378 QTest::addColumn<int>("error");
3380 int error_rgb565 = ((1<<3) + (1<<2) + (1<<3));
3381 QTest::newRow("rgb565_on_rgb565") << QImage::Format_RGB16
3382 << QImage::Format_RGB16
3384 QTest::newRow("argb8565_on_rgb565") << QImage::Format_ARGB8565_Premultiplied
3385 << QImage::Format_RGB16
3388 QTest::newRow("rgb32_on_rgb565") << QImage::Format_RGB32
3389 << QImage::Format_RGB16
3392 QTest::newRow("argb32pm_on_rgb565") << QImage::Format_ARGB32_Premultiplied
3393 << QImage::Format_RGB16
3397 int diffColor(quint32 ap, quint32 bp)
3399 int a = qAlpha(ap) - qAlpha(bp);
3400 int r = qRed(ap) - qRed(bp);
3401 int b = qBlue(ap) - qBlue(bp);
3402 int g = qBlue(ap) - qBlue(bp);
3404 return qAbs(a) + qAbs(r) + qAbs(g) + qAbs(b);
3407 // this test assumes premultiplied pixels...
3409 void tst_QPainter::imageBlending()
3411 QFETCH(QImage::Format, sourceFormat);
3412 QFETCH(QImage::Format, destFormat);
3417 QImage orig_dest(6, 6, QImage::Format_ARGB32_Premultiplied);
3419 QPainter p(&orig_dest);
3420 p.fillRect(0, 0, 6, 3, QColor::fromRgbF(1, 0, 0));
3421 p.fillRect(3, 0, 3, 6, QColor::fromRgbF(0, 0, 1, 0.5));
3423 dest = orig_dest.convertToFormat(destFormat);
3425 // An image like this: (r = red, m = magenta, b = light alpha blue, 0 = transparent)
3436 QImage orig_source(6, 6, QImage::Format_ARGB32_Premultiplied);
3437 orig_source.fill(0);
3438 QPainter p(&orig_source);
3439 p.fillRect(1, 1, 4, 4, QColor::fromRgbF(0, 1, 0, 0.5));
3440 p.fillRect(2, 2, 2, 2, QColor::fromRgbF(0, 1, 0));
3442 source = orig_source.convertToFormat(sourceFormat);
3444 // An image like this: (0 = transparent, . = green at 0.5 alpha, g = opaque green.
3454 p.drawImage(0, 0, source);
3465 // the g pixels, always green..
3466 QVERIFY(diffColor(dest.pixel(2, 2), 0xff00ff00) <= error); // g
3468 if (source.hasAlphaChannel()) {
3469 QVERIFY(diffColor(dest.pixel(0, 0), 0xffff0000) <= error); // r
3470 QVERIFY(diffColor(dest.pixel(5, 0), 0xff7f007f) <= error); // m
3471 QVERIFY(diffColor(dest.pixel(1, 1), 0xff7f7f00) <= error); // r.
3472 QVERIFY(diffColor(dest.pixel(4, 1), 0xff3f7f3f) <= error); // m.
3473 if (dest.hasAlphaChannel()) {
3474 QVERIFY(diffColor(dest.pixel(1, 3), 0x7f007f00) <= error); // .
3475 QVERIFY(diffColor(dest.pixel(4, 3), 0x7f007f3f) <= error); // b.
3476 QVERIFY(diffColor(dest.pixel(4, 3), 0x7f007f3f) <= error); // b.
3477 QVERIFY(diffColor(dest.pixel(4, 4), 0x7f00007f) <= error); // b
3478 QVERIFY(diffColor(dest.pixel(4, 0), 0) <= 0); // 0
3481 QVERIFY(diffColor(dest.pixel(0, 0), 0xff000000) <= 0);
3482 QVERIFY(diffColor(dest.pixel(1, 1), 0xff007f00) <= error);
3486 void tst_QPainter::imageBlending_clipped()
3488 QImage src(20, 20, QImage::Format_RGB16);
3490 p.fillRect(src.rect(), Qt::red);
3493 QImage dst(40, 20, QImage::Format_RGB16);
3495 p.fillRect(dst.rect(), Qt::white);
3498 QImage expected = dst;
3501 p.setClipRect(QRect(23, 0, 20, 20));
3503 // should be completely clipped
3504 p.drawImage(QRectF(3, 0, 20, 20), src);
3507 // dst should be left unchanged
3508 QCOMPARE(dst, expected);
3511 void tst_QPainter::paintOnNullPixmap()
3513 QPixmap pix(16, 16);
3516 QPainter p(&textPixmap);
3517 p.drawPixmap(10, 10, pix);
3520 QPixmap textPixmap2(16,16);
3521 p.begin(&textPixmap2);
3525 void tst_QPainter::checkCompositionMode()
3527 QImage refImage(50,50,QImage::Format_ARGB32);
3528 QPainter painter(&refImage);
3529 painter.fillRect(QRect(0,0,50,50),Qt::blue);
3531 QImage testImage(50,50,QImage::Format_ARGB32);
3532 QPainter p(&testImage);
3533 p.fillRect(QRect(0,0,50,50),Qt::red);
3535 p.setCompositionMode(QPainter::CompositionMode_SourceOut);
3537 p.fillRect(QRect(0,0,50,50),Qt::blue);
3539 QCOMPARE(refImage.pixel(20,20),testImage.pixel(20,20));
3542 static QLinearGradient inverseGradient(QLinearGradient g)
3544 QLinearGradient g2 = g;
3546 QGradientStops stops = g.stops();
3548 QGradientStops inverse;
3549 foreach (QGradientStop stop, stops)
3550 inverse << QGradientStop(1 - stop.first, stop.second);
3552 g2.setStops(inverse);
3556 void tst_QPainter::linearGradientSymmetry_data()
3558 QTest::addColumn<QGradientStops>("stops");
3560 if (sizeof(qreal) != sizeof(float)) {
3561 QGradientStops stops;
3562 stops << qMakePair(qreal(0.0), QColor(Qt::blue));
3563 stops << qMakePair(qreal(0.2), QColor(220, 220, 220, 0));
3564 stops << qMakePair(qreal(0.6), QColor(Qt::red));
3565 stops << qMakePair(qreal(0.9), QColor(220, 220, 220, 255));
3566 stops << qMakePair(qreal(1.0), QColor(Qt::black));
3567 QTest::newRow("multiple stops") << stops;
3571 QGradientStops stops;
3572 stops << qMakePair(qreal(0.0), QColor(Qt::blue));
3573 stops << qMakePair(qreal(1.0), QColor(Qt::black));
3574 QTest::newRow("two stops") << stops;
3577 if (sizeof(qreal) != sizeof(float)) {
3578 QGradientStops stops;
3579 stops << qMakePair(qreal(0.3), QColor(Qt::blue));
3580 stops << qMakePair(qreal(0.6), QColor(Qt::black));
3581 QTest::newRow("two stops 2") << stops;
3585 void tst_QPainter::linearGradientSymmetry()
3587 QFETCH(QGradientStops, stops);
3589 QImage a(64, 8, QImage::Format_ARGB32_Premultiplied);
3590 QImage b(64, 8, QImage::Format_ARGB32_Premultiplied);
3595 QLinearGradient gradient(QRectF(b.rect()).topLeft(), QRectF(b.rect()).topRight());
3596 gradient.setStops(stops);
3599 pa.fillRect(a.rect(), gradient);
3603 pb.fillRect(b.rect(), inverseGradient(gradient));
3606 b = b.mirrored(true);
3610 void tst_QPainter::gradientInterpolation()
3612 QImage image(256, 8, QImage::Format_ARGB32_Premultiplied);
3615 QLinearGradient gradient(QRectF(image.rect()).topLeft(), QRectF(image.rect()).topRight());
3616 gradient.setColorAt(0.0, QColor(255, 0, 0, 0));
3617 gradient.setColorAt(1.0, Qt::blue);
3620 painter.begin(&image);
3621 painter.fillRect(image.rect(), gradient);
3624 const QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(3));
3626 for (int i = 0; i < 256; ++i) {
3627 QCOMPARE(qAlpha(line[i]), qBlue(line[i])); // bright blue
3628 QVERIFY(qAbs(qAlpha(line[i]) - i) < 3); // linear alpha
3629 QCOMPARE(qRed(line[i]), 0); // no red component
3630 QCOMPARE(qGreen(line[i]), 0); // no green component
3633 gradient.setInterpolationMode(QGradient::ComponentInterpolation);
3636 painter.begin(&image);
3637 painter.fillRect(image.rect(), gradient);
3640 for (int i = 1; i < 256; ++i) {
3642 QVERIFY(qRed(line[i]) >= qBlue(line[i])); // red is dominant
3644 QVERIFY(qRed(line[i]) <= qBlue(line[i])); // blue is dominant
3646 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
3647 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
3648 QVERIFY(qAbs(qAlpha(line[i]) - i) < 3); // linear alpha
3649 QCOMPARE(qGreen(line[i]), 0); // no green component
3653 void tst_QPainter::drawPolygon()
3655 QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
3657 QPainterPathStroker stroker;
3658 stroker.setWidth(1.5);
3664 QPolygonF poly = stroker.createStroke(path).toFillPolygon();
3666 img.fill(0xffffffff);
3668 p.setRenderHint(QPainter::Antialiasing);
3669 p.setBrush(Qt::red);
3670 p.setPen(Qt::NoPen);
3671 p.drawPolygon(poly);
3672 p.translate(64, 64);
3673 p.drawPolygon(poly);
3676 QImage a = img.copy();
3678 img.fill(0xffffffff);
3680 p.setRenderHint(QPainter::Antialiasing);
3681 p.setBrush(Qt::red);
3682 p.setPen(Qt::NoPen);
3683 p.translate(64, 64);
3684 p.drawPolygon(poly);
3686 p.drawPolygon(poly);
3692 void tst_QPainter::inactivePainter()
3694 // This test succeeds if it doesn't segfault.
3698 QRegion region(QRect(20, 20, 60, 40));
3699 QPolygonF polygon(QVector<QPointF>() << QPointF(0, 0) << QPointF(12, 0) << QPointF(8, 6));
3700 path.addPolygon(polygon);
3706 p.setBackground(QBrush(Qt::blue));
3709 p.setBrush(Qt::red);
3710 p.setBrush(Qt::NoBrush);
3711 p.setBrush(QBrush(Qt::white, Qt::DiagCrossPattern));
3714 p.setBackgroundMode(Qt::OpaqueMode);
3716 p.boundingRect(QRectF(0, 0, 100, 20), Qt::AlignCenter, QLatin1String("Hello, World!"));
3717 p.boundingRect(QRect(0, 0, 100, 20), Qt::AlignCenter, QLatin1String("Hello, World!"));
3720 p.setBrushOrigin(QPointF(12, 34));
3721 p.setBrushOrigin(QPoint(12, 34));
3726 p.setClipPath(path);
3727 p.setClipRect(QRectF(42, 42, 42, 42));
3728 p.setClipRect(QRect(42, 42, 42, 42));
3729 p.setClipRegion(region);
3730 p.setClipping(true);
3733 p.combinedTransform();
3735 p.compositionMode();
3736 p.setCompositionMode(QPainter::CompositionMode_Plus);
3740 p.deviceTransform();
3743 p.setFont(QFont(QLatin1String("Times"), 24));
3748 p.layoutDirection();
3749 p.setLayoutDirection(Qt::RightToLeft);
3755 p.setPen(QPen(Qt::red));
3756 p.setPen(Qt::green);
3757 p.setPen(Qt::NoPen);
3760 p.setRenderHint(QPainter::Antialiasing, true);
3761 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
3770 p.viewTransformEnabled();
3771 p.setViewTransformEnabled(true);
3774 p.setViewport(QRect(10, 10, 620, 460));
3777 p.setWindow(QRect(10, 10, 620, 460));
3780 p.setWorldMatrix(QMatrix().translate(43, 21), true);
3781 p.setWorldMatrixEnabled(true);
3784 p.setTransform(QTransform().translate(12, 34), true);
3787 p.setWorldTransform(QTransform().scale(0.5, 0.5), true);
3790 bool testCompositionMode(int src, int dst, int expected, QPainter::CompositionMode op, qreal opacity = 1.0)
3792 // The test image needs to be large enough to test SIMD code
3793 const QSize imageSize(100, 100);
3795 QImage actual(imageSize, QImage::Format_ARGB32_Premultiplied);
3796 actual.fill(QColor(dst, dst, dst).rgb());
3798 QPainter p(&actual);
3799 p.setCompositionMode(op);
3800 p.setOpacity(opacity);
3801 p.fillRect(QRect(QPoint(), imageSize), QColor(src, src, src));
3804 if (qRed(actual.pixel(0, 0)) != expected) {
3805 qDebug("Fail: mode %d, src[%d] dst [%d] actual [%d] expected [%d]", op,
3806 src, dst, qRed(actual.pixel(0, 0)), expected);
3809 QImage refImage(imageSize, QImage::Format_ARGB32_Premultiplied);
3810 refImage.fill(QColor(expected, expected, expected).rgb());
3811 return actual == refImage;
3815 void tst_QPainter::extendedBlendModes()
3817 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Plus));
3818 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Plus));
3819 QVERIFY(testCompositionMode(127, 128, 255, QPainter::CompositionMode_Plus));
3820 QVERIFY(testCompositionMode(127, 0, 127, QPainter::CompositionMode_Plus));
3821 QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Plus));
3822 QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Plus));
3823 QVERIFY(testCompositionMode( 0, 255, 255, QPainter::CompositionMode_Plus));
3824 QVERIFY(testCompositionMode(128, 128, 255, QPainter::CompositionMode_Plus));
3826 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Plus, 0.3));
3827 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Plus, 0.3));
3828 QVERIFY(testCompositionMode(127, 128, 165, QPainter::CompositionMode_Plus, 0.3));
3829 QVERIFY(testCompositionMode(127, 0, 37, QPainter::CompositionMode_Plus, 0.3));
3830 QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Plus, 0.3));
3831 QVERIFY(testCompositionMode(255, 0, 75, QPainter::CompositionMode_Plus, 0.3));
3832 QVERIFY(testCompositionMode( 0, 255, 255, QPainter::CompositionMode_Plus, 0.3));
3833 QVERIFY(testCompositionMode(128, 128, 166, QPainter::CompositionMode_Plus, 0.3));
3834 QVERIFY(testCompositionMode(186, 200, 255, QPainter::CompositionMode_Plus, 0.3));
3836 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Multiply));
3837 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Multiply));
3838 QVERIFY(testCompositionMode(127, 255, 127, QPainter::CompositionMode_Multiply));
3839 QVERIFY(testCompositionMode(255, 127, 127, QPainter::CompositionMode_Multiply));
3840 QVERIFY(testCompositionMode( 63, 255, 63, QPainter::CompositionMode_Multiply));
3841 QVERIFY(testCompositionMode(255, 63, 63, QPainter::CompositionMode_Multiply));
3842 QVERIFY(testCompositionMode(127, 127, 63, QPainter::CompositionMode_Multiply));
3844 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Screen));
3845 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Screen));
3846 QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Screen));
3847 QVERIFY(testCompositionMode(255, 63, 255, QPainter::CompositionMode_Screen));
3848 QVERIFY(testCompositionMode( 63, 0, 63, QPainter::CompositionMode_Screen));
3849 QVERIFY(testCompositionMode( 0, 63, 63, QPainter::CompositionMode_Screen));
3850 QVERIFY(testCompositionMode(127, 127, 191, QPainter::CompositionMode_Screen));
3852 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Overlay));
3853 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Overlay));
3854 QVERIFY(testCompositionMode( 63, 63, 31, QPainter::CompositionMode_Overlay));
3855 QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Overlay));
3857 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Darken));
3858 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Darken));
3859 QVERIFY(testCompositionMode( 63, 63, 63, QPainter::CompositionMode_Darken));
3860 QVERIFY(testCompositionMode( 63, 255, 63, QPainter::CompositionMode_Darken));
3861 QVERIFY(testCompositionMode(255, 63, 63, QPainter::CompositionMode_Darken));
3862 QVERIFY(testCompositionMode( 63, 127, 63, QPainter::CompositionMode_Darken));
3863 QVERIFY(testCompositionMode(127, 63, 63, QPainter::CompositionMode_Darken));
3865 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_Lighten));
3866 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Lighten));
3867 QVERIFY(testCompositionMode( 63, 63, 63, QPainter::CompositionMode_Lighten));
3868 QVERIFY(testCompositionMode( 63, 255, 255, QPainter::CompositionMode_Lighten));
3869 QVERIFY(testCompositionMode(255, 63, 255, QPainter::CompositionMode_Lighten));
3870 QVERIFY(testCompositionMode( 63, 127, 127, QPainter::CompositionMode_Lighten));
3871 QVERIFY(testCompositionMode(127, 63, 127, QPainter::CompositionMode_Lighten));
3873 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_ColorDodge));
3874 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_ColorDodge));
3875 QVERIFY(testCompositionMode( 63, 127, 169, QPainter::CompositionMode_ColorDodge));
3876 QVERIFY(testCompositionMode(191, 127, 255, QPainter::CompositionMode_ColorDodge));
3877 QVERIFY(testCompositionMode(127, 191, 255, QPainter::CompositionMode_ColorDodge));
3879 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_ColorBurn));
3880 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_ColorBurn));
3881 QVERIFY(testCompositionMode(127, 127, 0, QPainter::CompositionMode_ColorBurn));
3882 QVERIFY(testCompositionMode(128, 128, 2, QPainter::CompositionMode_ColorBurn));
3883 QVERIFY(testCompositionMode(191, 127, 84, QPainter::CompositionMode_ColorBurn));
3885 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_HardLight));
3886 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_HardLight));
3887 QVERIFY(testCompositionMode(127, 127, 127, QPainter::CompositionMode_HardLight));
3888 QVERIFY(testCompositionMode( 63, 63, 31, QPainter::CompositionMode_HardLight));
3889 QVERIFY(testCompositionMode(127, 63, 63, QPainter::CompositionMode_HardLight));
3891 QVERIFY(testCompositionMode(255, 255, 255, QPainter::CompositionMode_SoftLight));
3892 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_SoftLight));
3893 QVERIFY(testCompositionMode(127, 127, 126, QPainter::CompositionMode_SoftLight));
3894 QVERIFY(testCompositionMode( 63, 63, 39, QPainter::CompositionMode_SoftLight));
3895 QVERIFY(testCompositionMode(127, 63, 62, QPainter::CompositionMode_SoftLight));
3897 QVERIFY(testCompositionMode(255, 255, 0, QPainter::CompositionMode_Difference));
3898 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Difference));
3899 QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Difference));
3900 QVERIFY(testCompositionMode(127, 127, 0, QPainter::CompositionMode_Difference));
3901 QVERIFY(testCompositionMode(127, 128, 1, QPainter::CompositionMode_Difference));
3902 QVERIFY(testCompositionMode(127, 63, 64, QPainter::CompositionMode_Difference));
3903 QVERIFY(testCompositionMode( 0, 127, 127, QPainter::CompositionMode_Difference));
3905 QVERIFY(testCompositionMode(255, 255, 0, QPainter::CompositionMode_Exclusion));
3906 QVERIFY(testCompositionMode( 0, 0, 0, QPainter::CompositionMode_Exclusion));
3907 QVERIFY(testCompositionMode(255, 0, 255, QPainter::CompositionMode_Exclusion));
3908 QVERIFY(testCompositionMode(127, 127, 127, QPainter::CompositionMode_Exclusion));
3909 QVERIFY(testCompositionMode( 63, 127, 127, QPainter::CompositionMode_Exclusion));
3910 QVERIFY(testCompositionMode( 63, 63, 95, QPainter::CompositionMode_Exclusion));
3911 QVERIFY(testCompositionMode(191, 191, 96, QPainter::CompositionMode_Exclusion));
3914 void tst_QPainter::zeroOpacity()
3916 QImage source(1, 1, QImage::Format_ARGB32_Premultiplied);
3917 source.fill(0xffffffff);
3919 QImage target(1, 1, QImage::Format_RGB32);
3920 target.fill(0xff000000);
3922 QPainter p(&target);
3924 p.drawImage(0, 0, source);
3927 QCOMPARE(target.pixel(0, 0), 0xff000000);
3930 void tst_QPainter::clippingBug()
3932 QImage img(32, 32, QImage::Format_ARGB32_Premultiplied);
3935 QImage expected = img;
3936 QPainter p(&expected);
3937 p.fillRect(1, 1, 30, 30, Qt::red);
3941 path.addRect(1, 1, 30, 30);
3942 path.addRect(1, 1, 30, 30);
3943 path.addRect(1, 1, 30, 30);
3946 p.setClipPath(path);
3947 p.fillRect(0, 0, 32, 32, Qt::red);
3950 QCOMPARE(img, expected);
3953 void tst_QPainter::emptyClip()
3955 QImage img(64, 64, QImage::Format_ARGB32_Premultiplied);
3957 p.setRenderHints(QPainter::Antialiasing);
3958 p.setClipRect(0, 32, 64, 0);
3959 p.fillRect(0, 0, 64, 64, Qt::white);
3963 path.lineTo(64, 64);
3964 path.lineTo(40, 64);
3965 path.lineTo(40, 80);
3968 p.fillPath(path, Qt::green);
3971 void tst_QPainter::drawImage_1x1()
3973 QImage source(1, 1, QImage::Format_ARGB32_Premultiplied);
3974 source.fill(0xffffffff);
3976 QImage img(32, 32, QImage::Format_ARGB32_Premultiplied);
3977 img.fill(0xff000000);
3979 p.drawImage(QRectF(0.9, 0.9, 32, 32), source);
3982 QImage expected = img;
3983 expected.fill(0xff000000);
3985 p.fillRect(1, 1, 31, 31, Qt::white);
3988 QCOMPARE(img, expected);
3991 void tst_QPainter::taskQT4444_dontOverflowDashOffset()
3997 pen.setStyle(Qt::DashDotLine);
4000 point[0] = QPointF(182.50868749707968,347.78457234212630);
4001 point[1] = QPointF(182.50868749707968,107.22501998401277);
4002 point[2] = QPointF(182.50868749707968,107.22501998401277);
4003 point[3] = QPointF(520.46600762283651,107.22501998401277);
4005 QImage crashImage(QSize(1000, 120), QImage::Format_ARGB32_Premultiplied);
4006 p.begin(&crashImage);
4008 p.drawLines(point, 2);
4011 QVERIFY(true); // Don't crash
4014 void tst_QPainter::painterBegin()
4017 QImage indexed8Image(16, 16, QImage::Format_Indexed8);
4018 QImage rgb32Image(16, 16, QImage::Format_RGB32);
4019 QImage argb32Image(16, 16, QImage::Format_ARGB32_Premultiplied);
4023 // Painting on null image should fail.
4024 QVERIFY(!p.begin(&nullImage));
4026 // Check that the painter is not messed up by using it on another image.
4027 QVERIFY(p.begin(&rgb32Image));
4030 // If painting on indexed8 image fails, the painter state should still be OK.
4031 if (p.begin(&indexed8Image))
4033 QVERIFY(p.begin(&rgb32Image));
4036 // Try opening a painter on the two different images.
4037 QVERIFY(p.begin(&rgb32Image));
4038 QVERIFY(!p.begin(&argb32Image));
4041 // Try opening two painters on the same image.
4042 QVERIFY(p.begin(&rgb32Image));
4044 QVERIFY(!q.begin(&rgb32Image));
4048 // Try ending an inactive painter.
4052 void tst_QPainter::setPenColor(QPainter& p)
4054 p.setPen(Qt::NoPen);
4056 // Setting color, then style
4057 // Should work even though the pen is "NoPen with color", temporarily.
4058 QPen newPen(p.pen());
4059 newPen.setColor(Qt::red);
4060 QCOMPARE(p.pen().style(), newPen.style());
4061 QCOMPARE(p.pen().style(), Qt::NoPen);
4064 QCOMPARE(p.pen().color().name(), QString("#ff0000"));
4066 QPen newPen2(p.pen());
4067 newPen2.setStyle(Qt::SolidLine);
4070 QCOMPARE(p.pen().color().name(), QString("#ff0000"));
4073 void tst_QPainter::setPenColorOnImage()
4075 QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
4080 void tst_QPainter::setPenColorOnPixmap()
4082 QPixmap pix(10, 10);
4087 #ifndef QT_NO_WIDGETS
4088 class TestProxy : public QGraphicsProxyWidget
4091 TestProxy() : QGraphicsProxyWidget() {}
4092 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
4094 QGraphicsProxyWidget::paint(painter, option, widget);
4095 deviceTransform = painter->deviceTransform();
4097 QTransform deviceTransform;
4100 class TestWidget : public QWidget
4104 TestWidget() : QWidget(), painted(false) {}
4105 void paintEvent(QPaintEvent *)
4108 deviceTransform = p.deviceTransform();
4109 worldTransform = p.worldTransform();
4112 QTransform deviceTransform;
4113 QTransform worldTransform;
4117 void tst_QPainter::QTBUG5939_attachPainterPrivate()
4119 QWidget *w = new QWidget();
4120 QGraphicsScene *scene = new QGraphicsScene();
4121 QGraphicsView *view = new QGraphicsView(scene, w);
4123 TestProxy *proxy = new TestProxy();
4124 TestWidget *widget = new TestWidget();
4125 proxy->setWidget(widget);
4126 scene->addItem(proxy);
4128 w->resize(scene->sceneRect().size().toSize());
4131 QTRY_VERIFY(widget->painted);
4133 QVERIFY(widget->worldTransform.isIdentity());
4134 QCOMPARE(widget->deviceTransform, proxy->deviceTransform);
4138 void tst_QPainter::clipBoundingRect()
4140 QPixmap pix(500, 500);
4144 // Test a basic rectangle
4145 p.setClipRect(100, 100, 200, 100);
4146 QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4147 QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4148 p.setClipRect(120, 120, 20, 20, Qt::IntersectClip);
4149 QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4150 QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4152 // Test a basic float rectangle
4153 p.setClipRect(QRectF(100, 100, 200, 100));
4154 QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4155 QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4156 p.setClipRect(QRectF(120, 120, 20, 20), Qt::IntersectClip);
4157 QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4158 QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4160 // Test a basic path + region
4162 path.addRect(100, 100, 200, 100);
4163 p.setClipPath(path);
4164 QVERIFY(p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4165 QVERIFY(!p.clipBoundingRect().contains(QRectF(50, 50, 300, 200)));
4166 p.setClipRegion(QRegion(120, 120, 20, 20), Qt::IntersectClip);
4167 QVERIFY(p.clipBoundingRect().contains(QRect(120, 120, 20, 20)));
4168 QVERIFY(!p.clipBoundingRect().contains(QRectF(100, 100, 200, 100)));
4170 p.setClipRect(0, 0, 500, 500);
4171 p.translate(250, 250);
4172 for (int i=0; i<360; ++i) {
4174 p.setClipRect(-100, -100, 200, 200, Qt::IntersectClip);
4176 QVERIFY(p.clipBoundingRect().contains(QRectF(-100, -100, 200, 200)));
4177 QVERIFY(!p.clipBoundingRect().contains(QRectF(-250, -250, 500, 500)));
4181 void tst_QPainter::drawText_subPixelPositionsInRaster_qtbug5053()
4183 #if !defined(Q_OS_MAC)
4184 QSKIP("Only Mac supports sub pixel positions in raster engine currently");
4186 QFontMetricsF fm(qApp->font());
4188 QImage baseLine(fm.width(QChar::fromLatin1('e')), fm.height(), QImage::Format_RGB32);
4189 baseLine.fill(Qt::white);
4191 QPainter p(&baseLine);
4192 p.setRenderHint(QPainter::Qt4CompatiblePainting);
4193 p.drawText(0, fm.ascent(), QString::fromLatin1("e"));
4196 bool foundDifferentRasterization = false;
4197 for (int i=1; i<12; ++i) {
4198 QImage comparison(baseLine.size(), QImage::Format_RGB32);
4199 comparison.fill(Qt::white);
4202 QPainter p(&comparison);
4203 p.setRenderHint(QPainter::Qt4CompatiblePainting);
4204 p.drawText(QPointF(i / 12.0, fm.ascent()), QString::fromLatin1("e"));
4207 if (comparison != baseLine) {
4208 foundDifferentRasterization = true;
4213 QVERIFY(foundDifferentRasterization);
4216 void tst_QPainter::drawPointScaled()
4218 QImage image(32, 32, QImage::Format_RGB32);
4219 image.fill(0xffffffff);
4227 pen.setColor(Qt::red);
4233 QCOMPARE(image.pixel(16, 16), 0xffff0000);
4236 class GradientProducer : public QThread
4242 void GradientProducer::run()
4244 QImage image(1, 1, QImage::Format_RGB32);
4247 for (int i = 0; i < 1000; ++i) {
4249 g.setColorAt(0, QColor(i % 256, 0, 0));
4250 g.setColorAt(1, Qt::white);
4252 p.fillRect(image.rect(), g);
4256 void tst_QPainter::QTBUG14614_gradientCacheRaceCondition()
4258 const int threadCount = 16;
4259 GradientProducer producers[threadCount];
4260 for (int i = 0; i < threadCount; ++i)
4261 producers[i].start();
4262 for (int i = 0; i < threadCount; ++i)
4263 producers[i].wait();
4266 void tst_QPainter::drawTextOpacity()
4268 QImage image(32, 32, QImage::Format_RGB32);
4269 image.fill(0xffffffff);
4272 p.setPen(QColor("#6F6F6F"));
4274 p.drawText(5, 30, QLatin1String("Qt"));
4277 QImage copy = image;
4278 image.fill(0xffffffff);
4281 p.setPen(QColor("#6F6F6F"));
4282 p.drawLine(-10, -10, -1, -1);
4284 p.drawText(5, 30, QLatin1String("Qt"));
4287 QCOMPARE(image, copy);
4290 void tst_QPainter::QTBUG17053_zeroDashPattern()
4292 QImage image(32, 32, QImage::Format_RGB32);
4293 image.fill(0xffffffff);
4295 QImage original = image;
4297 QVector<qreal> pattern;
4298 pattern << qreal(0) << qreal(0);
4301 QPen pen(Qt::black, 2.0);
4302 pen.setDashPattern(pattern);
4305 p.drawLine(0, 0, image.width(), image.height());
4307 QCOMPARE(image, original);
4310 class TextDrawerThread : public QThread
4317 void TextDrawerThread::run()
4319 rendering = QImage(100, 100, QImage::Format_ARGB32_Premultiplied);
4321 QPainter p(&rendering);
4322 p.fillRect(10, 10, 100, 100, Qt::blue);
4323 p.setPen(Qt::green);
4324 p.drawText(20, 20, "some text");
4328 void tst_QPainter::drawTextOutsideGuiThread()
4330 if (!QFontDatabase::supportsThreadedFontRendering())
4331 QSKIP("No threaded font rendering");
4333 QImage referenceRendering(100, 100, QImage::Format_ARGB32_Premultiplied);
4334 referenceRendering.fill(0);
4335 QPainter p(&referenceRendering);
4336 p.fillRect(10, 10, 100, 100, Qt::blue);
4337 p.setPen(Qt::green);
4338 p.drawText(20, 20, "some text");
4345 QCOMPARE(referenceRendering, t.rendering);
4348 void tst_QPainter::drawTextWithComplexBrush()
4350 QImage texture(10, 10, QImage::Format_ARGB32_Premultiplied);
4351 texture.fill(Qt::red);
4353 QImage image(100, 100, QImage::Format_ARGB32_Premultiplied);
4354 image.fill(Qt::white);
4360 QBrush brush(Qt::white);
4361 brush.setTextureImage(texture);
4362 p.setPen(QPen(brush, 2));
4364 p.drawText(10, 10, "Hello World");
4366 int paintedPixels = getPaintedPixels(image, Qt::white);
4367 QVERIFY(paintedPixels > 0);
4370 void tst_QPainter::QTBUG26013_squareCapStroke()
4372 QImage image(4, 4, QImage::Format_RGB32);
4375 p.setPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::SquareCap));
4377 for (int i = 0; i < 3; ++i) {
4380 image.fill(0xffffffff);
4382 p.drawLine(QLineF(0, d, 0, d + 2));
4383 p.drawLine(QLineF(1, d, 3, d));
4385 // ensure that a horizontal line and a vertical line with square cap round up (downwards) at the same time
4386 QCOMPARE(image.pixel(0, 0), image.pixel(1, 0));
4388 image.fill(0xffffffff);
4390 p.drawLine(QLineF(d, 0, d + 2, 0));
4391 p.drawLine(QLineF(d, 1, d, 3));
4393 // ensure that a vertical line and a horizontal line with square cap round up (to the right) at the same time
4394 QCOMPARE(image.pixel(0, 0), image.pixel(0, 1));
4398 void tst_QPainter::QTBUG25153_drawLine()
4400 QImage image(2, 2, QImage::Format_RGB32);
4402 QVector<Qt::PenCapStyle> styles;
4403 styles << Qt::FlatCap << Qt::SquareCap << Qt::RoundCap;
4405 foreach (Qt::PenCapStyle style, styles) {
4406 image.fill(0xffffffff);
4408 p.setPen(QPen(Qt::black, 0, Qt::SolidLine, style));
4409 p.drawLine(QLineF(0, 0, 0, 0));
4412 QCOMPARE(image.pixel(0, 0), 0xff000000);
4413 QCOMPARE(image.pixel(0, 1), 0xffffffff);
4414 QCOMPARE(image.pixel(1, 0), 0xffffffff);
4418 QTEST_MAIN(tst_QPainter)
4420 #include "tst_qpainter.moc"