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