Title: [285339] trunk
Revision
285339
Author
[email protected]
Date
2021-11-05 01:22:39 -0700 (Fri, 05 Nov 2021)

Log Message

[GTK][a11y] Embedded objects are not correctly handled by text interface with ATSPI
https://bugs.webkit.org/show_bug.cgi?id=232622

Reviewed by Andres Gonzalez.

Source/WebCore:

Make sure text iterator is emitting object replacement characters when converting offsets to/from visible positions.

* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::visiblePositionForIndex const):
(WebCore::AccessibilityRenderObject::indexForVisiblePosition const):
* accessibility/atspi/AccessibilityObjectTextAtspi.cpp:
(WebCore::AccessibilityObjectAtspi::boundsForSelection const):
* editing/Editing.cpp:
(WebCore::indexForVisiblePosition):
(WebCore::visiblePositionForIndex):
* editing/Editing.h:

Tools:

Add a test case to check handling of embedded objects by text interface.

* TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:
(testTextReplacedObjects):
(beforeAll):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (285338 => 285339)


--- trunk/Source/WebCore/ChangeLog	2021-11-05 08:21:13 UTC (rev 285338)
+++ trunk/Source/WebCore/ChangeLog	2021-11-05 08:22:39 UTC (rev 285339)
@@ -1,5 +1,24 @@
 2021-11-05  Carlos Garcia Campos  <[email protected]>
 
+        [GTK][a11y] Embedded objects are not correctly handled by text interface with ATSPI
+        https://bugs.webkit.org/show_bug.cgi?id=232622
+
+        Reviewed by Andres Gonzalez.
+
+        Make sure text iterator is emitting object replacement characters when converting offsets to/from visible positions.
+
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::visiblePositionForIndex const):
+        (WebCore::AccessibilityRenderObject::indexForVisiblePosition const):
+        * accessibility/atspi/AccessibilityObjectTextAtspi.cpp:
+        (WebCore::AccessibilityObjectAtspi::boundsForSelection const):
+        * editing/Editing.cpp:
+        (WebCore::indexForVisiblePosition):
+        (WebCore::visiblePositionForIndex):
+        * editing/Editing.h:
+
+2021-11-05  Carlos Garcia Campos  <[email protected]>
+
         Unreviewed. [GTK][WPE] Fix compile warning after r284675
 
         * accessibility/AXObjectCache.cpp:

Modified: trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp (285338 => 285339)


--- trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp	2021-11-05 08:21:13 UTC (rev 285338)
+++ trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp	2021-11-05 08:22:39 UTC (rev 285339)
@@ -2145,7 +2145,12 @@
     if (!node)
         return VisiblePosition();
 
+#if USE(ATSPI)
+    // We need to consider replaced elements for GTK, as they will be presented with the 'object replacement character' (0xFFFC).
+    return WebCore::visiblePositionForIndex(index, node, TextIteratorBehavior::EmitsObjectReplacementCharacters);
+#else
     return visiblePositionForIndexUsingCharacterIterator(*node, index);
+#endif
 }
     
 int AccessibilityRenderObject::indexForVisiblePosition(const VisiblePosition& position) const
@@ -2163,15 +2168,16 @@
     if (!node)
         return 0;
 
-#if USE(ATK) || USE(ATSPI)
     // We need to consider replaced elements for GTK, as they will be
     // presented with the 'object replacement character' (0xFFFC).
-    bool forSelectionPreservation = true;
-#else
-    bool forSelectionPreservation = false;
+    TextIteratorBehaviors behaviors;
+#if USE(ATSPI)
+    behaviors.add(TextIteratorBehavior::EmitsObjectReplacementCharacters);
+#elif USE(ATK)
+    behaviors.add(TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions);
 #endif
 
-    return WebCore::indexForVisiblePosition(*node, position, forSelectionPreservation);
+    return WebCore::indexForVisiblePosition(*node, position, behaviors);
 }
 
 Element* AccessibilityRenderObject::rootEditableElementForPosition(const Position& position) const

Modified: trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp (285338 => 285339)


--- trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp	2021-11-05 08:21:13 UTC (rev 285338)
+++ trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp	2021-11-05 08:22:39 UTC (rev 285339)
@@ -610,9 +610,9 @@
     auto rangeInParent = *makeSimpleRange(parentFirstPosition, nodeRangeStart);
 
     // Set values for start offsets and calculate initial range length.
-    int startOffset = characterCount(rangeInParent, TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions);
+    int startOffset = characterCount(rangeInParent, TextIteratorBehavior::EmitsObjectReplacementCharacters);
     auto nodeRange = *makeSimpleRange(nodeRangeStart, nodeRangeEnd);
-    int rangeLength = characterCount(nodeRange, TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions);
+    int rangeLength = characterCount(nodeRange, TextIteratorBehavior::EmitsObjectReplacementCharacters);
     return { startOffset, startOffset + rangeLength };
 }
 

Modified: trunk/Source/WebCore/editing/Editing.cpp (285338 => 285339)


