Title: [294875] trunk
Revision
294875
Author
tyle...@apple.com
Date
2022-05-26 04:40:09 -0700 (Thu, 26 May 2022)

Log Message

AccessibilityTable::m_isExposable is never recomputed after AccessibilityTable::init
https://bugs.webkit.org/show_bug.cgi?id=240750

Reviewed by Andres Gonzalez.

AccessibilityTable::m_isExposable is never recomputed after
AccessibilityTable::init. This is bad because the semantics of table,
and the semantics of the table cells in the table, are dependent on
whether the table is exposed.

With this commit, we recompute m_isExposable when a table's row count
changes. This commit also updates the isolated tree for row count
changes, meaning we handle dynamic aria-rowcount value modifications.

Test: accessibility/table-exposure-updates-dynamically.html.
Also added another testcase to accessibility/aria-table-attributes.html.

* LayoutTests/accessibility/aria-table-attributes-expected.txt:
* LayoutTests/accessibility/aria-table-attributes.html: Add testcase.
* LayoutTests/accessibility/table-exposure-updates-dynamically-expected.txt: Added.
* LayoutTests/accessibility/table-exposure-updates-dynamically.html: Added.
* LayoutTests/platform/glib/accessibility/table-exposure-updates-dynamically-expected.txt: Added.
* LayoutTests/platform/ios/TestExpectations: Enable new test.
* LayoutTests/platform/ios/accessibility/table-exposure-updates-dynamically-expected.txt: Added.
* LayoutTests/platform/win/TestExpectations: Disable new test.
* Source/WebCore/accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::remove):
(WebCore::AXObjectCache::childrenChanged):
(WebCore::AXObjectCache::handleRowCountChanged): Added.
(WebCore::AXObjectCache::handleAriaExpandedChange):
(WebCore::AXObjectCache::handleAttributeChange):
(WebCore::filterWeakHashSetForRemoval):
(WebCore::AXObjectCache::prepareForDocumentDestruction):
(WebCore::AXObjectCache::performDeferredCacheUpdate):
(WebCore::AXObjectCache::updateIsolatedTree):
* Source/WebCore/accessibility/AXObjectCache.h:
* Source/WebCore/accessibility/AccessibilityTable.cpp:
(WebCore::AccessibilityTable::recomputeIsExposable): Added.
(WebCore::AccessibilityTable::updateChildrenRoles): Added.
(WebCore::AccessibilityTable::addChildren):
* Source/WebCore/accessibility/AccessibilityTable.h:
* Source/WebCore/html/HTMLTablePartElement.h:
Moved findParentTable from protected to public so it can be called from
accessibility code.

Canonical link: https://commits.webkit.org/251005@main

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/accessibility/aria-table-attributes-expected.txt (294874 => 294875)


--- trunk/LayoutTests/accessibility/aria-table-attributes-expected.txt	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/LayoutTests/accessibility/aria-table-attributes-expected.txt	2022-05-26 11:40:09 UTC (rev 294875)
@@ -1,22 +1,21 @@
 This tests that attributes related to aria table/grid are working correctly.
 
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+PASS: grid.numberAttributeValue('AXARIAColumnCount') === 16
+PASS: grid.numberAttributeValue('AXARIARowCount') === 30
+PASS: grid.rowCount === 4
+PASS: grid.columnCount === 4
+PASS: cell1.numberAttributeValue('AXARIAColumnIndex') === 2
+PASS: cell1.numberAttributeValue('AXARIARowIndex') === 7
+PASS: cell2.numberAttributeValue('AXARIAColumnIndex') === 4
+PASS: cell2.numberAttributeValue('AXARIARowIndex') === 8
+PASS: cell4.numberAttributeValue('AXARIAColumnIndex') === 3
+PASS: cell2.rowIndexRange() === '{1, 2}'
+PASS: cell5.columnIndexRange() === '{2, 3}'
+PASS: cell3.rowIndexRange() === '{1, 2}'
+PASS: cell6.rowIndexRange() === '{0, 2}'
+PASS: cell7.rowIndexRange() === '{0, 2}'
+PASS: #grid AXARIARowCount dynamically changed to 60.
 
