Title: [292774] trunk
Revision
292774
Author
[email protected]
Date
2022-04-12 10:02:46 -0700 (Tue, 12 Apr 2022)

Log Message

AX: Incorrect role on dynamic lists
https://bugs.webkit.org/show_bug.cgi?id=238831

Reviewed by Andres Gonzalez.

Source/WebCore:

AccessibilityList objects cache their role after running
AccessibilityNodeObject::determineAccessibilityRole, but we never
recomputed it when necessary.

With this patch, when the children of a list changes, we also
re-compute its role, since a list's role is dependent on its children.

Test: accessibility/list-with-dynamically-changing-content.html

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::handleChildrenChanged):
(WebCore::AXObjectCache::handleRoleChange):
(WebCore::AXObjectCache::handleAriaRoleChanged):
Renamed to handleRoleChange.
* accessibility/AXObjectCache.h:
(WebCore::AXObjectCache::handleRoleChange):
(WebCore::AXObjectCache::handleAriaRoleChanged):
Renamed to handleRoleChange.
* accessibility/AccessibilityNodeObject.cpp:
(WebCore::AccessibilityNodeObject::updateRole):
(WebCore::AccessibilityNodeObject::updateAccessibilityRole):
Renamed to updateRole.
* accessibility/AccessibilityNodeObject.h:
* accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::updateRole):
(WebCore::AccessibilityObject::updateAccessibilityRole):
Renamed to updateRole.
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::updateRoleAfterChildrenCreation):
* accessibility/AccessibilityTable.cpp:
(WebCore::AccessibilityTable::addChildren):

LayoutTests:

* accessibility/list-with-dynamically-changing-content-expected.txt: Added.
* accessibility/list-with-dynamically-changing-content.html: Added.
* platform/ios/accessibility/list-with-dynamically-changing-content-expected.txt: Added.
* platform/ios/TestExpectations: Enable new test.
* platform/win/TestExpectations: Skip new test.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (292773 => 292774)


--- trunk/LayoutTests/ChangeLog	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/LayoutTests/ChangeLog	2022-04-12 17:02:46 UTC (rev 292774)
@@ -1,3 +1,16 @@
+2022-04-12  Tyler Wilcock  <[email protected]>
+
+        AX: Incorrect role on dynamic lists
+        https://bugs.webkit.org/show_bug.cgi?id=238831
+
+        Reviewed by Andres Gonzalez.
+
+        * accessibility/list-with-dynamically-changing-content-expected.txt: Added.
+        * accessibility/list-with-dynamically-changing-content.html: Added.
+        * platform/ios/accessibility/list-with-dynamically-changing-content-expected.txt: Added.
+        * platform/ios/TestExpectations: Enable new test.
+        * platform/win/TestExpectations: Skip new test.
+
 2022-04-11  Myles C. Maxfield  <[email protected]>
 
         Make fast/text/otsvg-canvas.html more robust

Added: trunk/LayoutTests/accessibility/list-with-dynamically-changing-content-expected.txt (0 => 292774)


--- trunk/LayoutTests/accessibility/list-with-dynamically-changing-content-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/accessibility/list-with-dynamically-changing-content-expected.txt	2022-04-12 17:02:46 UTC (rev 292774)
@@ -0,0 +1,25 @@
+This test ensures that lists that are initially empty but gain children later become part of the AX tree with the proper role.
+
+#ul-list: AXRole: AXGroup
+#ul-list: childrenCount 0
+#aria-list: AXRole: AXGroup
+#aria-list: childrenCount 0
+
+Adding listitems to both lists.
+
+#ul-list: AXRole: AXList
+#ul-list: childrenCount 1
+#aria-list: AXRole: AXList
+#aria-list: childrenCount 1
+
+Clearing listitems from both lists.
+
+#ul-list: AXRole: AXGroup
+#ul-list: childrenCount 0
+#aria-list: AXRole: AXGroup
+#aria-list: childrenCount 0
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/accessibility/list-with-dynamically-changing-content.html (0 => 292774)


