From 0c0eadc484ab7143801593ccdbe8e96eeb9f6cf7 Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Fri, 26 Aug 2022 14:51:04 +0200 Subject: [PATCH] a11y: Prevent one case of losing a11y interface when setting event child MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 9a369a25ddfac9352cabde65c8476c7433dc6c3a added a QAccessibleEvent ctor that takes a QAccessibleInterface* instead of a QObject*. Retrieving the QAccessibleInterface* later is done using the interface's unique ID stored in the m_uniqueId member. However, the fact that m_uniqueId is a member of the union alongside with m_child means that setting a child via QAccessibleEvent::setChild also overwrites the stored unique ID, which breaks retrieving the accessible interface later. Fix this for the case where the QAccessibleInterface has an associated QObject by assigning m_object in the ctor as well. This means that a QAccessibleEvent created using either of the two constructors (the one taking the QObject* and the one taking the QAccessibleInterface* associated with the object) now behaves the same. Fixing the case where there is no associated QObject would require further changes (e.g. adding a member for the QAccessibleInterface* or making the m_uniqueId member a separate member instead of having it in a union with m_child). However, I see no way to do so without breaking the ABI, so that is left unchanged. This also adds a corresponding test case. Fixes: QTBUG-105988 Pick-to: 6.4 Change-Id: I71a548af0277a5034e9e207f066fa3e25c5393f3 Reviewed-by: Tor Arne Vestbø --- src/gui/accessible/qaccessible.h | 3 +- .../qaccessibility/tst_qaccessibility.cpp | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 2700b5c0807..b5e155c01e4 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -287,7 +287,7 @@ public: } inline QAccessibleEvent(QAccessibleInterface *iface, QAccessible::Event typ) - : m_type(typ), m_object(nullptr) + : m_type(typ) { Q_ASSERT(iface); Q_ASSERT(m_type != QAccessible::ValueChanged); @@ -299,6 +299,7 @@ public: Q_ASSERT(m_type != QAccessible::TextUpdated); Q_ASSERT(m_type != QAccessible::TableModelChanged); m_uniqueId = QAccessible::uniqueId(iface); + m_object = iface->object(); } virtual ~QAccessibleEvent(); diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index 89ef57e29b3..8479985c0e8 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -163,6 +163,7 @@ public slots: void cleanup(); private slots: void eventTest(); + void eventWithChildTest(); void customWidget(); void deletedWidget(); void subclassedWidget(); @@ -353,6 +354,33 @@ void tst_QAccessibility::eventTest() QTestAccessibility::clearEvents(); } +void tst_QAccessibility::eventWithChildTest() +{ + // make sure that QAccessibleEvent created using either of the two QAccessibleEvent + // behaves the same when the same underlying QObject is used + QWidget widget; + QWidget childWidget(&widget); + + // QAccessibleEvent constructor called with the QObject* + QAccessibleEvent event1(&widget, QAccessible::Focus); + + // QAccessibleEvent constructor called with the QAccessibleInterface* for the same QObject* + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(&widget); + QAccessibleEvent event2(iface, QAccessible::Focus); + + QVERIFY(event1.accessibleInterface() != nullptr); + QVERIFY(event2.accessibleInterface() != nullptr); + QCOMPARE(event1.accessibleInterface(), event2.accessibleInterface()); + + // set same child for both + event1.setChild(0); + event2.setChild(0); + + QVERIFY(event1.accessibleInterface() != nullptr); + QVERIFY(event2.accessibleInterface() != nullptr); + QCOMPARE(event1.accessibleInterface(), event2.accessibleInterface()); +} + void tst_QAccessibility::customWidget() { {