From 9ab11c726e313c5de1bd1a9b9528e67b18e175ba Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Thu, 18 Aug 2022 15:21:38 +0200 Subject: [PATCH] a11y atspi: Support text interface's GetStringAtOffset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GetStringAtOffset method was added to the AT-SPI Text interface in at-spi2-core commmit [1]: commit 56220f05bc8b7683911658e1a8aff4a1ab3cab8d Author: Mike Gorse Date: Mon Aug 19 16:43:02 2013 -0500 Add atspi_text_get_string_at_offset As compared to GetTextAtOffset, which is very similar and already supported in Qt's AT-SPI adapter, the new method uses a new enum, AtspiTextGranularity, to specify the region of text that should be returned. Other than AtspiTextBoundaryType (that is used by GetTextAtOffset), AtspiTextGranularity now also has a value for the paragraph granularity (ATSPI_TEXT_GRANULARITY_PARAGRAPH). While AtspiTextBoundaryType has two enum values for the word/sentence/line boundaries (ATSPI_TEXT_BOUNDARY_WORD_START and ATSPI_TEXT_BOUNDARY_WORD_END, etc.), AtspiTextGranularity doesn't have this any more, but ATSPI_TEXT_GRANULARITY_WORD etc. seem to correspond to what the variants ending on "_START" do when used with GetTextAtOffset, since the documentation says that the range is "defined by the boundaries of a word starting at the beginning of the current word and finishing at the beginning of the following one, if present." (and likewise for ATSPI_TEXT_GRANULARITY_SENTENCE, ATSPI_TEXT_GRANULARITY_LINE, ATSPI_TEXT_GRANULARITY_PARAGRAPH). In order to support GetStringAtOffset, this adds a new mapping from the AtspiTextGranularity enum values to the corresponding QAccessible::TextBoundaryType, similar to what's done for the AtspiTextBoundaryType in the handling of the GetTextAtOffset method. The existing AtSpiAdaptor::qAccessibleBoundaryType method is renamed to AtSpiAdaptor::qAccessibleBoundaryTypeFromAtspiBoundaryType to clearer distinguish it from the newly introduced AtSpiAdaptor::qAccessibleBoundaryTypeFromAtspiTextGranularity. No similar new alternatives have been added to AT-SPI for GetTextBeforeOffset and GetTextAfterOffset. [1] https://gitlab.gnome.org/GNOME/at-spi2-core/-/commit/56220f05bc8b7683911658e1a8aff4a1ab3cab8d Fixes: QTBUG-105811 Change-Id: I674a760e80c349baea89dcb4ac7aecdef9b2b45f Reviewed-by: Tor Arne Vestbø --- src/gui/accessible/linux/atspiadaptor.cpp | 57 +++++++++++++++++++++-- src/gui/accessible/linux/atspiadaptor_p.h | 4 +- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/gui/accessible/linux/atspiadaptor.cpp b/src/gui/accessible/linux/atspiadaptor.cpp index 2ff64fd1b76..b965d9270a3 100644 --- a/src/gui/accessible/linux/atspiadaptor.cpp +++ b/src/gui/accessible/linux/atspiadaptor.cpp @@ -438,6 +438,13 @@ QString AtSpiAdaptor::introspect(const QString &path) const " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" " \n" " \n" " \n" @@ -1836,6 +1843,16 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString QVariantList sel; sel << start << end; connection.send(message.createReply(sel)); + } else if (function == "GetStringAtOffset"_L1) { + int offset = message.arguments().at(0).toInt(); + uint granularity = message.arguments().at(1).toUInt(); + if (!isValidAtspiTextGranularity(granularity)) + return false; + int startOffset, endOffset; + QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryTypeFromAtspiTextGranularity(granularity), &startOffset, &endOffset); + QVariantList ret; + ret << text << startOffset << endOffset; + connection.send(message.createReply(ret)); } else if (function == "GetText"_L1) { int startOffset = message.arguments().at(0).toInt(); int endOffset = message.arguments().at(1).toInt(); @@ -1846,7 +1863,7 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString int offset = message.arguments().at(0).toInt(); int type = message.arguments().at(1).toUInt(); int startOffset, endOffset; - QString text = interface->textInterface()->textAfterOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset); + QString text = interface->textInterface()->textAfterOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset); QVariantList ret; ret << text << startOffset << endOffset; connection.send(message.createReply(ret)); @@ -1854,7 +1871,7 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString int offset = message.arguments().at(0).toInt(); int type = message.arguments().at(1).toUInt(); int startOffset, endOffset; - QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset); + QString text = interface->textInterface()->textAtOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset); QVariantList ret; ret << text << startOffset << endOffset; connection.send(message.createReply(ret)); @@ -1862,7 +1879,7 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString int offset = message.arguments().at(0).toInt(); int type = message.arguments().at(1).toUInt(); int startOffset, endOffset; - QString text = interface->textInterface()->textBeforeOffset(offset, qAccessibleBoundaryType(type), &startOffset, &endOffset); + QString text = interface->textInterface()->textBeforeOffset(offset, qAccessibleBoundaryTypeFromAtspiBoundaryType(type), &startOffset, &endOffset); QVariantList ret; ret << text << startOffset << endOffset; connection.send(message.createReply(ret)); @@ -1894,7 +1911,7 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString return true; } -QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryType(int atspiTextBoundaryType) const +QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryTypeFromAtspiBoundaryType(int atspiTextBoundaryType) { switch (atspiTextBoundaryType) { case ATSPI_TEXT_BOUNDARY_CHAR: @@ -1913,6 +1930,38 @@ QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryType(int atspiTex return QAccessible::CharBoundary; } +bool AtSpiAdaptor::isValidAtspiTextGranularity(uint atspiTextGranularity) +{ + if (atspiTextGranularity == ATSPI_TEXT_GRANULARITY_CHAR + || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_WORD + || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_SENTENCE + || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_LINE + || atspiTextGranularity == ATSPI_TEXT_GRANULARITY_PARAGRAPH) + return true; + + qCWarning(lcAccessibilityAtspi) << "Unknown value" << atspiTextGranularity << "for AT-SPI text granularity type"; + return false; +} + +QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryTypeFromAtspiTextGranularity(uint atspiTextGranularity) +{ + Q_ASSERT(isValidAtspiTextGranularity(atspiTextGranularity)); + + switch (atspiTextGranularity) { + case ATSPI_TEXT_GRANULARITY_CHAR: + return QAccessible::CharBoundary; + case ATSPI_TEXT_GRANULARITY_WORD: + return QAccessible::WordBoundary; + case ATSPI_TEXT_GRANULARITY_SENTENCE: + return QAccessible::SentenceBoundary; + case ATSPI_TEXT_GRANULARITY_LINE: + return QAccessible::LineBoundary; + case ATSPI_TEXT_GRANULARITY_PARAGRAPH: + return QAccessible::ParagraphBoundary; + } + return QAccessible::CharBoundary; +} + namespace { struct AtSpiAttribute { diff --git a/src/gui/accessible/linux/atspiadaptor_p.h b/src/gui/accessible/linux/atspiadaptor_p.h index ccb392a27da..2e3b7a67c49 100644 --- a/src/gui/accessible/linux/atspiadaptor_p.h +++ b/src/gui/accessible/linux/atspiadaptor_p.h @@ -106,7 +106,9 @@ private: QString getAttributeValue(QAccessibleInterface *, int offset, const QString &attributeName) const; QList getCharacterExtents(QAccessibleInterface *, int offset, uint coordType) const; QList getRangeExtents(QAccessibleInterface *, int startOffset, int endOffset, uint coordType) const; - QAccessible::TextBoundaryType qAccessibleBoundaryType(int atspiTextBoundaryType) const; + static QAccessible::TextBoundaryType qAccessibleBoundaryTypeFromAtspiBoundaryType(int atspiTextBoundaryType); + static bool isValidAtspiTextGranularity(uint coordType); + static QAccessible::TextBoundaryType qAccessibleBoundaryTypeFromAtspiTextGranularity(uint atspiTextGranularity); static bool inheritsQAction(QObject *object); // private vars