--- trunk/LayoutTests/accessibility/list-with-dynamically-changing-content.html	                        (rev 0)
+++ trunk/LayoutTests/accessibility/list-with-dynamically-changing-content.html	2022-04-12 17:02:46 UTC (rev 292774)
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+
+<ul id="ul-list"></ul>
+<div id="aria-list" role="list"></div>
+
+<script>
+    var testOutput = "This test ensures that lists that are initially empty but gain children later become part of the AX tree with the proper role.\n\n";
+    var ulList, ariaList;
+
+    function verifyLists() {
+        testOutput += `#ul-list: ${ulList.role}\n`;
+        testOutput += `#ul-list: childrenCount ${ulList.childrenCount}\n`;
+        testOutput += `#aria-list: ${ariaList.role}\n`;
+        testOutput += `#aria-list: childrenCount ${ariaList.childrenCount}\n`;
+    }
+
+    async function waitForChildrenCount(count) {
+        await waitFor(() => {
+            return ulList.childrenCount === count && ariaList.childrenCount === count;
+        });
+    }
+
+    if (window.accessibilityController) {
+        window.jsTestIsAsync = true;
+        ulList = accessibilityController.accessibleElementById("ul-list");
+        ariaList = accessibilityController.accessibleElementById("aria-list");
+        verifyLists();
+
+        testOutput += `\nAdding listitems to both lists.\n\n`;
+        const li = document.createElement("li");
+        li.textContent = "A dynamic list item";
+        document.getElementById("ul-list").appendChild(li);
+
+        const ariaListItem = document.createElement("div");
+        ariaListItem.role = "listitem";
+        document.getElementById("aria-list").appendChild(ariaListItem);
+
+        setTimeout(async function() {
+            await waitForChildrenCount(1);
+            verifyLists();
+
+            document.getElementById("ul-list").removeChild(li);
+            document.getElementById("aria-list").removeChild(ariaListItem);
+            testOutput += `\nClearing listitems from both lists.\n\n`;
+            await waitForChildrenCount(0);
+            verifyLists();
+
+            debug(testOutput);
+            finishJSTest();
+        }, 0);
+    }
+</script>
+</body>
+</html>
+

Modified: trunk/LayoutTests/platform/ios/TestExpectations (292773 => 292774)


--- trunk/LayoutTests/platform/ios/TestExpectations	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2022-04-12 17:02:46 UTC (rev 292774)
@@ -2097,6 +2097,7 @@
 accessibility/aria-readonly-updates-after-dynamic-change.html [ Pass ]
 accessibility/aria-required-updates-after-dynamic-change.html [ Pass ]
 accessibility/display-contents-element-roles.html [ Pass ]
+accessibility/list-with-dynamically-changing-content.html [ Pass ]
 accessibility/node-only-object-element-rect.html [ Pass ]
 accessibility/video-element-url-attribute.html [ Pass ]
 accessibility/visible-character-range-basic.html [ Pass ]

Added: trunk/LayoutTests/platform/ios/accessibility/list-with-dynamically-changing-content-expected.txt (0 => 292774)


--- trunk/LayoutTests/platform/ios/accessibility/list-with-dynamically-changing-content-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/ios/accessibility/list-with-dynamically-changing-content-expected.txt	2022-04-12 17:02:46 UTC (rev 292774)
@@ -0,0 +1,25 @@
+This test ensures that lists that are initially empty but gain children later become part of the AX tree with the proper role.
+
+#ul-list: Group
+#ul-list: childrenCount 0
+#aria-list: ApplicationGroup
+#aria-list: childrenCount 0
+
+Adding listitems to both lists.
+
+#ul-list: List
+#ul-list: childrenCount 1
+#aria-list: List
+#aria-list: childrenCount 1
+
+Clearing listitems from both lists.
+
+#ul-list: Group
+#ul-list: childrenCount 0
+#aria-list: ApplicationGroup
+#aria-list: childrenCount 0
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Modified: trunk/LayoutTests/platform/win/TestExpectations (292773 => 292774)


--- trunk/LayoutTests/platform/win/TestExpectations	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/LayoutTests/platform/win/TestExpectations	2022-04-12 17:02:46 UTC (rev 292774)
@@ -460,6 +460,9 @@
 # TODO Accept header is handled by the browser
 http/tests/misc/image-checks-for-accept.html [ Skip ]
 
