Accessibility client cannot navigate to internal links targets on iOS.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 11 Aug 2019 03:46:10 +0000 (03:46 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 11 Aug 2019 03:46:10 +0000 (03:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=200559
<rdar://problem/45242534>

Patch by Andres Gonzalez <andresg_22@apple.com> on 2019-08-10
Reviewed by Zalan Bujtas.

Source/WebCore:

The cause of the problem on iOS is that AccessibilityObject::firstAccessibleObjectFromNode
used in AccessibilityRenderObject::linkedUIElements may return an object
that is ignored by accessibility clients on iOS, and thus the client
would not track the target of an internal link. This change ensures that
accessibilityLinkedElement will return a valid accessibility element to
the client, if it is exists.
* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::firstAccessibleObjectFromNode):
(WebCore::firstAccessibleObjectFromNode):
* accessibility/AccessibilityObject.h:
* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper accessibilityLinkedElement]):

LayoutTests:

Extneded this test to not only check that internal links expose their
target, but also that the target is an accessible element. Added a
second test case where the target is contained in a grouping element.
* accessibility/ios-simulator/internal-link-expected.txt:
* accessibility/ios-simulator/internal-link.html:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@248513 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/accessibility/ios-simulator/internal-link-expected.txt
LayoutTests/accessibility/ios-simulator/internal-link.html
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityObject.cpp
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm

index fa87531..a3d4c61 100644 (file)
@@ -1,3 +1,17 @@
+2019-08-10  Andres Gonzalez  <andresg_22@apple.com>
+
+        Accessibility client cannot navigate to internal links targets on iOS.
+        https://bugs.webkit.org/show_bug.cgi?id=200559
+        <rdar://problem/45242534>
+
+        Reviewed by Zalan Bujtas.
+
+        Extneded this test to not only check that internal links expose their
+        target, but also that the target is an accessible element. Added a
+        second test case where the target is contained in a grouping element.
+        * accessibility/ios-simulator/internal-link-expected.txt:
+        * accessibility/ios-simulator/internal-link.html:
+
 2019-08-09  Yusuke Suzuki  <ysuzuki@apple.com>
 
         Universal XSS in JSObject::putInlineSlow and JSValue::putToPrimitive
index 33f404d..a04715e 100644 (file)
@@ -1,17 +1,22 @@
 Name 
 
 
+Linked Element 
 
 
+Go to greeting 
 
 
-Linked Element
-This test thats internal links return their linked elements
+Hello World!
+This tests that internal links return their linked elements, and that the returned object is indeed an accessible element.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS link.linkedElement().description is 'AXLabel: Linked Element'
+PASS linked1.description is 'AXLabel: Linked Element'
+PASS linked1.isIgnored is false
+PASS linked2.description is 'AXLabel: Hello World!'
+PASS linked2.isIgnored is false
 PASS successfullyParsed is true
 
 TEST COMPLETE
index af25df0..8a2b956 100644 (file)
@@ -3,39 +3,40 @@
 <head>
 <script src="../../resources/js-test-pre.js"></script>
 <script>
-var successfullyParsed = false;
 if (window.testRunner)
-   testRunner.dumpAsText();
+    testRunner.dumpAsText();
 </script>
 </head>
 <body>
 
-<a href="#name1" id="name">Name</a>
+<a href="#linked1" id="name">Name</a>
+<BR><BR><BR>
+<a name="linked1">Linked Element</a>
 
-<BR><BR><BR><BR>
 <BR><BR><BR>
-<a name="name1">Linked Element</a>
 
+<a href="#linked2" id="gotoGreeting">Go to greeting</a>
+<BR><BR><BR>
+<div id="linked2">Hello World!</div>
 
 <p id="description"></p>
 <div id="console"></div>
 
 <script>
-
-    description("This test thats internal links return their linked elements");
+    description("This tests that internal links return their linked elements, and that the returned object is indeed an accessible element.");
 
     if (window.accessibilityController) {
-
-        document.getElementById("name").focus();
-        var link = accessibilityController.focusedElement;
-        shouldBe("link.linkedElement().description", "'AXLabel: Linked Element'");
+        var link1 = accessibilityController.accessibleElementById("name");
+        var linked1 = link1.linkedElement();
+        shouldBe("linked1.description", "'AXLabel: Linked Element'");
+        shouldBeFalse("linked1.isIgnored");
+
+        var link2 = accessibilityController.accessibleElementById("gotoGreeting");
+        var linked2 = link2.linkedElement();
+        shouldBe("linked2.description", "'AXLabel: Hello World!'");
+        shouldBeFalse("linked2.isIgnored");
     }
