From a32a3aa388534f67da02fd7f15a59648637bd753 Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Wed, 3 Aug 2022 07:42:10 +0200 Subject: a11y atspi: Add support for ATSPI_COORD_TYPE_PARENT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far, only screen coordinates (`ATSPI_COORD_TYPE_SCREEN`) and coordinates relative to the widget's top-level window (`ATSPI_COORD_TYPE_WINDOW`) were supported. In at-spi 2.30, a third coordinate type, describing coordinates relative to the widget's immediate parent, was added: `ATSPI_COORD_TYPE_PARENT` (commit: [1]) This commit adds the handling to convert to and from that coord type as well and unifies the existing handling to convert to/from screen coordinates by introducing two static helper methods (`AtSpiAdaptor::translateToScreenCoordinates` and `AtSpiAdaptor::translateFromScreenCoordinates`) and making use of those wherever conversion needs to be done. In addition, also add a check to only handle requests using a coordinate type that is one of those that is actually supported instead of returning incorrect values (for the case that new coord types should be introduced in AT-SPI in the future). [1] https://gitlab.gnome.org/GNOME/at-spi2-core/-/commit/737c9853b681fb20fda79b32ed92cda96b381dd0 Fixes: QTBUG-105313 Change-Id: Ia8752bd6a35328cc2de33ecad08f2964735f41ae Reviewed-by: Tor Arne Vestbø --- src/gui/accessible/linux/atspiadaptor.cpp | 118 ++++++++++++++++-------------- src/gui/accessible/linux/atspiadaptor_p.h | 4 +- 2 files changed, 66 insertions(+), 56 deletions(-) (limited to 'src/gui/accessible') diff --git a/src/gui/accessible/linux/atspiadaptor.cpp b/src/gui/accessible/linux/atspiadaptor.cpp index 0c27422364..4837b6e65f 100644 --- a/src/gui/accessible/linux/atspiadaptor.cpp +++ b/src/gui/accessible/linux/atspiadaptor.cpp @@ -28,6 +28,11 @@ It sends notifications coming from Qt via dbus and listens to incoming dbus requests. */ +// ATSPI_COORD_TYPE_PARENT was added in at-spi 2.30, define here for older versions +#if ATSPI_COORD_TYPE_COUNT < 3 +#define ATSPI_COORD_TYPE_PARENT 2 +#endif + QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -1534,23 +1539,6 @@ static QAccessibleInterface * getWindow(QAccessibleInterface * interface) return parent; } -static QRect getRelativeRect(QAccessibleInterface *interface) -{ - QAccessibleInterface * window; - QRect wr, cr; - - cr = interface->rect(); - - window = getWindow(interface); - if (window) { - wr = window->rect(); - - cr.setX(cr.x() - wr.x()); - cr.setY(cr.y() - wr.y()); - } - return cr; -} - bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection) { if (function == "Contains"_L1) { @@ -1558,28 +1546,22 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt int x = message.arguments().at(0).toInt(); int y = message.arguments().at(1).toInt(); uint coordType = message.arguments().at(2).toUInt(); - if (coordType == ATSPI_COORD_TYPE_SCREEN) - ret = interface->rect().contains(x, y); - else - ret = getRelativeRect(interface).contains(x, y); + if (!isValidCoordType(coordType)) + return false; + ret = getExtents(interface, coordType).contains(x, y); sendReply(connection, message, ret); } else if (function == "GetAccessibleAtPoint"_L1) { - int x = message.arguments().at(0).toInt(); - int y = message.arguments().at(1).toInt(); + QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt()); uint coordType = message.arguments().at(2).toUInt(); - if (coordType == ATSPI_COORD_TYPE_WINDOW) { - QWindow * window = interface->window(); - if (window) { - x += window->position().x(); - y += window->position().y(); - } - } + if (!isValidCoordType(coordType)) + return false; + QPoint screenPos = translateToScreenCoordinates(interface, point, coordType); - QAccessibleInterface * childInterface(interface->childAt(x, y)); + QAccessibleInterface * childInterface(interface->childAt(screenPos.x(), screenPos.y())); QAccessibleInterface * iface = nullptr; while (childInterface) { iface = childInterface; - childInterface = iface->childAt(x, y); + childInterface = iface->childAt(screenPos.x(), screenPos.y()); } if (iface) { QString path = pathForInterface(iface); @@ -1593,6 +1575,8 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt sendReply(connection, message, (double) 1.0); } else if (function == "GetExtents"_L1) { uint coordType = message.arguments().at(0).toUInt(); + if (!isValidCoordType(coordType)) + return false; sendReply(connection, message, QVariant::fromValue(getExtents(interface, coordType))); } else if (function == "GetLayer"_L1) { sendReply(connection, message, QVariant::fromValue((uint)1)); @@ -1600,11 +1584,9 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt sendReply(connection, message, QVariant::fromValue((short)0)); } else if (function == "GetPosition"_L1) { uint coordType = message.arguments().at(0).toUInt(); - QRect rect; - if (coordType == ATSPI_COORD_TYPE_SCREEN) - rect = interface->rect(); - else - rect = getRelativeRect(interface); + if (!isValidCoordType(coordType)) + return false; + QRect rect = getExtents(interface, coordType); QVariantList pos; pos << rect.x() << rect.y(); connection.send(message.createReply(pos)); @@ -1649,7 +1631,7 @@ bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QSt QRect AtSpiAdaptor::getExtents(QAccessibleInterface *interface, uint coordType) { - return (coordType == ATSPI_COORD_TYPE_SCREEN) ? interface->rect() : getRelativeRect(interface); + return translateFromScreenCoordinates(interface, interface->rect(), coordType); } // Action interface @@ -1802,11 +1784,10 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString Q_ASSERT(!message.signature().isEmpty()); QPoint point(message.arguments().at(0).toInt(), message.arguments().at(1).toInt()); uint coordType = message.arguments().at(2).toUInt(); - if (coordType == ATSPI_COORD_TYPE_WINDOW) { - QWindow *win = interface->window(); - point += QPoint(win->x(), win->y()); - } - int offset = interface->textInterface()->offsetAtPoint(point); + if (!isValidCoordType(coordType)) + return false; + QPoint screenPos = translateToScreenCoordinates(interface, point, coordType); + int offset = interface->textInterface()->offsetAtPoint(screenPos); sendReply(connection, message, offset); } else if (function == "GetRangeExtents"_L1) { int startOffset = message.arguments().at(0).toInt(); @@ -2053,10 +2034,7 @@ QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, in QList AtSpiAdaptor::getCharacterExtents(QAccessibleInterface *interface, int offset, uint coordType) const { QRect rect = interface->textInterface()->characterRect(offset); - - if (coordType == ATSPI_COORD_TYPE_WINDOW) - rect = translateRectToWindowCoordinates(interface, rect); - + rect = translateFromScreenCoordinates(interface, rect, coordType); return QList() << rect.x() << rect.y() << rect.width() << rect.height(); } @@ -2074,22 +2052,52 @@ QList AtSpiAdaptor::getRangeExtents(QAccessibleInterface *interface, for (int i=startOffset + 1; i <= endOffset; i++) rect = rect | textInterface->characterRect(i); - // relative to window - if (coordType == ATSPI_COORD_TYPE_WINDOW) - rect = translateRectToWindowCoordinates(interface, rect); - + rect = translateFromScreenCoordinates(interface, rect, coordType); return QList() << rect.x() << rect.y() << rect.width() << rect.height(); } -QRect AtSpiAdaptor::translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect) +bool AtSpiAdaptor::isValidCoordType(uint coordType) { - QAccessibleInterface * window = getWindow(interface); - if (window) - return rect.translated(-window->rect().x(), -window->rect().y()); + if (coordType == ATSPI_COORD_TYPE_SCREEN || coordType == ATSPI_COORD_TYPE_WINDOW || coordType == ATSPI_COORD_TYPE_PARENT) + return true; + + qCWarning(lcAccessibilityAtspi) << "unknown value" << coordType << "for AT-SPI coord type"; + return false; +} + +QRect AtSpiAdaptor::translateFromScreenCoordinates(QAccessibleInterface *interface, const QRect &screenRect, uint targetCoordType) +{ + Q_ASSERT(isValidCoordType(targetCoordType)); + + QAccessibleInterface *upper = nullptr; + if (targetCoordType == ATSPI_COORD_TYPE_WINDOW) + upper = getWindow(interface); + else if (targetCoordType == ATSPI_COORD_TYPE_PARENT) + upper = interface->parent(); + + QRect rect = screenRect; + if (upper) + rect.translate(-upper->rect().x(), -upper->rect().y()); return rect; } +QPoint AtSpiAdaptor::translateToScreenCoordinates(QAccessibleInterface *interface, const QPoint &pos, uint fromCoordType) +{ + Q_ASSERT(isValidCoordType(fromCoordType)); + + QAccessibleInterface *upper = nullptr; + if (fromCoordType == ATSPI_COORD_TYPE_WINDOW) + upper = getWindow(interface); + else if (fromCoordType == ATSPI_COORD_TYPE_PARENT) + upper = interface->parent(); + + QPoint screenPos = pos; + if (upper) + screenPos += upper->rect().topLeft(); + + return screenPos; +} // Editable Text interface static QString textForRange(QAccessibleInterface *accessible, int startOffset, int endOffset) diff --git a/src/gui/accessible/linux/atspiadaptor_p.h b/src/gui/accessible/linux/atspiadaptor_p.h index 3d785e4c25..a5fbf2e23d 100644 --- a/src/gui/accessible/linux/atspiadaptor_p.h +++ b/src/gui/accessible/linux/atspiadaptor_p.h @@ -94,7 +94,9 @@ private: // component helper functions static QRect getExtents(QAccessibleInterface *interface, uint coordType); - static QRect translateRectToWindowCoordinates(QAccessibleInterface *interface, const QRect &rect); + static bool isValidCoordType(uint coordType); + static QRect translateFromScreenCoordinates(QAccessibleInterface *interface, const QRect &rect, uint targetCoordType); + static QPoint translateToScreenCoordinates(QAccessibleInterface *interface, const QPoint &pos, uint fromCoordType); // action helper functions QSpiActionArray getActions(QAccessibleInterface *interface) const; -- cgit v1.2.3