+# Probably wrong role after adding children to list (AXGroup instead of AXList).
+accessibility/list-with-dynamically-changing-content.html [ Skip ]
+
 # Need to implement AccessibilityUIElement::clearSelectedChildren()
 accessibility/aria-listbox-clear-selection-crash.html [ Skip ]
 accessibility/listbox-clear-selection.html [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (292773 => 292774)


--- trunk/Source/WebCore/ChangeLog	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/Source/WebCore/ChangeLog	2022-04-12 17:02:46 UTC (rev 292774)
@@ -1,3 +1,42 @@
+2022-04-12  Tyler Wilcock  <[email protected]>
+
+        AX: Incorrect role on dynamic lists
+        https://bugs.webkit.org/show_bug.cgi?id=238831
+
+        Reviewed by Andres Gonzalez.
+
+        AccessibilityList objects cache their role after running
+        AccessibilityNodeObject::determineAccessibilityRole, but we never
+        recomputed it when necessary.
+
+        With this patch, when the children of a list changes, we also
+        re-compute its role, since a list's role is dependent on its children.
+
+        Test: accessibility/list-with-dynamically-changing-content.html
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::handleChildrenChanged):
+        (WebCore::AXObjectCache::handleRoleChange):
+        (WebCore::AXObjectCache::handleAriaRoleChanged):
+        Renamed to handleRoleChange.
+        * accessibility/AXObjectCache.h:
+        (WebCore::AXObjectCache::handleRoleChange):
+        (WebCore::AXObjectCache::handleAriaRoleChanged):
+        Renamed to handleRoleChange.
+        * accessibility/AccessibilityNodeObject.cpp:
+        (WebCore::AccessibilityNodeObject::updateRole):
+        (WebCore::AccessibilityNodeObject::updateAccessibilityRole):
+        Renamed to updateRole.
+        * accessibility/AccessibilityNodeObject.h:
+        * accessibility/AccessibilityObject.h:
+        (WebCore::AccessibilityObject::updateRole):
+        (WebCore::AccessibilityObject::updateAccessibilityRole):
+        Renamed to updateRole.
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::updateRoleAfterChildrenCreation):
+        * accessibility/AccessibilityTable.cpp:
+        (WebCore::AccessibilityTable::addChildren):
+
 2022-04-12  Zan Dobersek  <[email protected]>
 
         [GTK][WPE] Move DMABuf-backed GraphicsContextGLANGLE functionality into a standalone derivation chain

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (292773 => 292774)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2022-04-12 17:02:46 UTC (rev 292774)
@@ -1075,6 +1075,10 @@
     updateIsolatedTree(object, AXChildrenChanged);
 #endif
 
+    // The role of list objects is dependent on their children, so we'll need to re-compute it here.
+    if (is<AccessibilityList>(object))
+        object.updateRole();
+
     postPlatformNotification(&object, AXChildrenChanged);
 }
 
@@ -1792,21 +1796,15 @@
         obj->handleActiveDescendantChanged();
 }
 
-void AXObjectCache::handleAriaRoleChanged(Node* node)
+void AXObjectCache::handleRoleChange(AccessibilityObject* axObject)
 {
     stopCachingComputedObjectAttributes();
+    if (axObject->hasIgnoredValueChanged())
+        childrenChanged(axObject->parentObject());
 
-    // Don't make an AX object unless it's needed
-    if (auto* object = get(node)) {
-        object->updateAccessibilityRole();
-
-        if (object->hasIgnoredValueChanged())
-            childrenChanged(object->parentObject());
-
 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
-        updateIsolatedTree(object, AXObjectCache::AXAriaRoleChanged);
+        updateIsolatedTree(axObject, AXObjectCache::AXAriaRoleChanged);
 #endif
-    }
 }
 
 void AXObjectCache::deferAttributeChangeIfNeeded(const QualifiedName& attrName, Element* element)
@@ -1843,8 +1841,10 @@
     if (!shouldProcessAttributeChange(attrName, element))
         return;
 
-    if (attrName == roleAttr)
-        handleAriaRoleChanged(element);
+    if (attrName == roleAttr) {
+        if (auto* axObject = get(element))
+            axObject->updateRole();
+    }
     else if (attrName == altAttr || attrName == titleAttr)
         textChanged(element);
     else if (attrName == disabledAttr)

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (292773 => 292774)


--- trunk/Source/WebCore/accessibility/AXObjectCache.h	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.h	2022-04-12 17:02:46 UTC (rev 292774)
@@ -186,6 +186,7 @@
     void childrenChanged(RenderObject*, RenderObject* newChild = nullptr);
     void childrenChanged(AccessibilityObject*);
     void checkedStateChanged(Node*);
