QWidget: clamp own rect in pointInsideRectAndMask

The rect of an empty widget (i.e. 0 width/height) will, after adjusting
by -1, be invalid as it will have a width/height of -1. In turn, calling
contains(p) on that rect can return true even though the rect is empty.

Fixes: QTBUG-131001
Pick-to: 6.8.1
Change-Id: I604f5942589f1c1079cae90bd0d3b104344d2c55
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: David Faure <david.faure@kdab.com>
(cherry picked from commit 1731d8af741a0a6cc6cd293be4aef52103d0899b)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Johannes Grunenberg 2024-11-10 18:09:45 +01:00 committed by Qt Cherry-pick Bot
parent 51b7476893
commit 4a27d0fe0a
2 changed files with 25 additions and 3 deletions

View File

@ -887,9 +887,15 @@ inline void QWidgetPrivate::setSharedPainter(QPainter *painter)
inline bool QWidgetPrivate::pointInsideRectAndMask(const QPointF &p) const
{
Q_Q(const QWidget);
// Use QRectF::contains so that (0, -0.1) isn't in, with p.toPoint() it would be
// The adjusted matches QRect semantics: (160,160) isn't contained in QRect(0, 0, 160, 160)
return QRectF(q->rect().adjusted(0, 0, -1, -1)).contains(p)
// Use QRectF::contains so that (0, -0.1) isn't in, with p.toPoint() it would be in.
// The -1 on right and bottom matches QRect semantics:
// (160,160) isn't contained in QRect(0, 0, 160, 160)
QRect r = q->rect();
r.setRight(qMax(-1, r.right() - 1));
r.setBottom(qMax(-1, r.bottom() - 1));
return r.toRectF().contains(p)
&& (!extra || !extra->hasMask || q->testAttribute(Qt::WA_MouseNoMask)
|| extra->mask.contains(p.toPoint() /* incorrect for the -0.1 case */));
}

View File

@ -11803,11 +11803,27 @@ void tst_QWidget::childAt()
grandChild->setAutoFillBackground(true);
grandChild->setGeometry(-20, -20, 220, 220);
QWidget *emptyChild = new QWidget(child);
emptyChild->setPalette(Qt::green);
emptyChild->setAutoFillBackground(true);
emptyChild->setGeometry(0, 159, 160, 0);
QVERIFY(!parent.childAt(19, 19));
QVERIFY(!parent.childAt(180, 180));
QCOMPARE(parent.childAt(20, 20), grandChild);
QCOMPARE(parent.childAt(179, 179), grandChild);
QCOMPARE(parent.childAt(120, 179), grandChild);
QCOMPARE(parent.childAt(QPointF(120.0, 178.9)), grandChild);
QVERIFY(!parent.childAt(120, 180));
QVERIFY(!parent.childAt(QPointF(120, 179.1)));
emptyChild->setGeometry(100, 0, 0, 160);
QCOMPARE(parent.childAt(120, 120), grandChild);
QCOMPARE(parent.childAt(QPointF(120.5, 120.0)), grandChild);
QCOMPARE(parent.childAt(QPointF(119.5, 120.0)), grandChild);
grandChild->setAttribute(Qt::WA_TransparentForMouseEvents);
QCOMPARE(parent.childAt(20, 20), child);
QCOMPARE(parent.childAt(179, 179), child);