Windows QPA: Fix crash in UI Automation with Youdao Dictionary
Unlike other accessibility classes, QAccessibleTree is returning a different instance, with a different ID, every time child()/childAt() are called for the same child elements. This causes ElementProviderFromPoint to return different IRawElementProviderSimple instances every time, for the same coordinates, which causes the NetEase Youdao Dictionary to call it in an infinite loop, allocating new QAccessibleTableCell instances, until the application crashes. The crash happened, for instance, just by using the mouse over Qt Creator's project tree while Youdao Dictionary was running. While the root cause seems to be QAccessibleTree not caching and reusing objects, this change adds a layer of safety to the UI Automation classes in the Windows QPA, to avoid causing a crash until QAccessibleTree, and possibly other accessibility classes, are fixed. Fixes: QTBUG-77974 Change-Id: I9b0c8174bc0fd9ef7f5626ee0b72c8a9626520ee Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
parent
364b9c80de
commit
1c55a6caf1
@ -670,18 +670,26 @@ HRESULT QWindowsUiaMainProvider::ElementProviderFromPoint(double x, double y, IR
|
|||||||
QPoint point;
|
QPoint point;
|
||||||
nativeUiaPointToPoint(uiaPoint, window, &point);
|
nativeUiaPointToPoint(uiaPoint, window, &point);
|
||||||
|
|
||||||
QAccessibleInterface *targetacc = accessible->childAt(point.x(), point.y());
|
if (auto targetacc = accessible->childAt(point.x(), point.y())) {
|
||||||
|
auto acc = accessible->childAt(point.x(), point.y());
|
||||||
if (targetacc) {
|
// Reject the cases where childAt() returns a different instance in each call for the same
|
||||||
QAccessibleInterface *acc = targetacc;
|
// element (e.g., QAccessibleTree), as it causes an endless loop with Youdao Dictionary installed.
|
||||||
// Controls can be embedded within grouping elements. By default returns the innermost control.
|
if (targetacc == acc) {
|
||||||
while (acc) {
|
// Controls can be embedded within grouping elements. By default returns the innermost control.
|
||||||
targetacc = acc;
|
while (acc) {
|
||||||
// For accessibility tools it may be better to return the text element instead of its subcomponents.
|
targetacc = acc;
|
||||||
if (targetacc->textInterface()) break;
|
// For accessibility tools it may be better to return the text element instead of its subcomponents.
|
||||||
acc = acc->childAt(point.x(), point.y());
|
if (targetacc->textInterface()) break;
|
||||||
|
acc = targetacc->childAt(point.x(), point.y());
|
||||||
|
if (acc != targetacc->childAt(point.x(), point.y())) {
|
||||||
|
qCDebug(lcQpaUiAutomation) << "Non-unique childAt() for" << targetacc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pRetVal = providerForAccessible(targetacc);
|
||||||
|
} else {
|
||||||
|
qCDebug(lcQpaUiAutomation) << "Non-unique childAt() for" << accessible;
|
||||||
}
|
}
|
||||||
*pRetVal = providerForAccessible(targetacc);
|
|
||||||
}
|
}
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user