+    void handleRoleChange(AccessibilityObject*);
     // Called when a node has just been attached, so we can make sure we have the right subclass of AccessibilityObject.
     void updateCacheAfterNodeIsAttached(Node*);
     void updateLoadingProgress(double);
@@ -467,7 +468,6 @@
     // Called by a node when text or a text equivalent (e.g. alt) attribute is changed.
     void textChanged(Node*);
     void handleActiveDescendantChanged(Node*);
-    void handleAriaRoleChanged(Node*);
     void handleAriaExpandedChange(Node*);
     void handleFocusedUIElementChanged(Node* oldFocusedNode, Node* newFocusedNode);
     void handleMenuListValueChanged(Element&);
@@ -602,7 +602,7 @@
 inline void AXObjectCache::handleAriaExpandedChange(Node*) { }
 inline void AXObjectCache::handleModalChange(Element&) { }
 inline void AXObjectCache::deferModalChange(Element*) { }
-inline void AXObjectCache::handleAriaRoleChanged(Node*) { }
+inline void AXObjectCache::handleRoleChange(AccessibilityObject*) { }
 inline void AXObjectCache::deferAttributeChangeIfNeeded(const QualifiedName&, Element*) { }
 inline void AXObjectCache::handleAttributeChange(const QualifiedName&, Element*) { }
 inline bool AXObjectCache::shouldProcessAttributeChange(const QualifiedName&, Element*) { return false; }

Modified: trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp (292773 => 292774)


--- trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/Source/WebCore/accessibility/AccessibilityNodeObject.cpp	2022-04-12 17:02:46 UTC (rev 292774)
@@ -120,9 +120,14 @@
     m_node = nullptr;
 }
 
-void AccessibilityNodeObject::updateAccessibilityRole()
+void AccessibilityNodeObject::updateRole()
 {
+    auto previousRole = m_role;
     m_role = determineAccessibilityRole();
+    if (previousRole != m_role) {
+        if (auto* cache = axObjectCache())
+            cache->handleRoleChange(this);
+    }
 }
 
 AccessibilityObject* AccessibilityNodeObject::firstChild() const

Modified: trunk/Source/WebCore/accessibility/AccessibilityNodeObject.h (292773 => 292774)


--- trunk/Source/WebCore/accessibility/AccessibilityNodeObject.h	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/Source/WebCore/accessibility/AccessibilityNodeObject.h	2022-04-12 17:02:46 UTC (rev 292774)
@@ -133,7 +133,7 @@
     AccessibilityObject* parentObject() const override;
     AccessibilityObject* parentObjectIfExists() const override;
 
-    void updateAccessibilityRole() override;
+    void updateRole() override;
 
     void increment() override;
     void decrement() override;

Modified: trunk/Source/WebCore/accessibility/AccessibilityObject.h (292773 => 292774)


--- trunk/Source/WebCore/accessibility/AccessibilityObject.h	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/Source/WebCore/accessibility/AccessibilityObject.h	2022-04-12 17:02:46 UTC (rev 292774)
@@ -508,7 +508,7 @@
     void increment() override { }
     void decrement() override { }
 
-    virtual void updateAccessibilityRole() { }
+    virtual void updateRole() { }
     const AccessibilityChildrenVector& children(bool updateChildrenIfNeeded = true) override;
     virtual void addChildren() { }
     enum class DescendIfIgnored : uint8_t { No, Yes };

Modified: trunk/Source/WebCore/accessibility/AccessibilityTable.cpp (292773 => 292774)


--- trunk/Source/WebCore/accessibility/AccessibilityTable.cpp	2022-04-12 16:03:50 UTC (rev 292773)
+++ trunk/Source/WebCore/accessibility/AccessibilityTable.cpp	2022-04-12 17:02:46 UTC (rev 292774)
@@ -429,7 +429,7 @@
     // see bug: https://bugs.webkit.org/show_bug.cgi?id=147001
     for (const auto& row : m_rows) {
         for (const auto& cell : row->children())
-            downcast<AccessibilityObject>(*cell).updateAccessibilityRole();
+            downcast<AccessibilityObject>(*cell).updateRole();
     }
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to