diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 8b712ee46d9..f9089d7bba2 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -876,9 +876,15 @@ QRegion QRegion::intersect(const QRect &r) const /*! \fn void QRegion::setRects(const QRect *rects, int number) + \overload + \obsolete Use the QSpan overload instead. +*/ - Sets the region using the array of rectangles specified by \a rects and - \a number. +/*! + \fn void QRegion::setRects(QSpan rects) + \since 6.8 + + Sets the region using the array of rectangles specified by \a rects. The rectangles \e must be optimally Y-X sorted and follow these restrictions: \list @@ -892,6 +898,11 @@ QRegion QRegion::intersect(const QRect &r) const \omit Only some platforms have these restrictions (Qt for Embedded Linux, X11 and \macos). \endomit + + \note For historical reasons, \c{rects.size()} must be less than \c{INT_MAX} + (see rectCount()). + + \sa rects() */ namespace { @@ -4214,18 +4225,39 @@ QRegion::const_iterator QRegion::end() const noexcept return d->qt_rgn ? d->qt_rgn->end() : nullptr; } -void QRegion::setRects(const QRect *rects, int num) +static Q_DECL_COLD_FUNCTION +void set_rects_warn(const char *what) { + qWarning("QRegion::setRects(): %s", what); +} + +void QRegion::setRects(const QRect *r, int n) +{ + if (!r && n) { // old setRects() allowed this, but QSpan doesn't + set_rects_warn("passing num != 0 when rects == nullptr is deprecated."); + n = 0; + } + setRects(QSpan(r, n)); +} + +void QRegion::setRects(QSpan rects) +{ + const auto num = int(rects.size()); + if (num != rects.size()) { + set_rects_warn("span size exceeds INT_MAX, ignoring"); + return; + } + *this = QRegion(); - if (!rects || num == 0 || (num == 1 && rects->isEmpty())) + if (!rects.data() || num == 0 || (num == 1 && rects.front().isEmpty())) return; detach(); d->qt_rgn->numRects = num; if (num == 1) { - d->qt_rgn->extents = *rects; - d->qt_rgn->innerRect = *rects; + d->qt_rgn->extents = rects.front(); + d->qt_rgn->innerRect = rects.front(); } else { d->qt_rgn->rects.resize(num); @@ -4246,12 +4278,30 @@ void QRegion::setRects(const QRect *rects, int num) } } +/*! + \since 6.8 + + Returns a span of non-overlapping rectangles that make up the region. The + span remains valid until the next call of a mutating (non-const) method on + this region. + + The union of all the rectangles is equal to the original region. + + \note This functions existed in Qt 5, too, but returned QVector + instead. + + \sa setRects() +*/ +QSpan QRegion::rects() const noexcept +{ + return {begin(), end()}; +}; + int QRegion::rectCount() const noexcept { return (d->qt_rgn ? d->qt_rgn->numRects : 0); } - bool QRegion::operator==(const QRegion &r) const { if (!d->qt_rgn) diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index b0051b60676..4b852815f32 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -8,11 +8,11 @@ #include #include #include -#include #ifndef QT_NO_DATASTREAM #include #endif +#include QT_BEGIN_NAMESPACE @@ -75,6 +75,8 @@ public: QRect boundingRect() const noexcept; void setRects(const QRect *rect, int num); + void setRects(QSpan r); + QSpan rects() const noexcept; int rectCount() const noexcept; QRegion operator|(const QRegion &r) const; diff --git a/tests/auto/gui/painting/qregion/tst_qregion.cpp b/tests/auto/gui/painting/qregion/tst_qregion.cpp index 3d60e62fc1a..934725844a6 100644 --- a/tests/auto/gui/painting/qregion/tst_qregion.cpp +++ b/tests/auto/gui/painting/qregion/tst_qregion.cpp @@ -138,12 +138,15 @@ void tst_QRegion::rects() QRegion region(rect); QVERIFY(region.isEmpty()); QCOMPARE(region.begin(), region.end()); + QVERIFY(region.rects().isEmpty()); } { QRect rect(10, -20, 30, 40); QRegion region(rect); QCOMPARE(region.end(), region.begin() + 1); QCOMPARE(*region.begin(), rect); + QCOMPARE(region.rects().size(), 1); + QCOMPARE(region.rects()[0], rect); } { QRect r(QPoint(10, 10), QPoint(40, 40)); @@ -190,6 +193,7 @@ void tst_QRegion::setRects() QCOMPARE(region, QRegion()); QCOMPARE(region.begin(), region.end()); QVERIFY(!region.boundingRect().isValid()); + QVERIFY(region.rects().isEmpty()); } { QRegion region; @@ -197,12 +201,15 @@ void tst_QRegion::setRects() region.setRects(&rect, 1); QCOMPARE(region.begin(), region.end()); QVERIFY(!region.boundingRect().isValid()); + QVERIFY(region.rects().isEmpty()); } { QRegion region; QRect rect(10, -20, 30, 40); region.setRects(&rect, 1); QCOMPARE(region.end(), region.begin() + 1); + QCOMPARE(region.rects().size(), 1); + QCOMPARE(region.rects()[0], rect); QCOMPARE(*region.begin(), rect); } } @@ -316,10 +323,12 @@ void tst_QRegion::emptyPolygonRegion() QRegion r(pa); QTEST(r.isEmpty(), "isEmpty"); QTEST(int(std::distance(r.begin(), r.end())), "numRects"); - QList rects; - std::copy(r.begin(), r.end(), std::back_inserter(rects)); + QList rects{r.begin(), r.end()}; QTEST(int(rects.size()), "numRects"); QTEST(rects, "rects"); + const auto span = r.rects(); + rects.assign(span.begin(), span.end()); + QTEST(rects, "rects"); } @@ -862,6 +871,7 @@ void tst_QRegion::isEmpty() QCOMPARE(region, QRegion()); QCOMPARE(region.rectCount(), 0); QCOMPARE(region.boundingRect(), QRect()); + QVERIFY(region.rects().isEmpty()); } void tst_QRegion::regionFromPath() @@ -877,6 +887,10 @@ void tst_QRegion::regionFromPath() QCOMPARE(rgn.begin()[0], QRect(0, 0, 10, 10)); QCOMPARE(rgn.begin()[1], QRect(0, 100, 100, 1000)); + QCOMPARE(rgn.rects().size(), 2); + QCOMPARE(rgn.rects()[0], QRect(0, 0, 10, 10)); + QCOMPARE(rgn.rects()[1], QRect(0, 100, 100, 1000)); + QCOMPARE(rgn.boundingRect(), QRect(0, 0, 100, 1100)); } @@ -893,6 +907,12 @@ void tst_QRegion::regionFromPath() QCOMPARE(rgn.begin()[2], QRect(90, 10, 10, 80)); QCOMPARE(rgn.begin()[3], QRect(0, 90, 100, 10)); + QCOMPARE(rgn.rects().size(), 4); + QCOMPARE(rgn.rects()[0], QRect(0, 0, 100, 10)); + QCOMPARE(rgn.rects()[1], QRect(0, 10, 10, 80)); + QCOMPARE(rgn.rects()[2], QRect(90, 10, 10, 80)); + QCOMPARE(rgn.rects()[3], QRect(0, 90, 100, 10)); + QCOMPARE(rgn.boundingRect(), QRect(0, 0, 100, 100)); } }