Title: [284245] trunk
Revision
284245
Author
[email protected]
Date
2021-10-15 07:35:04 -0700 (Fri, 15 Oct 2021)

Log Message

AX: WebKit should not expose redundant AXGroups with missing role when the label is the same as the contents
https://bugs.webkit.org/show_bug.cgi?id=169924

Patch by Tyler Wilcock <[email protected]> on 2021-10-15
Reviewed by Andres Gonzalez.

Source/WebCore:

Don't expose groups with redundant accessibility text on the Mac.
Here's an example of one such group:

<div aria-label="1">1</div>

This group is not useful to accessibility clients. Instead, we
expose the text contents directly.

Test: accessibility/ignore-redundant-accessibility-text-groups.html

* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::textUnderElement const):
Instead of asserting when we try to get the text of an element in a
document that needs a style update, return an empty string.

* accessibility/mac/AccessibilityObjectMac.mm:
(WebCore::shouldIgnoreGroup): Added.
(WebCore::AccessibilityObject::accessibilityPlatformIncludesObject const):

LayoutTests:

Add a test ensuring WebKit appropriately does and doesn't expose
groups with redundant accessibility text.

* accessibility/mac/ignore-redundant-accessibility-text-groups-expected.txt: Added.
* accessibility/mac/ignore-redundant-accessibility-text-groups.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (284244 => 284245)


--- trunk/LayoutTests/ChangeLog	2021-10-15 14:32:36 UTC (rev 284244)
+++ trunk/LayoutTests/ChangeLog	2021-10-15 14:35:04 UTC (rev 284245)
@@ -1,5 +1,18 @@
 2021-10-15  Tyler Wilcock  <[email protected]>
 
+        AX: WebKit should not expose redundant AXGroups with missing role when the label is the same as the contents
+        https://bugs.webkit.org/show_bug.cgi?id=169924
+
+        Reviewed by Andres Gonzalez.
+
+        Add a test ensuring WebKit appropriately does and doesn't expose
+        groups with redundant accessibility text.
+
+        * accessibility/mac/ignore-redundant-accessibility-text-groups-expected.txt: Added.
+        * accessibility/mac/ignore-redundant-accessibility-text-groups.html: Added.
+
+2021-10-15  Tyler Wilcock  <[email protected]>
+
         AX: Return AXEmptyGroup subrole for groups with no accessible content
         https://bugs.webkit.org/show_bug.cgi?id=231528
 

Added: trunk/LayoutTests/accessibility/mac/ignore-redundant-accessibility-text-groups-expected.txt (0 => 284245)


--- trunk/LayoutTests/accessibility/mac/ignore-redundant-accessibility-text-groups-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/accessibility/mac/ignore-redundant-accessibility-text-groups-expected.txt	2021-10-15 14:35:04 UTC (rev 284245)
@@ -0,0 +1,30 @@
+This test ensures WebKit ignores groups with redundant accessibility text.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS !ariaLabelGroup is true
+PASS !titleGroup is true
+PASS !ariaLabelDiv is true
+PASS !titleDiv is true
+PASS typeof clickHandlerGroup is 'object'
+PASS typeof clickHandlerDiv is 'object'
+PASS resultElement.role is 'AXRole: AXStaticText'
+PASS resultElement.stringValue is 'AXValue: Blue cheese'
+PASS resultElement.role is 'AXRole: AXStaticText'
+PASS resultElement.stringValue is 'AXValue: Oranges'
+PASS contentContainer.childrenCount is 6
+PASS contentContainer.childAtIndex(0).stringValue is 'AXValue: Blue cheese'
+PASS contentContainer.childAtIndex(0).role is 'AXRole: AXStaticText'
+PASS contentContainer.childAtIndex(1).stringValue is 'AXValue: Oranges'
+PASS contentContainer.childAtIndex(1).role is 'AXRole: AXStaticText'
+PASS contentContainer.childAtIndex(2).role is 'AXRole: AXGroup'
+PASS contentContainer.childAtIndex(3).stringValue is 'AXValue: Jello'
+PASS contentContainer.childAtIndex(3).role is 'AXRole: AXStaticText'
+PASS contentContainer.childAtIndex(4).stringValue is 'AXValue: Broccoli'
+PASS contentContainer.childAtIndex(4).role is 'AXRole: AXStaticText'
+PASS contentContainer.childAtIndex(5).role is 'AXRole: AXGroup'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/accessibility/mac/ignore-redundant-accessibility-text-groups.html (0 => 284245)