-
-PASS grid.numberAttributeValue('AXARIAColumnCount') is 16
-PASS grid.numberAttributeValue('AXARIARowCount') is 30
-PASS grid.rowCount is 4
-PASS grid.columnCount is 4
-PASS cell1.numberAttributeValue('AXARIAColumnIndex') is 2
-PASS cell1.numberAttributeValue('AXARIARowIndex') is 7
-PASS cell2.numberAttributeValue('AXARIAColumnIndex') is 4
-PASS cell2.numberAttributeValue('AXARIARowIndex') is 8
-PASS cell4.numberAttributeValue('AXARIAColumnIndex') is 3
-PASS cell2.rowIndexRange() is '{1, 2}'
-PASS cell5.columnIndexRange() is '{2, 3}'
-PASS cell3.rowIndexRange() is '{1, 2}'
-PASS cell6.rowIndexRange() is '{0, 2}'
-PASS cell7.rowIndexRange() is '{0, 2}'
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/accessibility/aria-table-attributes.html (294874 => 294875)


--- trunk/LayoutTests/accessibility/aria-table-attributes.html	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/LayoutTests/accessibility/aria-table-attributes.html	2022-05-26 11:40:09 UTC (rev 294875)
@@ -1,9 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
 <html>
 <head>
-<script src=""
+<script src=""
+<script src=""
 </head>
-<body id="body">
+<body>
 
 <div id="grid" role="grid" aria-colcount="16" aria-rowcount="30">
   <div role="rowgroup">
@@ -64,46 +65,53 @@
 </table>
 
 <script>
+    var testOutput = "This tests that attributes related to aria table/grid are working correctly.\n\n";
 
-    description("This tests that attributes related to aria table/grid are working correctly.");
-
     if (window.accessibilityController) {
-    
-          var grid = accessibilityController.accessibleElementById("grid");
-          var cell1 = accessibilityController.accessibleElementById("cell1");
-          var cell2 = accessibilityController.accessibleElementById("cell2");
-          var cell3 = accessibilityController.accessibleElementById("cell3");
-          var cell4 = accessibilityController.accessibleElementById("cell4");
-          var cell5 = accessibilityController.accessibleElementById("cell5");
-          var cell6 = accessibilityController.accessibleElementById("cell6");
-          var cell7 = accessibilityController.accessibleElementById("cell7");
-          
-          // aria-colcount and aria-rowcount
-          shouldBe("grid.numberAttributeValue('AXARIAColumnCount')", "16");
-          shouldBe("grid.numberAttributeValue('AXARIARowCount')", "30");
-          shouldBe("grid.rowCount", "4");
-          shouldBe("grid.columnCount", "4");
+        window.jsTestIsAsync = true;
 
-          // aria-colindex and aria-rowindex
-          shouldBe("cell1.numberAttributeValue('AXARIAColumnIndex')", "2");
-          shouldBe("cell1.numberAttributeValue('AXARIARowIndex')", "7");
-          shouldBe("cell2.numberAttributeValue('AXARIAColumnIndex')", "4");
-          shouldBe("cell2.numberAttributeValue('AXARIARowIndex')", "8");
-          // aria-colindex from parent row
-          shouldBe("cell4.numberAttributeValue('AXARIAColumnIndex')", "3");
-          
-          // aria-colspan and aria-rowspan, including aria-rowspan="0"
-          shouldBe("cell2.rowIndexRange()", "'{1, 2}'");
-          shouldBe("cell5.columnIndexRange()", "'{2, 3}'");
-          shouldBe("cell3.rowIndexRange()", "'{1, 2}'");
+        var grid = accessibilityController.accessibleElementById("grid");
+        var cell1 = accessibilityController.accessibleElementById("cell1");
+        var cell2 = accessibilityController.accessibleElementById("cell2");
+        var cell3 = accessibilityController.accessibleElementById("cell3");
+        var cell4 = accessibilityController.accessibleElementById("cell4");
+        var cell5 = accessibilityController.accessibleElementById("cell5");
+        var cell6 = accessibilityController.accessibleElementById("cell6");
+        var cell7 = accessibilityController.accessibleElementById("cell7");
 
-          shouldBe("cell6.rowIndexRange()", "'{0, 2}'");
-          // use rowspan for native table
-          shouldBe("cell7.rowIndexRange()", "'{0, 2}'");
+        // aria-colcount and aria-rowcount
+        testOutput += expect("grid.numberAttributeValue('AXARIAColumnCount')", "16");
+        testOutput += expect("grid.numberAttributeValue('AXARIARowCount')", "30");
+        testOutput += expect("grid.rowCount", "4");
+        testOutput += expect("grid.columnCount", "4");
+
+        // aria-colindex and aria-rowindex
+        testOutput += expect("cell1.numberAttributeValue('AXARIAColumnIndex')", "2");
+        testOutput += expect("cell1.numberAttributeValue('AXARIARowIndex')", "7");
+        testOutput += expect("cell2.numberAttributeValue('AXARIAColumnIndex')", "4");
+        testOutput += expect("cell2.numberAttributeValue('AXARIARowIndex')", "8");
+        // aria-colindex from parent row
+        testOutput += expect("cell4.numberAttributeValue('AXARIAColumnIndex')", "3");
+
+        // aria-colspan and aria-rowspan, including aria-rowspan="0"
+        testOutput += expect("cell2.rowIndexRange()", "'{1, 2}'");
+        testOutput += expect("cell5.columnIndexRange()", "'{2, 3}'");
+        testOutput += expect("cell3.rowIndexRange()", "'{1, 2}'");
+
+        testOutput += expect("cell6.rowIndexRange()", "'{0, 2}'");
+        // use rowspan for native table
+        testOutput += expect("cell7.rowIndexRange()", "'{0, 2}'");
+
+        document.getElementById("grid").setAttribute("aria-rowcount", "60");
+        setTimeout(async function() {
+            await waitFor(() => { return grid.numberAttributeValue('AXARIARowCount') === 60 });
+            testOutput += "PASS: #grid AXARIARowCount dynamically changed to 60.\n";
+
+            debug(testOutput);
+            finishJSTest();
+        }, 0);
     }
