Skip to content
Permalink
Browse files
AccessibilityTable::m_isExposable is never recomputed after Accessibi…
…lityTable::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
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@294875 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
twilco committed May 26, 2022
1 parent aafbf50 commit 14c287919c3eae72e00b244b4e47d69e322e9d11
Showing 13 changed files with 263 additions and 70 deletions.
@@ -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
@@ -1,9 +1,10 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/js-test-pre.js"></script>
<script src="../resources/accessibility-helper.js"></script>
<script src="../resources/js-test.js"></script>
</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>

description("This tests that attributes related to aria table/grid are working correctly.");
var testOutput = "This tests that attributes related to aria table/grid are working correctly.\n\n";

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");

</script>
// 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}'");

<script src="../resources/js-test-post.js"></script>
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>
</body>
</html>

@@ -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

@@ -0,0 +1,66 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../resources/js-test.js"></script>
<script src="../resources/accessibility-helper.js"></script>
</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>

@@ -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

@@ -2114,6 +2114,7 @@ webkit.org/b/148806 imported/w3c/web-platform-tests/css/css-multicol/multicol-sp
# 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 ]
@@ -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

@@ -459,6 +459,9 @@ fast/events/mouseover-button.html [ Skip ]
# 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 ]

0 comments on commit 14c2879

Please sign in to comment.