--- trunk/LayoutTests/accessibility/mac/ignore-redundant-accessibility-text-groups.html	                        (rev 0)
+++ trunk/LayoutTests/accessibility/mac/ignore-redundant-accessibility-text-groups.html	2021-10-15 14:35:04 UTC (rev 284245)
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+
+<div id="content" role="group">
+    <!-- First, test role="group" elements. -->
+    <div id="aria-label-group" role="group" aria-label="Blue cheese">
+        Blue cheese
+    </div>
+
+    <div id="title-group" role="group" title="Oranges">
+        Oranges
+    </div>
+
+    <div id="click-handler-group" role="group" aria-label="Group click handler" _onclick_="emptyClickHandler()">
+        Group click handler
+    </div>
+
+    <!-- Also test role-less generic divs. -->
+    <div id="aria-label-div" aria-label="Jello">
+        Jello
+    </div>
+
+    <div id="title-div" title="Broccoli">
+        Broccoli
+    </div>
+
+    <div id="click-handler-div" aria-label="Div click handler" _onclick_="emptyClickHandler()">
+        Div click handler
+    </div>
+</div>
+
+<script>
+    description("This test ensures WebKit ignores groups with redundant accessibility text.");
+    const emptyClickHandler = () => {};
+
+    if (window.accessibilityController) {
+
+        var contentContainer = accessibilityController.accessibleElementById("content");
+
+        var ariaLabelGroup = accessibilityController.accessibleElementById("aria-label-group");
+        var clickHandlerGroup = accessibilityController.accessibleElementById("click-handler-group");
+        var titleGroup = accessibilityController.accessibleElementById("title-group");
+
+        var ariaLabelDiv = accessibilityController.accessibleElementById("aria-label-div");
+        var clickHandlerDiv = accessibilityController.accessibleElementById("click-handler-div");
+        var titleDiv = accessibilityController.accessibleElementById("title-div");
+
+        // We shouldn't be able to get an accessible element for these groups because they should be ignored.
+        shouldBeTrue("!ariaLabelGroup");
+        shouldBeTrue("!titleGroup");
+        shouldBeTrue("!ariaLabelDiv");
+        shouldBeTrue("!titleDiv");
+        // But any group with an event handler should always be exposed.
+        shouldBe("typeof clickHandlerGroup", "'object'");
+        shouldBe("typeof clickHandlerDiv", "'object'");
+
+        // Ensure we can search for the text within the ignored groups.
+        var resultElement = contentContainer.uiElementForSearchPredicate(contentContainer, true, "AXAnyTypeSearchKey", "", false);
+        shouldBe("resultElement.role", "'AXRole: AXStaticText'");
+        shouldBe("resultElement.stringValue", "'AXValue: Blue cheese'");
+
+        resultElement = contentContainer.uiElementForSearchPredicate(resultElement, true, "AXAnyTypeSearchKey", "", false);
+        shouldBe("resultElement.role", "'AXRole: AXStaticText'");
+        shouldBe("resultElement.stringValue", "'AXValue: Oranges'");
+
+        // Ensure the only accessible content exposed via `children` is the text elements and event handler groups.
+        shouldBe("contentContainer.childrenCount", "6");
+        shouldBe("contentContainer.childAtIndex(0).stringValue", "'AXValue: Blue cheese'");
+        shouldBe("contentContainer.childAtIndex(0).role", "'AXRole: AXStaticText'");
+
+        shouldBe("contentContainer.childAtIndex(1).stringValue", "'AXValue: Oranges'");
+        shouldBe("contentContainer.childAtIndex(1).role", "'AXRole: AXStaticText'");
+
+        shouldBe("contentContainer.childAtIndex(2).role", "'AXRole: AXGroup'");
+
+        shouldBe("contentContainer.childAtIndex(3).stringValue", "'AXValue: Jello'");
+        shouldBe("contentContainer.childAtIndex(3).role", "'AXRole: AXStaticText'");
+
+        shouldBe("contentContainer.childAtIndex(4).stringValue", "'AXValue: Broccoli'");
+        shouldBe("contentContainer.childAtIndex(4).role", "'AXRole: AXStaticText'");
+
+        shouldBe("contentContainer.childAtIndex(5).role", "'AXRole: AXGroup'");
+
+        document.getElementById("content").style.visibility = "hidden";
+    }
+</script>
+</body>
+</html>
+

Modified: trunk/Source/WebCore/ChangeLog (284244 => 284245)


