QQuickDeliveryAgentPrivate: fix performance regression in eventTargets()

a89a34463b introduced a predicate
parameter to eventTargets. The problem is that it is passed by
std::function copy. Since eventTargets is called recursively it can
easily, in a heavy scene, lead to hundreds of allocation + deallocations
for each single event handling.

Pass the predicate as a (qxp::)function_ref to fix this.

Since function_ref has reference semantics, we cannot inititalize it
with nullptr anymore. So define a noop predicate for the
contextMenuTargets() case.

Pick-to: 6.9
Change-Id: I6a3162b9b76b197bba07c1725ac7768c8883818b
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Aurélien Brooke 2025-03-10 20:49:09 +01:00
parent e5d916b00c
commit a62ef0f62e
2 changed files with 11 additions and 10 deletions

View File

@ -2077,7 +2077,7 @@ void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
*/
// FIXME: should this be iterative instead of recursive?
QVector<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item, const QEvent *event, QPointF scenePos,
std::function<std::optional<bool>(QQuickItem *item, const QEvent *event)> predicate) const
qxp::function_ref<std::optional<bool> (QQuickItem *, const QEvent *)> predicate) const
{
QVector<QQuickItem *> targets;
auto itemPrivate = QQuickItemPrivate::get(item);
@ -2089,13 +2089,9 @@ QVector<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item,
return targets;
}
QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
if (predicate) {
const auto override = predicate(item, event);
if (override == true)
relevant = true;
else if (override == false)
relevant = false;
}
const std::optional<bool> override = predicate(item, event);
if (override.has_value())
relevant = override.value();
if (relevant) {
auto it = std::lower_bound(children.begin(), children.end(), 0,
[](auto lhs, auto rhs) -> bool { return lhs->z() < rhs; });
@ -2940,7 +2936,11 @@ bool QQuickDeliveryAgentPrivate::dragOverThreshold(QVector2D delta)
*/
QVector<QQuickItem *> QQuickDeliveryAgentPrivate::contextMenuTargets(QQuickItem *item, const QContextMenuEvent *event) const
{
return eventTargets(item, event, event->pos(), nullptr);
auto predicate = [](QQuickItem *, const QEvent *) -> std::optional<bool> {
return std::nullopt;
};
return eventTargets(item, event, event->pos(), predicate);
}
/*!

View File

@ -18,6 +18,7 @@
#include <QtQuick/private/qquickdeliveryagent_p.h>
#include <QtGui/qevent.h>
#include <QtCore/qstack.h>
#include <QtCore/qxpfunctional.h>
#include <private/qevent_p.h>
#include <private/qpointingdevice_p.h>
@ -166,7 +167,7 @@ public:
void deliverUpdatedPoints(QPointerEvent *event);
void deliverMatchingPointsToItem(QQuickItem *item, bool isGrabber, QPointerEvent *pointerEvent, bool handlersOnly = false);
QVector<QQuickItem *> eventTargets(QQuickItem *, const QEvent *event, QPointF scenePos, std::function<std::optional<bool> (QQuickItem *, const QEvent *)> predicate) const;
QVector<QQuickItem *> eventTargets(QQuickItem *, const QEvent *event, QPointF scenePos, qxp::function_ref<std::optional<bool> (QQuickItem *, const QEvent *)> predicate) const;
QVector<QQuickItem *> pointerTargets(QQuickItem *, const QPointerEvent *event, const QEventPoint &point,
bool checkMouseButtons, bool checkAcceptsTouch) const;
QVector<QQuickItem *> mergePointerTargets(const QVector<QQuickItem *> &list1, const QVector<QQuickItem *> &list2) const;