--- trunk/Source/WebCore/editing/Editing.cpp	2021-11-05 08:21:13 UTC (rev 285338)
+++ trunk/Source/WebCore/editing/Editing.cpp	2021-11-05 08:22:39 UTC (rev 285339)
@@ -994,15 +994,12 @@
 }
 
 // FIXME: Merge this function with the one above.
-int indexForVisiblePosition(Node& node, const VisiblePosition& visiblePosition, bool forSelectionPreservation)
+int indexForVisiblePosition(Node& node, const VisiblePosition& visiblePosition, TextIteratorBehaviors behaviors)
 {
     if (visiblePosition.isNull())
         return 0;
 
     auto range = makeSimpleRange(makeBoundaryPointBeforeNodeContents(node), visiblePosition);
-    TextIteratorBehaviors behaviors;
-    if (forSelectionPreservation)
-        behaviors.add(TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions);
     return range ? characterCount(*range, behaviors) : 0;
 }
 
@@ -1016,11 +1013,11 @@
     return visiblePositionForIndex(startIndex + offset, root.get());
 }
 
-VisiblePosition visiblePositionForIndex(int index, ContainerNode* scope)
+VisiblePosition visiblePositionForIndex(int index, Node* scope, TextIteratorBehaviors behaviors)
 {
     if (!scope)
         return { };
-    return { makeDeprecatedLegacyPosition(resolveCharacterLocation(makeRangeSelectingNodeContents(*scope), index, TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions)) };
+    return { makeDeprecatedLegacyPosition(resolveCharacterLocation(makeRangeSelectingNodeContents(*scope), index, behaviors)) };
 }
 
 VisiblePosition visiblePositionForIndexUsingCharacterIterator(Node& node, int index)

Modified: trunk/Source/WebCore/editing/Editing.h (285338 => 285339)


--- trunk/Source/WebCore/editing/Editing.h	2021-11-05 08:21:13 UTC (rev 285338)
+++ trunk/Source/WebCore/editing/Editing.h	2021-11-05 08:22:39 UTC (rev 285339)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "Position.h"
+#include "TextIteratorBehavior.h"
 #include <wtf/Forward.h>
 #include <wtf/HashSet.h>
 #include <wtf/unicode/CharacterNames.h>
@@ -144,9 +145,9 @@
 bool lineBreakExistsAtVisiblePosition(const VisiblePosition&);
 
 WEBCORE_EXPORT int indexForVisiblePosition(const VisiblePosition&, RefPtr<ContainerNode>& scope);
-int indexForVisiblePosition(Node&, const VisiblePosition&, bool forSelectionPreservation);
+int indexForVisiblePosition(Node&, const VisiblePosition&, TextIteratorBehaviors);
 WEBCORE_EXPORT VisiblePosition visiblePositionForPositionWithOffset(const VisiblePosition&, int offset);
-WEBCORE_EXPORT VisiblePosition visiblePositionForIndex(int index, ContainerNode* scope);
+WEBCORE_EXPORT VisiblePosition visiblePositionForIndex(int index, Node* scope, TextIteratorBehaviors = TextIteratorBehavior::EmitsCharactersBetweenAllVisiblePositions);
 VisiblePosition visiblePositionForIndexUsingCharacterIterator(Node&, int index); // FIXME: Why do we need this version?
 
 WEBCORE_EXPORT VisiblePosition closestEditablePositionInElementForAbsolutePoint(const Element&, const IntPoint&);

Modified: trunk/Tools/ChangeLog (285338 => 285339)


--- trunk/Tools/ChangeLog	2021-11-05 08:21:13 UTC (rev 285338)
+++ trunk/Tools/ChangeLog	2021-11-05 08:22:39 UTC (rev 285339)
@@ -1,3 +1,16 @@
+2021-11-05  Carlos Garcia Campos  <[email protected]>
+
+        [GTK][a11y] Embedded objects are not correctly handled by text interface with ATSPI
+        https://bugs.webkit.org/show_bug.cgi?id=232622
+
+        Reviewed by Andres Gonzalez.
+
+        Add a test case to check handling of embedded objects by text interface.
+
+        * TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp:
+        (testTextReplacedObjects):
+        (beforeAll):
+
 2021-11-03  Jonathan Bedard  <[email protected]>
 
         [git-webkit] Add land command

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp (285338 => 285339)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp	2021-11-05 08:21:13 UTC (rev 285338)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp	2021-11-05 08:22:39 UTC (rev 285339)
@@ -1523,6 +1523,97 @@
 #endif
 }
 