--- trunk/Source/WebCore/ChangeLog	2021-10-15 14:32:36 UTC (rev 284244)
+++ trunk/Source/WebCore/ChangeLog	2021-10-15 14:35:04 UTC (rev 284245)
@@ -1,5 +1,31 @@
 2021-10-15  Tyler Wilcock  <[email protected]>
 
+        AX: WebKit should not expose redundant AXGroups with missing role when the label is the same as the contents
+        https://bugs.webkit.org/show_bug.cgi?id=169924
+
+        Reviewed by Andres Gonzalez.
+
+        Don't expose groups with redundant accessibility text on the Mac.
+        Here's an example of one such group:
+
+        <div aria-label="1">1</div>
+
+        This group is not useful to accessibility clients. Instead, we
+        expose the text contents directly.
+
+        Test: accessibility/ignore-redundant-accessibility-text-groups.html
+
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::textUnderElement const):
+        Instead of asserting when we try to get the text of an element in a
+        document that needs a style update, return an empty string.
+
+        * accessibility/mac/AccessibilityObjectMac.mm:
+        (WebCore::shouldIgnoreGroup): Added.
+        (WebCore::AccessibilityObject::accessibilityPlatformIncludesObject const):
+
+2021-10-15  Tyler Wilcock  <[email protected]>
+
         AX: Return AXEmptyGroup subrole for groups with no accessible content
         https://bugs.webkit.org/show_bug.cgi?id=231528
 

Modified: trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp (284244 => 284245)


--- trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp	2021-10-15 14:32:36 UTC (rev 284244)
+++ trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp	2021-10-15 14:35:04 UTC (rev 284245)
@@ -680,12 +680,14 @@
             if (Frame* frame = nodeDocument->frame()) {
                 // catch stale WebCoreAXObject (see <rdar://problem/3960196>)
                 if (frame->document() != nodeDocument)
-                    return String();
+                    return { };
 
-                // Renders referenced by accessibility objects could get destroyed, if TextIterator ends up triggering
-                // style update/layout here. See also AXObjectCache::deferTextChangedIfNeeded().
-                ASSERT_WITH_SECURITY_IMPLICATION(!nodeDocument->childNeedsStyleRecalc());
+                // Renderers referenced by accessibility objects could get destroyed if TextIterator ends up triggering
+                // a style update or layout here. See also AXObjectCache::deferTextChangedIfNeeded().
+                if (nodeDocument->childNeedsStyleRecalc())
+                    return { };
                 ASSERT_WITH_SECURITY_IMPLICATION(!nodeDocument->view()->layoutContext().isInRenderTreeLayout());
+
                 return plainText(*textRange, textIteratorBehaviorForTextRange());
             }
         }

Modified: trunk/Source/WebCore/accessibility/mac/AccessibilityObjectMac.mm (284244 => 284245)


--- trunk/Source/WebCore/accessibility/mac/AccessibilityObjectMac.mm	2021-10-15 14:32:36 UTC (rev 284244)
+++ trunk/Source/WebCore/accessibility/mac/AccessibilityObjectMac.mm	2021-10-15 14:35:04 UTC (rev 284245)
@@ -114,6 +114,28 @@
     return true;
 }
 
+static bool shouldIgnoreGroup(const AccessibilityObject& axObject)
+{
+    if (!axObject.isGroup() && axObject.roleValue() != AccessibilityRole::Div)
+        return false;
+
+    // Never ignore a <div> with event listeners attached to it (e.g. onclick).
+    if (axObject.node() && axObject.node()->hasEventListeners())
+        return false;
+
+    auto* first = axObject.firstChild();
+    if (first && first == axObject.lastChild() && first->roleValue() == AccessibilityRole::StaticText) {
+        Vector<AccessibilityText> axText;
+        axObject.accessibilityText(axText);
+        // Don't expose <div>s whose only child is text that has the same content as the <div>s accessibility text.
+        // Instead, we should expose the text element directly.
+        auto firstText = axText.size() ? axText[0].text : String();
+        if (first->stringValue() == firstText)
+            return true;
+    }
+    return false;
+}
+
 AccessibilityObjectInclusion AccessibilityObject::accessibilityPlatformIncludesObject() const
 {
     if (isMenuListPopup() || isMenuListOption())
@@ -142,6 +164,9 @@
         }
     }
     
+    if (shouldIgnoreGroup(*this))
+        return AccessibilityObjectInclusion::IgnoreObject;
+
     return AccessibilityObjectInclusion::DefaultBehavior;
 }
     
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to