-
 </script>
-
-<script src=""
 </body>
 </html>
+

Added: trunk/LayoutTests/accessibility/table-exposure-updates-dynamically-expected.txt (0 => 294875)


--- trunk/LayoutTests/accessibility/table-exposure-updates-dynamically-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/accessibility/table-exposure-updates-dynamically-expected.txt	2022-05-26 11:40:09 UTC (rev 294875)
@@ -0,0 +1,18 @@
+This test ensures a table's "exposed" state (whether it is an accessibility data table, vs. just a layout table) updates in response to dynamic page changes.
+
+Initial table state has aria-rowcount, so it should be a data table.
+#table AXRole: AXTable
+#cellOne AXRole: AXCell
+
+Removing aria-rowcount. Based on this table's contents, it should now become a layout table.
+#table AXRole: AXUnknown
+#cellOne AXRole: AXGroup
+
+Adding a lot of rows which should cause the table to become an accessibility data table.
+#table AXRole: AXTable
+#cellOne AXRole: AXCell
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/accessibility/table-exposure-updates-dynamically.html (0 => 294875)


--- trunk/LayoutTests/accessibility/table-exposure-updates-dynamically.html	                        (rev 0)
+++ trunk/LayoutTests/accessibility/table-exposure-updates-dynamically.html	2022-05-26 11:40:09 UTC (rev 294875)
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+
+<table id="table" aria-rowcount="1">
+    <tr>
+        <td id="cellOne">x</td>
+        <td>x</td>
+    </tr>
+</table>
+
+<script>
+    var testOutput = `This test ensures a table's "exposed" state (whether it is an accessibility data table, vs. just a layout table) updates in response to dynamic page changes.\n\n`;
+
+    function createCell() {
+        const cell = document.createElement("td");
+        cell.appendChild(document.createTextNode("Text inside cell"));
+        return cell;
+    }
+
+    if (window.accessibilityController) {
+        window.jsTestIsAsync = true;
+
+        const table = accessibilityController.accessibleElementById("table");
+        const cellOne = accessibilityController.accessibleElementById("cellOne");
+        testOutput += "Initial table state has aria-rowcount, so it should be a data table.\n";
+        testOutput += `#table ${table.role}\n`;
+        testOutput += `#cellOne ${cellOne.role}\n`;
+
+        testOutput += "\nRemoving aria-rowcount. Based on this table's contents, it should now become a layout table.\n";
+        document.getElementById("table").removeAttribute("aria-rowcount");
+        setTimeout(async function() {
+            await waitFor(() => {
+                return !cellOne.role.includes("Cell") && !table.role.includes("Table");
+            });
+            testOutput += `#table ${table.role}\n`;
+            testOutput += `#cellOne ${cellOne.role}\n`;
+
+            testOutput += "\nAdding a lot of rows which should cause the table to become an accessibility data table.\n";
+            for (let i = 0; i < 20; i++) {
+                const row = document.getElementById("table").insertRow(-1);
+                row.appendChild(createCell());
+                row.appendChild(createCell());
+            }
+
+            await waitFor(() => {
+                return table.childrenCount >= 20 &&
+                    cellOne.role.includes("Cell") &&
+                    table.role.includes("Table");
+            });
+            testOutput += `#table ${table.role}\n`;
+            testOutput += `#cellOne ${cellOne.role}\n`;
+
+            document.getElementById("table").style.visibility = "hidden";
+            debug(testOutput);
+            finishJSTest();
+        }, 0);
+    }
+</script>
+</body>
+</html>
+

