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 <qregion.h>
32
33#include <qbitmap.h>
34#include <qpainter.h>
35#include <qpainterpath.h>
36#include <qpolygon.h>
37
38class tst_QRegion : public QObject
39{
40 Q_OBJECT
41
42public:
43 tst_QRegion();
44
45private slots:
46 void moveSemantics();
47 void boundingRect();
48 void rangeFor();
49 void rects();
50 void swap();
51 void setRects();
52 void ellipseRegion();
53 void polygonRegion();
54 void bitmapRegion();
55 void intersected_data();
56 void intersected();
57 void emptyPolygonRegion_data();
58 void emptyPolygonRegion();
59
60 void intersects_region_data();
61 void intersects_region();
62 void intersects_rect_data();
63 void intersects_rect();
64 void contains_point();
65
66 void operator_plus_data();
67 void operator_plus();
68 void operator_minus_data();
69 void operator_minus();
70 void operator_intersect_data();
71 void operator_intersect();
72 void operator_xor_data();
73 void operator_xor();
74
75 void rectCount_data();
76 void rectCount();
77
78 void isEmpty_data();
79 void isEmpty();
80
81 void regionFromPath();
82 void scaleRegions_data();
83 void scaleRegions();
84
85#ifdef QT_BUILD_INTERNAL
86 void regionToPath_data();
87 void regionToPath();
88#endif
89};
90
91tst_QRegion::tst_QRegion()
92{
93}
94
95void tst_QRegion::moveSemantics()
96{
97 const QRegion rect(QRect(0, 0, 100, 100));
98
99 // move assignment
100 {
101 QRegion r1 = rect;
102 QRegion r2;
103 r2 = std::move(r1);
104 QVERIFY(r1.isNull());
105 QCOMPARE(r2, rect);
106 }
107
108 // move construction
109 {
110 QRegion r1 = rect;
111 QRegion r2 = std::move(r1);
112 QVERIFY(r1.isNull());
113 QCOMPARE(r2, rect);
114 }
115}
116
117void tst_QRegion::boundingRect()
118{
119 {
120 QRect rect;
121 QRegion region(rect);
122 QCOMPARE(region.boundingRect(), rect);
123 }
124 {
125 QRect rect(10, -20, 30, 40);
126 QRegion region(rect);
127 QCOMPARE(region.boundingRect(), rect);
128 }
129 {
130 QRect rect(15,25,10,10);
131 QRegion region(rect);
132 QCOMPARE(region.boundingRect(), rect);
133 }
134
135}
136
137void tst_QRegion::rangeFor()
138{
139 // compile-only test for range-for over QRegion, so really useless
140 // content otherwise:
141 QRect rect(10, -20, 30, 40);
142 QRegion region(rect);
143 int equal = 0;
144 for (const QRect &r : region) // check this compiles
145 equal += int(r == rect); // can't use QCOMPARE here b/c of the
146 // MSVC 201272013 parse bug re:
147 // do-while in range-for loops
148 QCOMPARE(equal, 1);
149}
150
151void tst_QRegion::rects()
152{
153 {
154 QRect rect;
155 QRegion region(rect);
156 QVERIFY(region.isEmpty());
157 QCOMPARE(region.begin(), region.end());
158#if QT_DEPRECATED_SINCE(5, 11)
159 QVERIFY(region.rects().isEmpty());
160#endif
161 }
162 {
163 QRect rect(10, -20, 30, 40);
164 QRegion region(rect);
165 QCOMPARE(region.end(), region.begin() + 1);
166 QCOMPARE(*region.begin(), rect);
167#if QT_DEPRECATED_SINCE(5, 11)
168 QCOMPARE(region.rects().count(), 1);
169 QCOMPARE(region.rects()[0], rect);
170#endif
171 }
172 {
173 QRect r(QPoint(10, 10), QPoint(40, 40));
174 QRegion region(r);
175 QVERIFY(region.contains(QPoint(10,10)));
176 QVERIFY(region.contains(QPoint(20,40)));
177 QVERIFY(region.contains(QPoint(40,20)));
178 QVERIFY(!region.contains(QPoint(20,41)));
179 QVERIFY(!region.contains(QPoint(41,20)));
180 }
181 {
182 QRect r(10, 10, 30, 30);
183 QRegion region(r);
184 QVERIFY(region.contains(QPoint(10,10)));
185 QVERIFY(region.contains(QPoint(20,39)));
186 QVERIFY(region.contains(QPoint(39,20)));
187 QVERIFY(!region.contains(QPoint(20,40)));
188 QVERIFY(!region.contains(QPoint(40,20)));
189 }
190}
191
192void tst_QRegion::swap()
193{
194 QRegion r1(QRect(0, 0,10,10));
195 QRegion r2(QRect(10,10,10,10));
196 r1.swap(other&: r2);
197 QCOMPARE(*r1.begin(), QRect(10,10,10,10));
198 QCOMPARE(*r2.begin(), QRect(0, 0,10,10));
199}
200
201void tst_QRegion::setRects()
202{
203 {
204 QRegion region;
205 region.setRects(rect: 0, num: 0);
206 QVERIFY(region.isEmpty());
207 QCOMPARE(region.begin(), region.end());
208 }
209 {
210 QRegion region;
211 QRect rect;
212 region.setRects(rect: &rect, num: 0);
213 QVERIFY(region.isEmpty());
214 QCOMPARE(region, QRegion());
215 QCOMPARE(region.begin(), region.end());
216 QVERIFY(!region.boundingRect().isValid());
217#if QT_DEPRECATED_SINCE(5, 11)
218 QVERIFY(region.rects().isEmpty());
219#endif
220 }
221 {
222 QRegion region;
223 QRect rect;
224 region.setRects(rect: &rect, num: 1);
225 QCOMPARE(region.begin(), region.end());
226 QVERIFY(!region.boundingRect().isValid());
227#if QT_DEPRECATED_SINCE(5, 11)
228 QVERIFY(region.rects().isEmpty());
229#endif
230 }
231 {
232 QRegion region;
233 QRect rect(10, -20, 30, 40);
234 region.setRects(rect: &rect, num: 1);
235 QCOMPARE(region.end(), region.begin() + 1);
236#if QT_DEPRECATED_SINCE(5, 11)
237 QCOMPARE(region.rects().count(), 1);
238 QCOMPARE(region.rects()[0], rect);
239#endif
240 QCOMPARE(*region.begin(), rect);
241 }
242}
243
244void tst_QRegion::ellipseRegion()
245{
246 QRegion region(0, 0, 100, 100, QRegion::Ellipse);
247
248 // These should not be inside the circe
249 QVERIFY(!region.contains(QPoint(13, 13)));
250 QVERIFY(!region.contains(QPoint(13, 86)));
251 QVERIFY(!region.contains(QPoint(86, 13)));
252 QVERIFY(!region.contains(QPoint(86, 86)));
253
254 // These should be inside
255 QVERIFY(region.contains(QPoint(16, 16)));
256 QVERIFY(region.contains(QPoint(16, 83)));
257 QVERIFY(region.contains(QPoint(83, 16)));
258 QVERIFY(region.contains(QPoint(83, 83)));
259
260 // ..a..
261 // .. ..
262 // . .
263 // . .
264 // b c
265 // . .
266 // . .
267 // .. ..
268 // ..d..
269 QVERIFY(region.contains(QPoint(50, 0))); // Mid-top (a)
270 QVERIFY(region.contains(QPoint(0, 50))); // Mid-left (b)
271 QVERIFY(region.contains(QPoint(99, 50))); // Mid-right (c)
272 QVERIFY(region.contains(QPoint(50, 99))); // Mid-bottom (d)
273
274 QRect bounds = region.boundingRect();
275 QCOMPARE(bounds.x(), 0);
276 QCOMPARE(bounds.y(), 0);
277 QCOMPARE(bounds.width(), 100);
278 QCOMPARE(bounds.height(), 100);
279}
280
281void tst_QRegion::polygonRegion()
282{
283 QPolygon pa;
284 {
285 QRegion region (pa);
286 QVERIFY(region.isEmpty());
287 }
288 {
289 pa.setPoints(nPoints: 8, firstx: 10, firsty: 10, // a____________b
290 40, 10, // | |
291 40, 20, // |___ ___|
292 30, 20, // | |
293 30, 40, // | |
294 20, 40, // | |
295 20, 20, // |____c
296 10, 20);
297
298 QRegion region (pa);
299 QVERIFY(!region.isEmpty());
300
301 // These should not be inside the circle
302 QVERIFY(!region.contains(QPoint( 9, 9)));
303 QVERIFY(!region.contains(QPoint(30, 41)));
304 QVERIFY(!region.contains(QPoint(41, 10)));
305 QVERIFY(!region.contains(QPoint(31, 21)));
306
307 // These should be inside
308 QVERIFY(region.contains(QPoint(10, 10))); // Upper-left (a)
309
310 }
311}
312
313void tst_QRegion::emptyPolygonRegion_data()
314{
315 QTest::addColumn<QPolygon>(name: "pa");
316 QTest::addColumn<bool>(name: "isEmpty");
317 QTest::addColumn<int>(name: "numRects");
318 QTest::addColumn<QVector<QRect> >(name: "rects");
319
320 QPolygon pa;
321
322
323 QTest::newRow(dataTag: "no points") << pa << true << 0 << QVector<QRect>();
324 pa = QPolygon() << QPoint(10,10);
325 QTest::newRow(dataTag: "one point") << pa << true << 0 << QVector<QRect>();
326 pa = QPolygon() << QPoint(10,10) << QPoint(10,20);
327 QTest::newRow(dataTag: "two points, horizontal") << pa << true << 0 << QVector<QRect>();
328
329 pa = QPolygon() << QPoint(10,10) << QPoint(20,10);
330 QTest::newRow(dataTag: "two points, vertical") << pa << true << 0 << QVector<QRect>();
331
332 pa = QPolygon() << QPoint(10,10) << QPoint(20,20);
333 QTest::newRow(dataTag: "two points, diagonal") << pa << true << 0 << QVector<QRect>();
334
335 pa = QPolygon() << QPoint(10,10) << QPoint(15,15) << QPoint(10,15) << QPoint(10, 10) ;
336 QVector<QRect> v;
337 v << QRect(10,11,1, 1) << QRect(10,12,2,1) << QRect(10,13,3,1) << QRect(10,14,4,1);
338 QTest::newRow(dataTag: "triangle") << pa << false << 4 << v;
339
340 v.clear();
341 v << QRect(10,10,10,10);
342
343 QTest::newRow(dataTag: "rectangle") << QPolygon(QRect(10,10,10,10)) << false << 1 << v;
344
345}
346
347void tst_QRegion::emptyPolygonRegion()
348{
349 QFETCH(QPolygon, pa);
350
351 QRegion r(pa);
352 QTEST(r.isEmpty(), "isEmpty");
353 QTEST(int(std::distance(r.begin(), r.end())), "numRects");
354 QVector<QRect> rects;
355 std::copy(first: r.begin(), last: r.end(), result: std::back_inserter(x&: rects));
356 QTEST(rects.size(), "numRects");
357 QTEST(rects, "rects");
358#if QT_DEPRECATED_SINCE(5, 11)
359 QCOMPARE(r.rects(), rects);
360#endif
361}
362
363
364static const char *circle_xpm[] = {
365 "20 20 2 1",
366 " c #FFFFFF",
367 ". c #000000",
368 " ...... ",
369 " .......... ",
370 " .............. ",
371 " ................ ",
372 " ................ ",
373 " .................. ",
374 " .................. ",
375 "....................",
376 "....................",
377 "....................",
378 "....................",
379 "....................",
380 "....................",
381 " .................. ",
382 " .................. ",
383 " ................ ",
384 " ................ ",
385 " .............. ",
386 " .......... ",
387 " ...... "
388};
389
390void tst_QRegion::bitmapRegion()
391{
392 QBitmap circle;
393 {
394 QRegion region(circle);
395 QVERIFY(region.isEmpty());
396 }
397 {
398 circle = QPixmap(circle_xpm);
399 QRegion region(circle);
400
401 //// These should not be inside the circe
402 QVERIFY(!region.contains(QPoint(2, 2)));
403 QVERIFY(!region.contains(QPoint(2, 17)));
404 QVERIFY(!region.contains(QPoint(17, 2)));
405 QVERIFY(!region.contains(QPoint(17, 17)));
406
407 //// These should be inside
408 QVERIFY(region.contains(QPoint(3, 3)));
409 QVERIFY(region.contains(QPoint(3, 16)));
410 QVERIFY(region.contains(QPoint(16, 3)));
411 QVERIFY(region.contains(QPoint(16, 16)));
412
413 QVERIFY(region.contains(QPoint(0, 10))); // Mid-left
414 QVERIFY(region.contains(QPoint(10, 0))); // Mid-top
415 QVERIFY(region.contains(QPoint(19, 10))); // Mid-right
416 QVERIFY(region.contains(QPoint(10, 19))); // Mid-bottom
417 }
418}
419
420void tst_QRegion::intersected_data()
421{
422 QTest::addColumn<QRegion>(name: "r1");
423 QTest::addColumn<QRegion>(name: "r2");
424 QTest::addColumn<bool>(name: "intersects");
425 // QTest::addColumn<QRegion>("intersected");
426
427 QPolygon ps1(8);
428 QPolygon ps2(8);
429 ps1.putPoints(index: 0,nPoints: 8, firstx: 20,firsty: 20, 50,20, 50,100, 70,100, 70,20, 120,20, 120,200, 20, 200);
430 ps2.putPoints(index: 0,nPoints: 8, firstx: 100,firsty: 150, 140,150, 140,160, 160,160, 160,150, 200,150, 200,180, 100,180);
431 QTest::newRow(dataTag: "task30716") << QRegion(ps1) << QRegion(ps2) << true;
432}
433
434void tst_QRegion::intersected()
435{
436 QFETCH(QRegion, r1);
437 QFETCH(QRegion, r2);
438 QFETCH(bool, intersects);
439
440 QRegion interReg = r1.intersected(r: r2);
441 QVERIFY(interReg.isEmpty() != intersects);
442 // Need a way to test the intersected QRegion is right
443}
444
445void tst_QRegion::intersects_region_data()
446{
447 QTest::addColumn<QRegion>(name: "r1");
448 QTest::addColumn<QRegion>(name: "r2");
449 QTest::addColumn<bool>(name: "intersects");
450
451 QTest::newRow(dataTag: "rect overlap rect") << QRegion(100, 100, 200, 200)
452 << QRegion(200, 200, 200, 200)
453 << true;
454
455 QTest::newRow(dataTag: "rect not overlap rect") << QRegion(100, 100, 200, 200)
456 << QRegion(400, 400, 200, 200)
457 << false;
458
459 QTest::newRow(dataTag: "ellipse overlap ellipse") << QRegion(100, 100, 200, 200, QRegion::Ellipse)
460 << QRegion(200, 200, 200, 200, QRegion::Ellipse)
461 << true;
462
463 QTest::newRow(dataTag: "ellipse not overlap ellipse") << QRegion(100, 100, 200, 200, QRegion::Ellipse)
464 << QRegion(400, 400, 200, 200, QRegion::Ellipse)
465 << false;
466}
467
468void tst_QRegion::intersects_region()
469{
470 QFETCH(QRegion, r1);
471 QFETCH(QRegion, r2);
472 QFETCH(bool, intersects);
473 QCOMPARE(r1.intersects(r2), intersects);
474}
475
476
477void tst_QRegion::intersects_rect_data()
478{
479 QTest::addColumn<QRegion>(name: "region");
480 QTest::addColumn<QRect>(name: "rect");
481 QTest::addColumn<bool>(name: "intersects");
482
483 QTest::newRow(dataTag: "rect overlap rect") << QRegion(100, 100, 200, 200)
484 << QRect(200, 200, 200, 200)
485 << true;
486
487 QTest::newRow(dataTag: "rect not overlap rect") << QRegion(100, 100, 200, 200)
488 << QRect(400, 400, 200, 200)
489 << false;
490
491 QTest::newRow(dataTag: "ellipse overlap rect") << QRegion(100, 100, 200, 200, QRegion::Ellipse)
492 << QRect(200, 200, 200, 200)
493 << true;
494
495 QTest::newRow(dataTag: "ellipse not overlap rect") << QRegion(100, 100, 200, 200, QRegion::Ellipse)
496 << QRect(400, 400, 200, 200)
497 << false;
498}
499
500void tst_QRegion::intersects_rect()
501{
502 QFETCH(QRegion, region);
503 QFETCH(QRect, rect);
504 QFETCH(bool, intersects);
505 QCOMPARE(region.intersects(rect), intersects);
506}
507
508void tst_QRegion::contains_point()
509{
510 QCOMPARE(QRegion().contains(QPoint(1,1)),false);
511 QCOMPARE(QRegion(0,0,2,2).contains(QPoint(1,1)),true);
512}
513
514void tst_QRegion::operator_plus_data()
515{
516 QTest::addColumn<QRegion>(name: "r1");
517 QTest::addColumn<QRegion>(name: "r2");
518 QTest::addColumn<QRegion>(name: "expected");
519
520 QTest::newRow(dataTag: "empty 0") << QRegion() << QRegion() << QRegion();
521 QTest::newRow(dataTag: "empty 1") << QRegion() << QRegion(QRect(10, 10, 10, 10))
522 << QRegion(QRect(10, 10, 10, 10));
523 QTest::newRow(dataTag: "empty 2") << QRegion(QRect(10, 10, 10, 10)) << QRegion()
524 << QRegion(QRect(10, 10, 10, 10));
525
526 QRegion expected;
527 QVector<QRect> rects;
528 rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10);
529 expected.setRects(rect: rects.constData(), num: rects.size());
530 QTest::newRow(dataTag: "non overlapping") << QRegion(10, 10, 10, 10)
531 << QRegion(22, 10, 10, 10)
532 << expected;
533
534 rects.clear();
535 rects << QRect(50, 0, 50, 2);
536 expected.setRects(rect: rects.constData(), num: rects.size());
537 QTest::newRow(dataTag: "adjacent y-rects") << QRegion(50, 0, 50, 1)
538 << QRegion(50, 1, 50, 1)
539 << expected;
540
541 rects.clear();
542 rects << QRect(50, 0, 2, 1);
543 expected.setRects(rect: rects.constData(), num: rects.size());
544 QTest::newRow(dataTag: "adjacent x-rects") << QRegion(50, 0, 1, 1)
545 << QRegion(51, 0, 1, 1)
546 << expected;
547
548 rects.clear();
549 rects << QRect(10, 10, 10, 10) << QRect(10, 20, 5, 10);
550 QRegion r1;
551 r1.setRects(rect: rects.constData(), num: rects.size());
552 QTest::newRow(dataTag: "double merge") << r1 << QRegion(15, 20, 5, 10)
553 << QRegion(10, 10, 10, 20);
554 rects.clear();
555 rects << QRect(15, 10, 5, 10) << QRect(10, 20, 10, 10);
556 r1.setRects(rect: rects.constData(), num: rects.size());
557 QTest::newRow(dataTag: "double merge 2") << r1 << QRegion(10, 10, 5, 10)
558 << QRegion(10, 10, 10, 20);
559 QTest::newRow(dataTag: "overlapping x") << QRegion(10, 10, 10, 10)
560 << QRegion(15, 10, 10, 10)
561 << QRegion(10, 10, 15, 10);
562 QTest::newRow(dataTag: "overlapping y") << QRegion(10, 10, 10, 10)
563 << QRegion(10, 15, 10, 10)
564 << QRegion(10, 10, 10, 15);
565 rects.clear();
566 rects << QRect(10, 10, 10, 10) << QRect(10, 20, 5, 10);
567 r1.setRects(rect: rects.constData(), num: rects.size());
568 rects.clear();
569 rects << QRect(15, 20, 5, 10) << QRect(10, 30, 10, 10);
570 QRegion r2;
571 r2.setRects(rect: rects.constData(), num: rects.size());
572 QTest::newRow(dataTag: "triple merge") << r1 << r2
573 << QRegion(10, 10, 10, 30);
574
575 rects.clear();
576 rects << QRect(10, 10, 4, 10) << QRect(15, 10, 10, 10);
577 r1.setRects(rect: rects.constData(), num: rects.size());
578 rects.clear();
579 rects << QRect(15, 20, 10, 10);
580 r2.setRects(rect: rects.constData(), num: rects.size());
581 rects.clear();
582 rects << QRect(10, 10, 4, 10) << QRect(15, 10, 10, 10)
583 << QRect(15, 20, 10, 10);
584 expected.setRects(rect: rects.constData(), num: rects.size());
585 QTest::newRow(dataTag: "don't merge y") << r1 << r2 << expected;
586
587 QTest::newRow(dataTag: "equal 1") << QRegion(10, 10, 10, 10)
588 << QRegion(10, 10, 10, 10)
589 << QRegion(10, 10, 10, 10);
590 QTest::newRow(dataTag: "equal 2") << expected << expected << expected;
591}
592
593void tst_QRegion::operator_plus()
594{
595 QFETCH(QRegion, r1);
596 QFETCH(QRegion, r2);
597 QFETCH(QRegion, expected);
598
599 if (r1 + r2 != expected) {
600 qDebug() << "r1 + r2" << (r1 + r2);
601 qDebug() << "expected" << expected;
602 }
603 QCOMPARE(r1 + r2, expected);
604 if (r2.rectCount() == 1) {
605 if (r1 + r2.boundingRect() != expected) {
606 qDebug() << "r1 + QRect(r2)" << (r1 + r2.boundingRect());
607 qDebug() << "expected" << expected;
608 }
609 QCOMPARE(r1 + r2.boundingRect(), expected);
610 }
611
612 if (r2 + r1 != expected) {
613 qDebug() << "r2 + r1" << (r2 + r1);
614 qDebug() << "expected" << expected;
615 }
616 QCOMPARE(r2 + r1, expected);
617 if (r1.rectCount() == 1) {
618 if (r1 + r2.boundingRect() != expected) {
619 qDebug() << "r2 + QRect(r1)" << (r2 + r1.boundingRect());
620 qDebug() << "expected" << expected;
621 }
622 QCOMPARE(r2 + r1.boundingRect(), expected);
623 }
624
625 QRegion result1 = r1;
626 result1 += r2;
627 if (result1 != expected) {
628 qDebug() << "r1 += r2" << result1;
629 qDebug() << "expected" << expected;
630 }
631 QCOMPARE(result1, expected);
632 if (r2.rectCount() == 1) {
633 result1 = r1;
634 result1 += r2.boundingRect();
635 if (result1 != expected) {
636 qDebug() << "r1 += QRect(r2)" << result1;
637 qDebug() << "expected" << expected;
638 }
639 QCOMPARE(result1, expected);
640 }
641
642 QRegion result2 = r2;
643 result2 += r1;
644 if (result2 != expected) {
645 qDebug() << "r2 += r1" << result2;
646 qDebug() << "expected" << expected;
647 }
648 QCOMPARE(result2, expected);
649 if (r1.rectCount() == 1) {
650 result2 = r2;
651 result2 += r1.boundingRect();
652 if (result2 != expected) {
653 qDebug() << "r2 += QRect(r1)" << result2;
654 qDebug() << "expected" << expected;
655 }
656 QCOMPARE(result2, expected);
657 }
658}
659
660void tst_QRegion::operator_minus_data()
661{
662 QTest::addColumn<QRegion>(name: "dest");
663 QTest::addColumn<QRegion>(name: "subtract");
664 QTest::addColumn<QRegion>(name: "expected");
665
666 QTest::newRow(dataTag: "empty 0") << QRegion() << QRegion() << QRegion();
667 QTest::newRow(dataTag: "empty 1") << QRegion() << QRegion(QRect(10, 10, 10, 10))
668 << QRegion();
669 QTest::newRow(dataTag: "empty 2") << QRegion(QRect(10, 10, 10, 10)) << QRegion()
670 << QRegion(QRect(10, 10, 10, 10));
671
672 QRegion dest;
673 QVector<QRect> rects;
674 rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10);
675 dest.setRects(rect: rects.constData(), num: rects.size());
676 QTest::newRow(dataTag: "simple 1") << dest
677 << QRegion(22, 10, 10, 10)
678 << QRegion(10, 10, 10, 10);
679 QTest::newRow(dataTag: "simple 2") << dest
680 << QRegion(10, 10, 10, 10)
681 << QRegion(22, 10, 10, 10);
682
683 rects.clear();
684 rects << QRect(0, 0, 10, 10) << QRect(15, 0, 10, 10);
685 dest.setRects(rect: rects.constData(), num: rects.size());
686
687 QRegion minus;
688 rects.clear();
689 rects << QRect(0, 0, 12, 12) << QRect(15, 0, 12, 12);
690 minus.setRects(rect: rects.constData(), num: rects.size());
691 QTest::newRow(dataTag: "empty 3") << dest << minus << QRegion();
692}
693
694void tst_QRegion::operator_minus()
695{
696 QFETCH(QRegion, dest);
697 QFETCH(QRegion, subtract);
698 QFETCH(QRegion, expected);
699
700 if (dest - subtract != expected) {
701 qDebug() << "dest - subtract" << (dest - subtract);
702 qDebug() << "expected" << expected;
703 };
704 QCOMPARE(dest - subtract, expected);
705
706 dest -= subtract;
707
708 if (dest != expected) {
709 qDebug() << "dest" << dest;
710 qDebug() << "expected" << expected;
711 };
712 QCOMPARE(dest, expected);
713}
714
715void tst_QRegion::operator_intersect_data()
716{
717 QTest::addColumn<QRegion>(name: "r1");
718 QTest::addColumn<QRegion>(name: "r2");
719 QTest::addColumn<QRegion>(name: "expected");
720
721 QTest::newRow(dataTag: "empty 0") << QRegion() << QRegion() << QRegion();
722 QTest::newRow(dataTag: "empty 1") << QRegion() << QRegion(QRect(10, 10, 10, 10))
723 << QRegion();
724 QTest::newRow(dataTag: "empty 2") << QRegion(QRect(10, 10, 10, 10)) << QRegion()
725 << QRegion();
726
727 QRegion dest;
728 QVector<QRect> rects;
729 rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10);
730 dest.setRects(rect: rects.constData(), num: rects.size());
731 QTest::newRow(dataTag: "simple 1") << dest
732 << QRegion(22, 10, 10, 10)
733 << QRegion(22, 10, 10, 10);
734 QTest::newRow(dataTag: "simple 2") << dest
735 << QRegion(10, 10, 10, 10)
736 << QRegion(10, 10, 10, 10);
737
738 rects.clear();
739 rects << QRect(10, 10, 10, 10) << QRect(10, 20, 15, 10);
740 dest.setRects(rect: rects.constData(), num: rects.size());
741 QTest::newRow(dataTag: "merge 1") << dest
742 << QRegion(10, 10, 10, 20)
743 << QRegion(10, 10, 10, 20);
744
745 rects.clear();
746 rects << QRect(11, 11, 218, 117) << QRect(11, 128, 218, 27)
747 << QRect(264, 128, 122, 27) << QRect(11, 155, 218, 43)
748 << QRect(11, 198, 218, 27) << QRect(264, 198, 122, 27)
749 << QRect(11, 225, 218, 221);
750 dest.setRects(rect: rects.constData(), num: rects.size());
751 QTest::newRow(dataTag: "merge 2") << dest << QRegion(11, 11, 218, 458)
752 << QRegion(11, 11, 218, 435);
753
754 rects.clear();
755 rects << QRect(0, 0, 10, 10) << QRect(20, 0, 10, 10);
756 dest.setRects(rect: rects.constData(), num: rects.size());
757 QTest::newRow(dataTag: "empty 3") << dest << QRegion(11, 0, 5, 5) << QRegion();
758
759 QTest::newRow(dataTag: "extents check") << dest << QRegion(0, 0, 15, 15)
760 << QRegion(0, 0, 10, 10);
761
762 rects.clear();
763 rects << QRect(10, 10, 10, 10) << QRect(10, 20, 10, 10)
764 << QRect(30, 20, 10, 10) << QRect(10, 30, 10, 10);
765 dest.setRects(rect: rects.constData(), num: rects.size());
766 rects.clear();
767 rects << QRect(10, 10, 10, 10) << QRect(10, 20, 10, 10)
768 << QRect(30, 20, 10, 10);
769 QRegion expected;
770 expected.setRects(rect: rects.constData(), num: rects.size());
771 QTest::newRow(dataTag: "dont merge") << dest << QRegion(0, 0, 100, 30)
772 << expected;
773}
774
775void tst_QRegion::operator_intersect()
776{
777 QFETCH(QRegion, r1);
778 QFETCH(QRegion, r2);
779 QFETCH(QRegion, expected);
780
781 if ((r1 & r2) != expected) {
782 qDebug() << "r1 & r2" << (r1 & r2);
783 qDebug() << "expected" << expected;
784 }
785 QCOMPARE(r1 & r2, expected);
786
787 if ((r2 & r1) != expected) {
788 qDebug() << "r2 & r1" << (r2 & r1);
789 qDebug() << "expected" << expected;
790 }
791 QCOMPARE(r2 & r1, expected);
792
793 r1 &= r2;
794 QCOMPARE(r1, expected);
795}
796
797void tst_QRegion::operator_xor_data()
798{
799 QTest::addColumn<QRegion>(name: "dest");
800 QTest::addColumn<QRegion>(name: "arg");
801 QTest::addColumn<QRegion>(name: "expected");
802
803 QTest::newRow(dataTag: "empty 0") << QRegion() << QRegion() << QRegion();
804 QTest::newRow(dataTag: "empty 1") << QRegion() << QRegion(QRect(10, 10, 10, 10))
805 << QRegion(QRect(10, 10, 10, 10));
806 QTest::newRow(dataTag: "empty 2") << QRegion(QRect(10, 10, 10, 10)) << QRegion()
807 << QRegion(QRect(10, 10, 10, 10));
808
809 QRegion dest;
810 QVector<QRect> rects;
811 rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10);
812 dest.setRects(rect: rects.constData(), num: rects.size());
813 QTest::newRow(dataTag: "simple 1") << dest
814 << QRegion(22, 10, 10, 10)
815 << QRegion(10, 10, 10, 10);
816 QTest::newRow(dataTag: "simple 2") << dest
817 << QRegion(10, 10, 10, 10)
818 << QRegion(22, 10, 10, 10);
819 QTest::newRow(dataTag: "simple 3") << dest << dest << QRegion();
820 QTest::newRow(dataTag: "simple 4") << QRegion(10, 10, 10, 10)
821 << QRegion(10, 10, 5, 10)
822 << QRegion(15, 10, 5, 10);
823 QTest::newRow(dataTag: "simple 5") << QRegion(10, 10, 10, 10)
824 << QRegion(10, 10, 10, 5)
825 << QRegion(10, 15, 10, 5);
826
827 const QRegion rgnA(0, 0, 100, 100);
828 const QRegion rgnB(0, 0, 10, 10);
829
830 QTest::newRow(dataTag: "simple 6") << rgnA
831 << rgnA - rgnB
832 << rgnB;
833
834 QTest::newRow(dataTag: "simple 7") << rgnB
835 << rgnA
836 << rgnA - rgnB;
837}
838
839void tst_QRegion::operator_xor()
840{
841 QFETCH(QRegion, dest);
842 QFETCH(QRegion, arg);
843 QFETCH(QRegion, expected);
844
845 QCOMPARE(dest ^ arg, expected);
846 QCOMPARE(dest.xored(arg), expected);
847
848 dest ^= arg;
849 QCOMPARE(dest, expected);
850}
851
852void tst_QRegion::rectCount_data()
853{
854 QTest::addColumn<QRegion>(name: "region");
855 QTest::addColumn<int>(name: "expected");
856
857 QTest::newRow(dataTag: "empty") << QRegion() << 0;
858 QTest::newRow(dataTag: "rect") << QRegion(10, 10, 10, 10) << 1;
859
860 QRegion dest;
861 QVector<QRect> rects;
862 rects << QRect(10, 10, 10, 10) << QRect(22, 10, 10, 10);
863 dest.setRects(rect: rects.constData(), num: rects.size());
864
865 QTest::newRow(dataTag: "2 rects") << dest << rects.size();
866}
867
868void tst_QRegion::rectCount()
869{
870 QFETCH(QRegion, region);
871 QFETCH(int, expected);
872
873 QCOMPARE(region.rectCount(), expected);
874}
875
876void tst_QRegion::isEmpty_data()
877{
878 QTest::addColumn<QRegion>(name: "region");
879
880 QTest::newRow(dataTag: "QRegion") << QRegion();
881
882 QVector<QRect> rects;
883 rects << QRect(0, 0, 10, 10) << QRect(15, 0, 10, 10);
884 QRegion r1;
885 r1.setRects(rect: rects.constData(), num: rects.size());
886
887 QRegion r2;
888 rects.clear();
889 rects << QRect(0, 0, 12, 12) << QRect(15, 0, 12, 12);
890 r2.setRects(rect: rects.constData(), num: rects.size());
891 QTest::newRow(dataTag: "minus") << (r1 - r2);
892}
893
894void tst_QRegion::isEmpty()
895{
896 QFETCH(QRegion, region);
897
898 QVERIFY(region.isEmpty());
899 QCOMPARE(region.begin(), region.end());
900 QCOMPARE(region, QRegion());
901 QCOMPARE(region.rectCount(), 0);
902 QCOMPARE(region.boundingRect(), QRect());
903#if QT_DEPRECATED_SINCE(5, 11)
904 QVERIFY(region.rects().isEmpty());
905#endif
906}
907
908void tst_QRegion::regionFromPath()
909{
910 {
911 QPainterPath path;
912 path.addRect(x: 0, y: 0, w: 10, h: 10);
913 path.addRect(x: 0, y: 100, w: 100, h: 1000);
914
915 QRegion rgn(path.toFillPolygon().toPolygon());
916
917 QCOMPARE(rgn.end(), rgn.begin() + 2);
918 QCOMPARE(rgn.begin()[0], QRect(0, 0, 10, 10));
919 QCOMPARE(rgn.begin()[1], QRect(0, 100, 100, 1000));
920
921#if QT_DEPRECATED_SINCE(5, 11)
922 QCOMPARE(rgn.rects().size(), 2);
923 QCOMPARE(rgn.rects().at(0), QRect(0, 0, 10, 10));
924 QCOMPARE(rgn.rects().at(1), QRect(0, 100, 100, 1000));
925#endif
926
927 QCOMPARE(rgn.boundingRect(), QRect(0, 0, 100, 1100));
928 }
929
930 {
931 QPainterPath path;
932 path.addRect(x: 0, y: 0, w: 100, h: 100);
933 path.addRect(x: 10, y: 10, w: 80, h: 80);
934
935 QRegion rgn(path.toFillPolygon().toPolygon());
936
937 QCOMPARE(rgn.end(), rgn.begin() + 4);
938 QCOMPARE(rgn.begin()[0], QRect(0, 0, 100, 10));
939 QCOMPARE(rgn.begin()[1], QRect(0, 10, 10, 80));
940 QCOMPARE(rgn.begin()[2], QRect(90, 10, 10, 80));
941 QCOMPARE(rgn.begin()[3], QRect(0, 90, 100, 10));
942
943#if QT_DEPRECATED_SINCE(5, 11)
944 QCOMPARE(rgn.rects().size(), 4);
945 QCOMPARE(rgn.rects().at(0), QRect(0, 0, 100, 10));
946 QCOMPARE(rgn.rects().at(1), QRect(0, 10, 10, 80));
947 QCOMPARE(rgn.rects().at(2), QRect(90, 10, 10, 80));
948 QCOMPARE(rgn.rects().at(3), QRect(0, 90, 100, 10));
949#endif
950
951 QCOMPARE(rgn.boundingRect(), QRect(0, 0, 100, 100));
952 }
953}
954
955void tst_QRegion::scaleRegions_data()
956{
957 QTest::addColumn<qreal>(name: "scale");
958 QTest::addColumn<QVector<QRect>>(name: "inputRects");
959 QTest::addColumn<QVector<QRect>>(name: "expectedRects");
960
961 QTest::newRow(dataTag: "1.0 single") << 1.0
962 << QVector<QRect>{ QRect(10, 10, 20, 20) }
963 << QVector<QRect>{ QRect(10, 10, 20, 20) };
964 QTest::newRow(dataTag: "1.0 multi") << 1.0
965 << QVector<QRect>{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) }
966 << QVector<QRect>{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) };
967 QTest::newRow(dataTag: "2.0 single") << 2.0
968 << QVector<QRect>{ QRect(10, 10, 20, 20) }
969 << QVector<QRect>{ QRect(20, 20, 40, 40) };
970 QTest::newRow(dataTag: "2.0 multi") << 2.0
971 << QVector<QRect>{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) }
972 << QVector<QRect>{ QRect(20, 20, 40, 40), QRect(80, 20, 40, 40) };
973 QTest::newRow(dataTag: "-1.0 single") << -1.0
974 << QVector<QRect>{ QRect(10, 10, 20, 20) }
975 << QVector<QRect>{ QRect(-30, -30, 20, 20) };
976 QTest::newRow(dataTag: "-1.0 multi") << -1.0
977 << QVector<QRect>{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) }
978 << QVector<QRect>{ QRect(-60, -30, 20, 20), QRect(-30, -30, 20, 20) };
979 QTest::newRow(dataTag: "-2.0 single") << -2.0
980 << QVector<QRect>{ QRect(10, 10, 20, 20) }
981 << QVector<QRect>{ QRect(-60, -60, 40, 40) };
982 QTest::newRow(dataTag: "-2.0 multi") << -2.0
983 << QVector<QRect>{ QRect(10, 10, 20, 20), QRect(40, 10, 20, 20) }
984 << QVector<QRect>{ QRect(-120, -60, 40, 40), QRect(-60, -60, 40, 40) };
985}
986
987void tst_QRegion::scaleRegions()
988{
989 QFETCH(qreal, scale);
990 QFETCH(QVector<QRect>, inputRects);
991 QFETCH(QVector<QRect>, expectedRects);
992
993 QRegion region;
994 region.setRects(rect: inputRects.constData(), num: inputRects.size());
995
996 QRegion expected(expectedRects.first());
997 expected.setRects(rect: expectedRects.constData(), num: expectedRects.size());
998
999 QTransform t;
1000 t.scale(sx: scale, sy: scale);
1001
1002 auto result = t.map(r: region);
1003
1004 QCOMPARE(result.rectCount(), expectedRects.size());
1005 QCOMPARE(result, expected);
1006}
1007
1008Q_DECLARE_METATYPE(QPainterPath)
1009
1010#ifdef QT_BUILD_INTERNAL
1011void tst_QRegion::regionToPath_data()
1012{
1013 QTest::addColumn<QPainterPath>(name: "path");
1014 {
1015 QPainterPath path;
1016 path.addRect(rect: QRect(0, 0, 10, 10));
1017
1018 QTest::newRow(dataTag: "Rectangle") << path;
1019 }
1020
1021 {
1022 QPainterPath path;
1023 path.addRect(rect: QRect(0, 0, 10, 10));
1024 path.addRect(rect: QRect(20, 0, 10, 10));
1025
1026 QTest::newRow(dataTag: "Two rects") << path;
1027 }
1028
1029 {
1030 QPainterPath path;
1031 path.addEllipse(rect: QRect(0, 0, 10, 10));
1032
1033 QTest::newRow(dataTag: "Ellipse") << path;
1034 }
1035
1036 {
1037 QPainterPath path;
1038 path.addRect(rect: QRect(0, 0, 3, 8));
1039 path.addRect(rect: QRect(6, 0, 3, 8));
1040 path.addRect(rect: QRect(3, 3, 3, 2));
1041 path.addRect(rect: QRect(12, 3, 3, 2));
1042
1043 QTest::newRow(dataTag: "H-dot") << path;
1044 }
1045
1046 {
1047 QPainterPath path;
1048 for (int y = 0; y <= 10; ++y) {
1049 for (int x = 0; x <= 10; ++x) {
1050 if (!(y & 1) || ((x ^ y) & 1))
1051 path.addRect(rect: QRect(x, y, 1, 1));
1052 }
1053 }
1054
1055 QTest::newRow(dataTag: "Grid") << path;
1056 }
1057}
1058#endif
1059
1060#ifdef QT_BUILD_INTERNAL
1061QT_BEGIN_NAMESPACE
1062extern QPainterPath qt_regionToPath(const QRegion &region);
1063QT_END_NAMESPACE
1064#endif
1065
1066#ifdef QT_BUILD_INTERNAL
1067void tst_QRegion::regionToPath()
1068{
1069
1070 QFETCH(QPainterPath, path);
1071
1072 for (int i = 0; i < 360; i += 10) {
1073
1074 QTransform transform;
1075 transform.scale(sx: 5, sy: 5);
1076 transform.rotate(a: i);
1077
1078 QPainterPath mapped = transform.map(p: path);
1079 QRegion region(mapped.toFillPolygon().toPolygon());
1080
1081 QPainterPath a;
1082 a.addRegion(region);
1083
1084 QPainterPath b = qt_regionToPath(region);
1085
1086 QRect r = a.boundingRect().toAlignedRect();
1087 QImage ia(r.size(), QImage::Format_RGB32);
1088 ia.fill(pixel: 0xffffffff);
1089 QImage ib = ia;
1090
1091 QPainter p(&ia);
1092 p.translate(dx: -r.x(), dy: -r.y());
1093 p.fillPath(path: a, brush: Qt::red);
1094 p.end();
1095 p.begin(&ib);
1096 p.translate(dx: -r.x(), dy: -r.y());
1097 p.fillPath(path: b, brush: Qt::red);
1098 p.end();
1099
1100 QCOMPARE(ia, ib);
1101 QCOMPARE(a.boundingRect(), b.boundingRect());
1102 }
1103}
1104#endif
1105
1106QTEST_MAIN(tst_QRegion)
1107#include "tst_qregion.moc"
1108

source code of qtbase/tests/auto/gui/painting/qregion/tst_qregion.cpp