QRegion: re-add rects() and port setRects() to QSpan
In Qt 5, we had QVector<QRect> QRegion::rects(), but it was deprecated, because just iterating over the QRegion as a container of QRects was more efficient (QRegion has a SSO for the case of one rectangle). With QSpan, we can now bring it back with the same efficiency as iteration, supporting Qt 5 code that never made the move away from rects() and new code that wishes to make the conversion into rectangles more explicit. Re-add the Qt 5 tests, which show that the function is nearly a drop-in replacement for the Qt 5 rects() (QSpan, at the time of this commit, doesn't have relational operators, yet). Also add a QSpan overload of setRects(). The old (ptr, n) function (now obsoleted, but not deprecated) allowed nullptr + n != 0, which QSpan doesn't accept, so print a warning in that case. Also, QSpan can hold more than INT_MAX elements on 64-bit platforms, but QRegion's API was never ported from int to qsizetype, so we need to catch oversized spans used as inputs, too. [ChangeLog][QtGui][QRegion] Added QSpan overload of setRects(); re-added Qt5's rects(), but returning QSpan instead of QVector now. Fixes: QTBUG-124712 Change-Id: I24570c886cbf77abd8d1f4a3f42ae53c892cd9ff Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
f22e9795d9
commit
0076999031
@ -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<const QRect> 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<const QRect>(r, n));
|
||||
}
|
||||
|
||||
void QRegion::setRects(QSpan<const QRect> 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<QRect>
|
||||
instead.
|
||||
|
||||
\sa setRects()
|
||||
*/
|
||||
QSpan<const QRect> 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)
|
||||
|
@ -8,11 +8,11 @@
|
||||
#include <QtCore/qatomic.h>
|
||||
#include <QtCore/qrect.h>
|
||||
#include <QtGui/qwindowdefs.h>
|
||||
#include <QtCore/qcontainerfwd.h>
|
||||
|
||||
#ifndef QT_NO_DATASTREAM
|
||||
#include <QtCore/qdatastream.h>
|
||||
#endif
|
||||
#include <QtCore/qspan.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -75,6 +75,8 @@ public:
|
||||
|
||||
QRect boundingRect() const noexcept;
|
||||
void setRects(const QRect *rect, int num);
|
||||
void setRects(QSpan<const QRect> r);
|
||||
QSpan<const QRect> rects() const noexcept;
|
||||
int rectCount() const noexcept;
|
||||
|
||||
QRegion operator|(const QRegion &r) const;
|
||||
|
@ -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<QRect> rects;
|
||||
std::copy(r.begin(), r.end(), std::back_inserter(rects));
|
||||
QList<QRect> 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));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user