Added: trunk/LayoutTests/platform/glib/accessibility/table-exposure-updates-dynamically-expected.txt (0 => 294875)


--- trunk/LayoutTests/platform/glib/accessibility/table-exposure-updates-dynamically-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/glib/accessibility/table-exposure-updates-dynamically-expected.txt	2022-05-26 11:40:09 UTC (rev 294875)
@@ -0,0 +1,18 @@
+This test ensures a table's "exposed" state (whether it is an accessibility data table, vs. just a layout table) updates in response to dynamic page changes.
+
+Initial table state has aria-rowcount, so it should be a data table.
+#table AXRole: AXTable
+#cellOne AXRole: AXCell
+
+Removing aria-rowcount. Based on this table's contents, it should now become a layout table.
+#table AXRole: AXUnknown
+#cellOne AXRole: AXSection
+
+Adding a lot of rows which should cause the table to become an accessibility data table.
+#table AXRole: AXTable
+#cellOne AXRole: AXCell
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Modified: trunk/LayoutTests/platform/ios/TestExpectations (294874 => 294875)


--- trunk/LayoutTests/platform/ios/TestExpectations	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2022-05-26 11:40:09 UTC (rev 294875)
@@ -2114,6 +2114,7 @@
 # Enable "phone number linkifying" test for iOS
 fast/dom/linkify-phone-numbers.html [ Pass ]
 
+accessibility/table-exposure-updates-dynamically.html [ Pass ]
 accessibility/aria-busy-updates-after-dynamic-change.html [ Pass ]
 accessibility/aria-hidden-display-contents-element.html [ Pass ]
 accessibility/aria-readonly-updates-after-dynamic-change.html [ Pass ]

Added: trunk/LayoutTests/platform/ios/accessibility/table-exposure-updates-dynamically-expected.txt (0 => 294875)


--- trunk/LayoutTests/platform/ios/accessibility/table-exposure-updates-dynamically-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/ios/accessibility/table-exposure-updates-dynamically-expected.txt	2022-05-26 11:40:09 UTC (rev 294875)
@@ -0,0 +1,18 @@
+This test ensures a table's "exposed" state (whether it is an accessibility data table, vs. just a layout table) updates in response to dynamic page changes.
+
+Initial table state has aria-rowcount, so it should be a data table.
+#table Table
+#cellOne Cell
+
+Removing aria-rowcount. Based on this table's contents, it should now become a layout table.
+#table Unknown
+#cellOne TextGroup
+
+Adding a lot of rows which should cause the table to become an accessibility data table.
+#table Table
+#cellOne Cell
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Modified: trunk/LayoutTests/platform/win/TestExpectations (294874 => 294875)