-
-    successfullyParsed = true;
 </script>
-
 <script src="../../resources/js-test-post.js"></script>
-
 </body>
 </html>
-
index 18560ef..d2b8026 100644 (file)
@@ -1,3 +1,24 @@
+2019-08-10  Andres Gonzalez  <andresg_22@apple.com>
+
+        Accessibility client cannot navigate to internal links targets on iOS.
+        https://bugs.webkit.org/show_bug.cgi?id=200559
+        <rdar://problem/45242534>
+
+        Reviewed by Zalan Bujtas.
+
+        The cause of the problem on iOS is that AccessibilityObject::firstAccessibleObjectFromNode
+        used in AccessibilityRenderObject::linkedUIElements may return an object
+        that is ignored by accessibility clients on iOS, and thus the client
+        would not track the target of an internal link. This change ensures that
+        accessibilityLinkedElement will return a valid accessibility element to
+        the client, if it is exists.
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::AccessibilityObject::firstAccessibleObjectFromNode):
+        (WebCore::firstAccessibleObjectFromNode):
+        * accessibility/AccessibilityObject.h:
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (-[WebAccessibilityObjectWrapper accessibilityLinkedElement]):
+
 2019-08-10  Youenn Fablet  <youenn@apple.com>
 
         Blob should store its session ID
index eaf24d2..0e68445 100644 (file)
@@ -540,15 +540,22 @@ AccessibilityObject* AccessibilityObject::nextSiblingUnignored(int limit) const
 
 AccessibilityObject* AccessibilityObject::firstAccessibleObjectFromNode(const Node* node)
 {
+    return WebCore::firstAccessibleObjectFromNode(node, [] (const AccessibilityObject& accessible) {
+        return !accessible.accessibilityIsIgnored();
+    });
+}
+
+AccessibilityObject* firstAccessibleObjectFromNode(const Node* node, const WTF::Function<bool(const AccessibilityObject&)>& isAccessible)
+{
     if (!node)
         return nullptr;
 
     AXObjectCache* cache = node->document().axObjectCache();
     if (!cache)
         return nullptr;
-    
+
     AccessibilityObject* accessibleObject = cache->getOrCreate(node->renderer());
-    while (accessibleObject && accessibleObject->accessibilityIsIgnored()) {
+    while (accessibleObject && !isAccessible(*accessibleObject)) {
         node = NodeTraversal::next(*node);
 
         while (node && !node->renderer())
index 9fab2ad..04b0a09 100644 (file)
@@ -1069,6 +1069,8 @@ inline int AccessibilityObject::lineForPosition(const VisiblePosition&) const {
 inline void AccessibilityObject::updateBackingStore() { }
 #endif
 
+AccessibilityObject* firstAccessibleObjectFromNode(const Node*, const WTF::Function<bool(const AccessibilityObject&)>& isAccessible);
+
 } // namespace WebCore
 
 #define SPECIALIZE_TYPE_TRAITS_ACCESSIBILITY(ToValueTypeName, predicate) \
index cb0dd97..3c50193 100644 (file)
@@ -1798,20 +1798,26 @@ static void appendStringToResult(NSMutableString *result, NSString *string)
 {
     if (![self _prepareAccessibilityCall])
         return nil;
-    
+
     // If this static text inside of a link, it should use its parent's linked element.
     AccessibilityObject* element = m_object;
     if (m_object->roleValue() == AccessibilityRole::StaticText && m_object->parentObjectUnignored()->isLink())
         element = m_object->parentObjectUnignored();
-    
-    AccessibilityObject::AccessibilityChildrenVector children;
-    element->linkedUIElements(children);
-    if (children.size() == 0)
+
+    AccessibilityObject::AccessibilityChildrenVector linkedElements;
+    element->linkedUIElements(linkedElements);
+    if (!linkedElements.size() || !linkedElements[0])
         return nil;
-    
-    return children[0]->wrapper();
-}
 
+    // AccessibilityObject::linkedUIElements may return an object that is
+    // exposed in other platforms but not on iOS, i.e., grouping or structure
+    // elements like <div> or <p>. Thus find the next accessible object that is
+    // exposed on iOS.
+    auto linkedElement = firstAccessibleObjectFromNode(linkedElements[0]->node(), [] (const AccessibilityObject& accessible) {
+        return accessible.wrapper().isAccessibilityElement;
+    });
+    return linkedElement ? linkedElement->wrapper() : nullptr;
+}
 
 - (BOOL)isAttachment
 {