summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Weghorn <[email protected]>2025-09-23 12:48:46 +0200
committerMichael Weghorn <[email protected]>2025-10-30 20:29:00 +0200
commit5aa53df448f78470497e77ab5b8938de56f064cd (patch)
treef3926a884e0f1caa29155e17c4e9e56dd8fa60bc
parent795f1fe3876ed3de1717c9a5c72f823c99189b1b (diff)
a11y: Fix cursor-based text{Before,After}Offset
So far, qt_accTextBeforeOffsetHelper and qt_accTextAfterOffsetHelper (used by QAccessibleTextWidget and QAccessibleQuickItem) were not consistently returning text items of the given boundary type that is completely *before* or *after* the given index, but could e.g. return the word in whose middle the offset is when using QAccessible::WordBoundary. This could for example break an assistive technology feature of navigating through a text by word if it relies on those methods. Adjust the implementations to prevent that from happening, by calling QAccessible::qAccessibleTextBoundaryHelper again with an index moved by one character until either a result before/after the given index is returned or the start/end of the text has been reached. Extend the existing QTextEdit a11y test by a few cases that would previously fail. (Note: Depending on the text granularity used, not every character in the text is necessarily considered part of any text item: E.g., when using QAccessible::WordBoundary, space characters in between words are not, at least not for the QTextCursor logic as used in QTextEdit or qtdeclarative's QQuickTextEdit). Fixes: QTBUG-140504 Task-number: QTBUG-139943 Change-Id: Ie6f0f2b2579237f42964d2498c818d1f02bf4bb8 Reviewed-by: Morten Johan Sørvig <[email protected]>
-rw-r--r--src/gui/accessible/qaccessiblehelper.cpp22
-rw-r--r--tests/auto/other/qaccessibility/tst_qaccessibility.cpp14
2 files changed, 32 insertions, 4 deletions
diff --git a/src/gui/accessible/qaccessiblehelper.cpp b/src/gui/accessible/qaccessiblehelper.cpp
index 40421ef329a..9ea72b1f6c9 100644
--- a/src/gui/accessible/qaccessiblehelper.cpp
+++ b/src/gui/accessible/qaccessiblehelper.cpp
@@ -57,13 +57,20 @@ QString qt_accTextBeforeOffsetHelper(const QAccessibleTextInterface &textInterfa
{
Q_ASSERT(startOffset);
Q_ASSERT(endOffset);
+ *startOffset = *endOffset = -1;
QTextCursor cursor = textCursor;
cursor.setPosition(offset);
std::pair<int, int> boundaries =
QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
- cursor.setPosition(boundaries.first - 1);
- boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
+ if (boundaries.second > offset) {
+ cursor.setPosition(boundaries.first);
+ while (boundaries.second > offset) {
+ if (!cursor.movePosition(QTextCursor::PreviousCharacter))
+ return QString();
+ boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
+ }
+ }
*startOffset = boundaries.first;
*endOffset = boundaries.second;
@@ -78,13 +85,20 @@ QString qt_accTextAfterOffsetHelper(const QAccessibleTextInterface &textInterfac
{
Q_ASSERT(startOffset);
Q_ASSERT(endOffset);
+ *startOffset = *endOffset = -1;
QTextCursor cursor = textCursor;
cursor.setPosition(offset);
std::pair<int, int> boundaries =
QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
- cursor.setPosition(boundaries.second);
- boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
+ if (boundaries.first <= offset) {
+ cursor.setPosition(boundaries.second);
+ while (boundaries.first <= offset) {
+ if (!cursor.movePosition(QTextCursor::NextCharacter))
+ return QString();
+ boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
+ }
+ }
*startOffset = boundaries.first;
*endOffset = boundaries.second;
diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
index 9a42c827504..2e92cdffada 100644
--- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
+++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
@@ -1904,6 +1904,20 @@ void tst_QAccessibility::textEditTest()
QCOMPARE(textIface->textAtOffset(15, QAccessible::LineBoundary, &startOffset, &endOffset), QString("How are you today?"));
QCOMPARE(startOffset, 13);
QCOMPARE(endOffset, 31);
+
+ QCOMPARE(textIface->textAfterOffset(3, QAccessible::WordBoundary, &startOffset, &endOffset),
+ QString("world"));
+ QCOMPARE(
+ textIface->textBeforeOffset(8, QAccessible::WordBoundary, &startOffset, &endOffset),
+ QString("hello"));
+ // no more word before or after the last one
+ QCOMPARE(
+ textIface->textBeforeOffset(1, QAccessible::WordBoundary, &startOffset, &endOffset),
+ QString());
+ QCOMPARE(textIface->textAfterOffset(textIface->characterCount() - 1,
+ QAccessible::WordBoundary, &startOffset, &endOffset),
+ QString());
+
QCOMPARE(textIface->characterCount(), 48);
QFontMetrics fm(edit.document()->defaultFont());
QCOMPARE(textIface->characterRect(0).size(), QSize(fm.horizontalAdvance("h"), fm.height()));