--- trunk/LayoutTests/platform/win/TestExpectations	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/LayoutTests/platform/win/TestExpectations	2022-05-26 11:40:09 UTC (rev 294875)
@@ -459,6 +459,9 @@
 # TODO Accept header is handled by the browser
 http/tests/misc/image-checks-for-accept.html [ Skip ]
 
+# Timing out since added in https://bugs.webkit.org/show_bug.cgi?id=240750 (likely some missing AccessibilityUIElement implementation).
+accessibility/table-exposure-updates-dynamically.html [ Skip ]
+
 # Probably wrong role after adding children to list (AXGroup instead of AXList).
 accessibility/list-with-dynamically-changing-content.html [ Skip ]
 accessibility/ignored-aria-role-description.html [ Skip ]

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (294874 => 294875)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2022-05-26 11:40:09 UTC (rev 294875)
@@ -85,6 +85,8 @@
 #include "HTMLOptionElement.h"
 #include "HTMLParserIdioms.h"
 #include "HTMLSelectElement.h"
+#include "HTMLTableElement.h"
+#include "HTMLTableSectionElement.h"
 #include "HTMLTextFormControlElement.h"
 #include "InlineRunAndOffset.h"
 #include "MathMLElement.h"
@@ -900,6 +902,7 @@
         m_deferredAttributeChange.remove(downcast<Element>(&node));
         m_modalElementsSet.remove(downcast<Element>(&node));
         m_deferredRecomputeIsIgnoredList.remove(downcast<Element>(node));
+        m_deferredRecomputeTableIsExposedList.remove(downcast<Element>(node));
         m_deferredSelectedChildredChangedList.remove(downcast<Element>(node));
         m_deferredModalChangedList.remove(downcast<Element>(node));
         m_deferredMenuListChange.remove(downcast<Element>(node));
@@ -1140,6 +1143,12 @@
         return;
     m_deferredChildrenChangedList.add(object);
 
+    // Adding or removing rows from a table can cause it to change from layout table to AX data table and vice versa, so queue up recomputation of that for the parent table.
+    if (auto* tableSectionElement = dynamicDowncast<HTMLTableSectionElement>(object->element())) {
+        if (auto* parentTable = tableSectionElement->findParentTable().get())
+            m_deferredRecomputeTableIsExposedList.add(*parentTable);
+    }
+
     if (!m_performCacheUpdateTimer.isActive())
         m_performCacheUpdateTimer.startOneShot(0_s);
 }
@@ -1293,7 +1302,18 @@
     
     postNotification(getOrCreate(node), &document(), AXMenuListItemSelected);
 }
-    
+
+void AXObjectCache::handleRowCountChanged(AXCoreObject* axObject, Document* document)
+{
+    if (!axObject)
+        return;
+
+    if (auto* axTable = dynamicDowncast<AccessibilityTable>(axObject))
+        axTable->recomputeIsExposable();
+
+    postNotification(axObject, document, AXRowCountChanged);
+}
+
 void AXObjectCache::deferFocusedUIElementChangeIfNeeded(Node* oldNode, Node* newNode)
 {
     if (nodeAndRendererAreValid(newNode) && rendererNeedsDeferredUpdate(*newNode->renderer())) {
@@ -1790,7 +1810,7 @@
 
         // Post that the ancestor's row count changed.
         if (ancestor)
-            postNotification(ancestor, &document(), AXRowCountChanged);
+            handleRowCountChanged(ancestor, &document());
 
         // Post that the specific row either collapsed or expanded.
         auto role = object->roleValue();
@@ -1942,6 +1962,8 @@
         postNotification(element, AXObjectCache::AXReadOnlyStatusChanged);
     else if (attrName == aria_requiredAttr)
         postNotification(element, AXObjectCache::AXRequiredStatusChanged);
+    else if (attrName == aria_rowcountAttr)
+        handleRowCountChanged(get(element), element ? &element->document() : nullptr);
     else if (attrName == aria_sortAttr)
         postNotification(element, AXObjectCache::AXSortDirectionChanged);
 }
@@ -3260,7 +3282,8 @@
         conditionallyAddNodeToFilterList(node, document, nodesToRemove);
 }
 