+static void testTextReplacedObjects(AccessibilityTest* test, gconstpointer)
+{
+#if !USE(ATSPI)
+    g_test_skip("Embedded objects are not correctly handled with ATK");
+#else
+    test->showInWindow(800, 600);
+    test->loadHtml(
+        "<html>"
+        "  <body>"
+        "    <p>This is <button>button1</button> and <button>button2</button> in paragraph</p>"
+        "  </body>"
+        "</html>",
+        nullptr);
+    test->waitUntilLoadFinished();
+
+    auto testApp = test->findTestApplication();
+    g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get()));
+
+    auto documentWeb = test->findDocumentWeb(testApp.get());
+    g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get()));
+    g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1);
+
+    auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr));
+    g_assert_true(ATSPI_IS_TEXT(p.get()));
+    auto length = atspi_text_get_character_count(ATSPI_TEXT(p.get()), nullptr);
+    g_assert_cmpint(length, ==, 28);
+    GUniquePtr<char> text(atspi_text_get_text(ATSPI_TEXT(p.get()), 0, -1, nullptr));
+    g_assert_cmpstr(text.get(), ==, "This is \357\277\274 and \357\277\274 in paragraph");
+    g_assert_cmpint(atspi_accessible_get_child_count(p.get(), nullptr), ==, 2);
+
+    auto button1 = adoptGRef(atspi_accessible_get_child_at_index(p.get(), 0, nullptr));
+    g_assert_true(ATSPI_IS_ACCESSIBLE(button1.get()));
+    text.reset(atspi_accessible_get_name(button1.get(), nullptr));
+    g_assert_cmpstr(text.get(), ==, "button1");
+
+    auto button2 = adoptGRef(atspi_accessible_get_child_at_index(p.get(), 1, nullptr));
+    g_assert_true(ATSPI_IS_ACCESSIBLE(button2.get()));
+    text.reset(atspi_accessible_get_name(button2.get(), nullptr));
+    g_assert_cmpstr(text.get(), ==, "button2");
+
+    UniqueAtspiTextRange range(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 8, ATSPI_TEXT_GRANULARITY_CHAR, nullptr));
+    g_assert_cmpstr(range->content, ==, "\357\277\274");
+    g_assert_cmpint(range->start_offset, ==, 8);
+    g_assert_cmpint(range->end_offset, ==, 9);
+    range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 14, ATSPI_TEXT_GRANULARITY_CHAR, nullptr));
+    g_assert_cmpstr(range->content, ==, "\357\277\274");
+    g_assert_cmpint(range->start_offset, ==, 14);
+    g_assert_cmpint(range->end_offset, ==, 15);
+
+    range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 8, ATSPI_TEXT_GRANULARITY_WORD, nullptr));
+    g_assert_cmpstr(range->content, ==, "\357\277\274 ");
+    g_assert_cmpint(range->start_offset, ==, 8);
+    g_assert_cmpint(range->end_offset, ==, 10);
+    range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 14, ATSPI_TEXT_GRANULARITY_WORD, nullptr));
+    g_assert_cmpstr(range->content, ==, "\357\277\274 ");
+    g_assert_cmpint(range->start_offset, ==, 14);
+    g_assert_cmpint(range->end_offset, ==, 16);
+
+    int startOffset, endOffset;
+    GRefPtr<GHashTable> attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 0, FALSE, &startOffset, &endOffset, nullptr));
+    g_assert_nonnull(attributes.get());
+    g_assert_cmpuint(g_hash_table_size(attributes.get()), ==, 0);
+    g_assert_cmpint(startOffset, ==, 0);
+    g_assert_cmpint(endOffset, ==, 8);
+
+    attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 9, FALSE, &startOffset, &endOffset, nullptr));
+    g_assert_nonnull(attributes.get());
+    g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 0);
+    g_assert_cmpint(startOffset, ==, 8);
+    g_assert_cmpint(endOffset, ==, 9);
+
+    attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 11, FALSE, &startOffset, &endOffset, nullptr));
+    g_assert_nonnull(attributes.get());
+    g_assert_cmpuint(g_hash_table_size(attributes.get()), ==, 0);
+    g_assert_cmpint(startOffset, ==, 9);
+    g_assert_cmpint(endOffset, ==, 14);
+
+    attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 15, FALSE, &startOffset, &endOffset, nullptr));
+    g_assert_nonnull(attributes.get());
+    g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 0);
+    g_assert_cmpint(startOffset, ==, 14);
+    g_assert_cmpint(endOffset, ==, 15);
+
+    attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 18, FALSE, &startOffset, &endOffset, nullptr));
+    g_assert_nonnull(attributes.get());
+    g_assert_cmpuint(g_hash_table_size(attributes.get()), ==, 0);
+    g_assert_cmpint(startOffset, ==, 15);
+    g_assert_cmpint(endOffset, ==, 28);
+#endif
+}
+
 void beforeAll()
 {
     AccessibilityTest::add("WebKitAccessibility", "accessible/basic-hierarchy", testAccessibleBasicHierarchy);
@@ -1542,6 +1633,7 @@
     AccessibilityTest::add("WebKitAccessibility", "text/selections", testTextSelections);
     AccessibilityTest::add("WebKitAccessibility", "text/attributes", testTextAttributes);
     AccessibilityTest::add("WebKitAccessibility", "text/state-changed", testTextStateChanged);
+    AccessibilityTest::add("WebKitAccessibility", "text/replaced-objects", testTextReplacedObjects);
 }
 
 void afterAll()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to