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)
|
\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:
|
The rectangles \e must be optimally Y-X sorted and follow these restrictions:
|
||||||
|
|
||||||
\list
|
\list
|
||||||
@ -892,6 +898,11 @@ QRegion QRegion::intersect(const QRect &r) const
|
|||||||
\omit
|
\omit
|
||||||
Only some platforms have these restrictions (Qt for Embedded Linux, X11 and \macos).
|
Only some platforms have these restrictions (Qt for Embedded Linux, X11 and \macos).
|
||||||
\endomit
|
\endomit
|
||||||
|
|
||||||
|
\note For historical reasons, \c{rects.size()} must be less than \c{INT_MAX}
|
||||||
|
(see rectCount()).
|
||||||
|
|
||||||
|
\sa rects()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -4214,18 +4225,39 @@ QRegion::const_iterator QRegion::end() const noexcept
|
|||||||
return d->qt_rgn ? d->qt_rgn->end() : nullptr;
|
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();
|
*this = QRegion();
|
||||||
if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
|
if (!rects.data() || num == 0 || (num == 1 && rects.front().isEmpty()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
detach();
|
detach();
|
||||||
|
|
||||||
d->qt_rgn->numRects = num;
|
d->qt_rgn->numRects = num;
|
||||||
if (num == 1) {
|
if (num == 1) {
|
||||||
d->qt_rgn->extents = *rects;
|
d->qt_rgn->extents = rects.front();
|
||||||
d->qt_rgn->innerRect = *rects;
|
d->qt_rgn->innerRect = rects.front();
|
||||||
} else {
|
} else {
|
||||||
d->qt_rgn->rects.resize(num);
|
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
|
int QRegion::rectCount() const noexcept
|
||||||
{
|
{
|
||||||
return (d->qt_rgn ? d->qt_rgn->numRects : 0);
|
return (d->qt_rgn ? d->qt_rgn->numRects : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool QRegion::operator==(const QRegion &r) const
|
bool QRegion::operator==(const QRegion &r) const
|
||||||
{
|
{
|
||||||
if (!d->qt_rgn)
|
if (!d->qt_rgn)
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
#include <QtCore/qatomic.h>
|
#include <QtCore/qatomic.h>
|
||||||
#include <QtCore/qrect.h>
|
#include <QtCore/qrect.h>
|
||||||
#include <QtGui/qwindowdefs.h>
|
#include <QtGui/qwindowdefs.h>
|
||||||
#include <QtCore/qcontainerfwd.h>
|
|
||||||
|
|
||||||
#ifndef QT_NO_DATASTREAM
|
#ifndef QT_NO_DATASTREAM
|
||||||
#include <QtCore/qdatastream.h>
|
#include <QtCore/qdatastream.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <QtCore/qspan.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -75,6 +75,8 @@ public:
|
|||||||
|
|
||||||
QRect boundingRect() const noexcept;
|
QRect boundingRect() const noexcept;
|
||||||
void setRects(const QRect *rect, int num);
|
void setRects(const QRect *rect, int num);
|
||||||
|
void setRects(QSpan<const QRect> r);
|
||||||
|
QSpan<const QRect> rects() const noexcept;
|
||||||
int rectCount() const noexcept;
|
int rectCount() const noexcept;
|
||||||
|
|
||||||
QRegion operator|(const QRegion &r) const;
|
QRegion operator|(const QRegion &r) const;
|
||||||
|
@ -138,12 +138,15 @@ void tst_QRegion::rects()
|
|||||||
QRegion region(rect);
|
QRegion region(rect);
|
||||||
QVERIFY(region.isEmpty());
|
QVERIFY(region.isEmpty());
|
||||||
QCOMPARE(region.begin(), region.end());
|
QCOMPARE(region.begin(), region.end());
|
||||||
|
QVERIFY(region.rects().isEmpty());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
QRect rect(10, -20, 30, 40);
|
QRect rect(10, -20, 30, 40);
|
||||||
QRegion region(rect);
|
QRegion region(rect);
|
||||||
QCOMPARE(region.end(), region.begin() + 1);
|
QCOMPARE(region.end(), region.begin() + 1);
|
||||||
QCOMPARE(*region.begin(), rect);
|
QCOMPARE(*region.begin(), rect);
|
||||||
|
QCOMPARE(region.rects().size(), 1);
|
||||||
|
QCOMPARE(region.rects()[0], rect);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
QRect r(QPoint(10, 10), QPoint(40, 40));
|
QRect r(QPoint(10, 10), QPoint(40, 40));
|
||||||
@ -190,6 +193,7 @@ void tst_QRegion::setRects()
|
|||||||
QCOMPARE(region, QRegion());
|
QCOMPARE(region, QRegion());
|
||||||
QCOMPARE(region.begin(), region.end());
|
QCOMPARE(region.begin(), region.end());
|
||||||
QVERIFY(!region.boundingRect().isValid());
|
QVERIFY(!region.boundingRect().isValid());
|
||||||
|
QVERIFY(region.rects().isEmpty());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
QRegion region;
|
QRegion region;
|
||||||
@ -197,12 +201,15 @@ void tst_QRegion::setRects()
|
|||||||
region.setRects(&rect, 1);
|
region.setRects(&rect, 1);
|
||||||
QCOMPARE(region.begin(), region.end());
|
QCOMPARE(region.begin(), region.end());
|
||||||
QVERIFY(!region.boundingRect().isValid());
|
QVERIFY(!region.boundingRect().isValid());
|
||||||
|
QVERIFY(region.rects().isEmpty());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
QRegion region;
|
QRegion region;
|
||||||
QRect rect(10, -20, 30, 40);
|
QRect rect(10, -20, 30, 40);
|
||||||
region.setRects(&rect, 1);
|
region.setRects(&rect, 1);
|
||||||
QCOMPARE(region.end(), region.begin() + 1);
|
QCOMPARE(region.end(), region.begin() + 1);
|
||||||
|
QCOMPARE(region.rects().size(), 1);
|
||||||
|
QCOMPARE(region.rects()[0], rect);
|
||||||
QCOMPARE(*region.begin(), rect);
|
QCOMPARE(*region.begin(), rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,10 +323,12 @@ void tst_QRegion::emptyPolygonRegion()
|
|||||||
QRegion r(pa);
|
QRegion r(pa);
|
||||||
QTEST(r.isEmpty(), "isEmpty");
|
QTEST(r.isEmpty(), "isEmpty");
|
||||||
QTEST(int(std::distance(r.begin(), r.end())), "numRects");
|
QTEST(int(std::distance(r.begin(), r.end())), "numRects");
|
||||||
QList<QRect> rects;
|
QList<QRect> rects{r.begin(), r.end()};
|
||||||
std::copy(r.begin(), r.end(), std::back_inserter(rects));
|
|
||||||
QTEST(int(rects.size()), "numRects");
|
QTEST(int(rects.size()), "numRects");
|
||||||
QTEST(rects, "rects");
|
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, QRegion());
|
||||||
QCOMPARE(region.rectCount(), 0);
|
QCOMPARE(region.rectCount(), 0);
|
||||||
QCOMPARE(region.boundingRect(), QRect());
|
QCOMPARE(region.boundingRect(), QRect());
|
||||||
|
QVERIFY(region.rects().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QRegion::regionFromPath()
|
void tst_QRegion::regionFromPath()
|
||||||
@ -877,6 +887,10 @@ void tst_QRegion::regionFromPath()
|
|||||||
QCOMPARE(rgn.begin()[0], QRect(0, 0, 10, 10));
|
QCOMPARE(rgn.begin()[0], QRect(0, 0, 10, 10));
|
||||||
QCOMPARE(rgn.begin()[1], QRect(0, 100, 100, 1000));
|
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));
|
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()[2], QRect(90, 10, 10, 80));
|
||||||
QCOMPARE(rgn.begin()[3], QRect(0, 90, 100, 10));
|
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));
|
QCOMPARE(rgn.boundingRect(), QRect(0, 0, 100, 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user