-static void filterWeakHashSetForRemoval(WeakHashSet<Element>& weakHashSet, const Document& document, HashSet<Ref<Node>>& nodesToRemove)
+template<typename T>
+static void filterWeakHashSetForRemoval(WeakHashSet<T>& weakHashSet, const Document& document, HashSet<Ref<Node>>& nodesToRemove)
 {
     weakHashSet.forEach([&] (auto& element) {
         conditionallyAddNodeToFilterList(&element, document, nodesToRemove);
@@ -3275,6 +3298,7 @@
     filterListForRemoval(m_deferredTextChangedList, document, nodesToRemove);
     filterListForRemoval(m_deferredNodeAddedOrRemovedList, document, nodesToRemove);
     filterWeakHashSetForRemoval(m_deferredRecomputeIsIgnoredList, document, nodesToRemove);
+    filterWeakHashSetForRemoval(m_deferredRecomputeTableIsExposedList, document, nodesToRemove);
     filterWeakHashSetForRemoval(m_deferredSelectedChildredChangedList, document, nodesToRemove);
     filterWeakHashSetForRemoval(m_deferredModalChangedList, document, nodesToRemove);
     filterWeakHashSetForRemoval(m_deferredMenuListChange, document, nodesToRemove);
@@ -3318,6 +3342,12 @@
         return;
     SetForScope performingDeferredCacheUpdate(m_performingDeferredCacheUpdate, true);
 
+    m_deferredRecomputeTableIsExposedList.forEach([this] (auto& tableElement) {
+        if (auto* axTable = dynamicDowncast<AccessibilityTable>(getOrCreate(&tableElement)))
+            axTable->recomputeIsExposable();
+    });
+    m_deferredRecomputeTableIsExposedList.clear();
+
     for (auto* nodeChild : m_deferredNodeAddedOrRemovedList) {
         handleMenuOpened(nodeChild);
         handleLiveRegionCreated(nodeChild);
@@ -3418,6 +3448,14 @@
         bool node { false };
     };
     HashMap<AXID, UpdatedFields> updatedObjects;
+    auto updateNode = [&] (RefPtr<AXCoreObject> axObject) {
+        auto updatedFields = updatedObjects.get(axObject->objectID());
+        if (!updatedFields.node) {
+            updatedObjects.set(axObject->objectID(), UpdatedFields { updatedFields.children, true });
+            tree->updateNode(*axObject);
+        }
+    };
+
     for (const auto& notification : notifications) {
         AXLOG(notification);
         if (!notification.first || !notification.first->objectID().isValid())
@@ -3466,17 +3504,14 @@
         case AXPressedStateChanged:
         case AXSelectedChildrenChanged:
         case AXTextChanged:
-        case AXValueChanged: {
-            auto updatedFields = updatedObjects.get(notification.first->objectID());
-            if (!updatedFields.node) {
-                updatedObjects.set(notification.first->objectID(), UpdatedFields { updatedFields.children, true });
-                tree->updateNode(*notification.first);
-            }
+        case AXValueChanged:
+            updateNode(notification.first);
             break;
-        }
+        case AXRowCountChanged:
+            updateNode(notification.first);
+            FALLTHROUGH;
         case AXChildrenChanged:
         case AXLanguageChanged:
-        case AXRowCountChanged:
         case AXRowCollapsed:
         case AXRowExpanded: {
             auto updatedFields = updatedObjects.get(notification.first->objectID());

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.h (294874 => 294875)


--- trunk/Source/WebCore/accessibility/AXObjectCache.h	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.h	2022-05-26 11:40:09 UTC (rev 294875)
@@ -464,6 +464,7 @@
     void handleMenuOpened(Node*);
     void handleLiveRegionCreated(Node*);
     void handleMenuItemSelected(Node*);
+    void handleRowCountChanged(AXCoreObject*, Document*);
     void handleAttributeChange(const QualifiedName&, Element*);
     bool shouldProcessAttributeChange(const QualifiedName&, Element*);
     void selectedChildrenChanged(Node*);
@@ -527,6 +528,7 @@
 
     AXTextStateChangeIntent m_textSelectionIntent;
     WeakHashSet<Element> m_deferredRecomputeIsIgnoredList;
+    WeakHashSet<HTMLTableElement> m_deferredRecomputeTableIsExposedList;
     ListHashSet<Node*> m_deferredTextChangedList;
     WeakHashSet<Element> m_deferredSelectedChildredChangedList;
     ListHashSet<RefPtr<AccessibilityObject>> m_deferredChildrenChangedList;

Modified: trunk/Source/WebCore/accessibility/AccessibilityTable.cpp (294874 => 294875)


--- trunk/Source/WebCore/accessibility/AccessibilityTable.cpp	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/Source/WebCore/accessibility/AccessibilityTable.cpp	2022-05-26 11:40:09 UTC (rev 294875)
@@ -362,6 +362,31 @@
     return isDataTable();
 }
 
+
+void AccessibilityTable::recomputeIsExposable()
+{
+    bool previouslyExposable = m_isExposable;
+    m_isExposable = computeIsTableExposableThroughAccessibility();
+    if (previouslyExposable != m_isExposable) {
+        // A table's role value is dependent on whether it's exposed, so notify the cache this has changed.
+        if (auto* cache = axObjectCache())
+            cache->handleRoleChange(this);
+
+        // Before resetting our existing children, possibly losing references to them, ensure we update their role (since a table cell's role is dependent on whether its parent table is exposable).
+        updateChildrenRoles();
+
+        m_childrenDirty = true;
+    }
+}
+
+void AccessibilityTable::updateChildrenRoles()
+{
+    for (const auto& row : m_rows) {
+        for (const auto& cell : row->children())
+            downcast<AccessibilityObject>(*cell).updateRole();
+    }
+}
+
 void AccessibilityTable::clearChildren()
 {
     AccessibilityRenderObject::clearChildren();
@@ -427,10 +452,7 @@
     // determines whether it is an accessibility table. Iterate all the cells and allow them to
     // update their roles now that the table knows its status.
     // 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).updateRole();
-    }
+    updateChildrenRoles();
 }
 
 void AccessibilityTable::addTableCellChild(AccessibilityObject* rowObject, HashSet<AccessibilityObject*>& appendedRows, unsigned& columnCount)

Modified: trunk/Source/WebCore/accessibility/AccessibilityTable.h (294874 => 294875)


--- trunk/Source/WebCore/accessibility/AccessibilityTable.h	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/Source/WebCore/accessibility/AccessibilityTable.h	2022-05-26 11:40:09 UTC (rev 294875)
@@ -49,6 +49,7 @@
 
     void addChildren() override;
     void clearChildren() final;
+    void updateChildrenRoles();
 
     AccessibilityChildrenVector columns() override;
     AccessibilityChildrenVector rows() override;
@@ -73,6 +74,7 @@
     bool isTable() const override { return true; }
     // Returns whether it is exposed as an AccessibilityTable to the platform.
     bool isExposable() const override;
+    void recomputeIsExposable();
 
     int axColumnCount() const override;
     int axRowCount() const override;

Modified: trunk/Source/WebCore/html/HTMLTablePartElement.h (294874 => 294875)


--- trunk/Source/WebCore/html/HTMLTablePartElement.h	2022-05-26 11:05:03 UTC (rev 294874)
+++ trunk/Source/WebCore/html/HTMLTablePartElement.h	2022-05-26 11:40:09 UTC (rev 294875)
@@ -33,6 +33,9 @@
 
 class HTMLTablePartElement : public HTMLElement {
     WTF_MAKE_ISO_ALLOCATED(HTMLTablePartElement);
+public:
+    RefPtr<const HTMLTableElement> findParentTable() const;
+
 protected:
     HTMLTablePartElement(const QualifiedName& tagName, Document& document)
         : HTMLElement(tagName, document)
@@ -41,8 +44,6 @@
 
     bool hasPresentationalHintsForAttribute(const QualifiedName&) const override;
     void collectPresentationalHintsForAttribute(const QualifiedName&, const AtomString&, MutableStyleProperties&) override;
-
-    RefPtr<const HTMLTableElement> findParentTable() const;
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to