LibWeb: Align default “th” and “td” roles with HTML-AAM spec and tests

This change aligns the default roles for “th” and “td” elements with the
requirements in the HTML-AAM spec, and with the corresponding WPT tests
at https://wpt.fyi/results/html-aam/table-roles.html, and with the
behavior in other engines.

Otherwise, without this change, the default role values for “th” and
“td” elements in some cases don’t match the behavior in other engines,
and don’t match the expected results for the corresponding WPT tests.
This commit is contained in:
sideshowbarker 2024-12-07 18:21:31 +09:00 committed by Andrew Kaster
parent 2d638485a8
commit e49fe384d1
Notes: github-actions[bot] 2024-12-12 00:02:47 +00:00
5 changed files with 252 additions and 10 deletions

View file

@ -196,16 +196,31 @@ WebIDL::Long HTMLTableCellElement::cell_index() const
Optional<ARIA::Role> HTMLTableCellElement::default_role() const
{
// TODO: For td:
// role=cell if the ancestor table element is exposed as a role=table
// role=gridcell if the ancestor table element is exposed as a role=grid or treegrid
// No corresponding role if the ancestor table element is not exposed as a role=table, grid or treegrid
// For th:
// role=columnheader, rowheader or cell if the ancestor table element is exposed as a role=table
// role=columnheader, rowheader or gridcell if the ancestor table element is exposed as a role=grid or treegrid
// No corresponding role if the ancestor table element is not exposed as a role=table, grid or treegrid
// https://www.w3.org/TR/html-aria/#el-td
// https://www.w3.org/TR/html-aria/#el-th
if (local_name() == TagNames::th) {
for (auto const* ancestor = parent_element(); ancestor; ancestor = ancestor->parent_element()) {
// AD-HOC: The ancestor checks here arent explicitly defined in the spec, but implicitly follow from what
// the spec does state, and from the physical placement/layout of elements. Also, the el-th and el-th-in-row
// tests at https://wpt.fyi/results/html-aam/table-roles.html require doing these ancestor checks — and
// implementing them causes the behavior to match that of other engines.
// https://w3c.github.io/html-aam/#el-th-columnheader
if (get_attribute(HTML::AttributeNames::scope) == "columnheader" || ancestor->local_name() == TagNames::thead)
return ARIA::Role::columnheader;
// https://w3c.github.io/html-aam/#el-th-rowheader
if (get_attribute(HTML::AttributeNames::scope) == "rowheader" || ancestor->local_name() == TagNames::tbody)
return ARIA::Role::rowheader;
}
}
auto const* table_element = first_ancestor_of_type<HTMLTableElement>();
// https://w3c.github.io/html-aam/#el-td
// https://w3c.github.io/html-aam/#el-th/
// (ancestor table element has table role)
if (table_element->role_or_default() == ARIA::Role::table)
return ARIA::Role::cell;
// https://w3c.github.io/html-aam/#el-td-gridcell
// https://w3c.github.io/html-aam/#el-th-gridcell
// (ancestor table element has grid or treegrid role)
if (first_is_one_of(table_element->role_or_default(), ARIA::Role::grid, ARIA::Role::gridcell))
return ARIA::Role::gridcell;
return {};
}

View file

@ -0,0 +1,12 @@
Harness status: OK
Found 7 tests
7 Pass
Pass el-table
Pass el-caption
Pass el-tr-thead
Pass el-th
Pass el-tr-tbody
Pass el-th-in-row
Pass el-td

View file

@ -0,0 +1,14 @@
Harness status: OK
Found 9 tests
9 Pass
Pass div role is caption (in div with table role)
Pass orphan p role is caption
Pass span role is cell (in div with row role, in div with rowgroup role, in div with table role)
Pass orphan span role is cell
Pass span role is columnheader (in div with row role, in div with rowgroup role, in div with table role)
Pass div role is row (in div with rowgroup role, in div with table role)
Pass div role is rowgroup (in div with table role)
Pass role is rowheader (in div with row role, in div with rowgroup role, in div with table role)
Pass div role is table

View file

@ -0,0 +1,53 @@
<!doctype html>
<html>
<head>
<title>HTML-AAM Role Verification Tests</title>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<script src="../resources/testdriver.js"></script>
<script src="../resources/testdriver-vendor.js"></script>
<script src="../resources/testdriver-actions.js"></script>
<script src="../wai-aria/scripts/aria-utils.js"></script>
</head>
<body>
<p>Tests the computedrole mappings for the table-related roles defined in <a href="https://w3c.github.io/html-aam/">HTML-AAM</a>. Most test names correspond to unique ID defined in the spec.<p>
<!-- ARIA table roles tested in wpt/wai-aria/role/table-roles.html -->
<table data-testname="el-table" data-expectedrole="table" class="ex">
<caption data-testname="el-caption" data-expectedrole="caption" class="ex">caption</caption>
<thead>
<tr data-testname="el-tr-thead" data-expectedrole="row" class="ex">
<th data-testname="el-th" data-expectedrole="columnheader" class="ex">a</th>
<th>b</th>
<th>c</th>
</tr>
</thead>
<tbody>
<tr data-testname="el-tr-tbody" data-expectedrole="row" class="ex">
<th data-testname="el-th-in-row" data-expectedrole="rowheader" class="ex">1</th>
<td data-testname="el-td" data-expectedrole="cell" class="ex">2</td>
<td>3</td>
</tr>
<tr>
<th>4</th>
<td>5</td>
<td>6</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>x</th>
<th>y</th>
<th>z</th>
</tr>
</tfoot>
</table>
<script>
AriaUtils.verifyRolesBySelector(".ex");
</script>
</body>
</html>

View file

@ -0,0 +1,148 @@
<!doctype html>
<html>
<head>
<title>Table Role Verification Tests</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../resources/testdriver.js"></script>
<script src="../../resources/testdriver-vendor.js"></script>
<script src="../../resources/testdriver-actions.js"></script>
<script src="../../wai-aria/scripts/aria-utils.js"></script>
</head>
<body>
<p>Tests <a href="https://w3c.github.io/aria/#table">table</a> and related roles.</p>
<!-- HTML <table> Elements Testing -->
<!-- <caption> -> wpt/html-aam/table-roles.html -->
<!-- <table> -> wpt/html-aam/table-roles.html -->
<!-- <tbody> -> wpt/html-aam/table-roles.html -->
<!-- <td> -> wpt/html-aam/table-roles.html -->
<!-- <tfoot> -> wpt/html-aam/table-roles.html -->
<!-- <th> -> wpt/html-aam/table-roles.html -->
<!-- <thead> -> wpt/html-aam/table-roles.html -->
<!-- <tr> -> wpt/html-aam/table-roles.html -->
<!-- ARIA Grid Elements Testing -->
<!-- Grid roles tested in ./grid-roles.html -->
<!-- ARIA Table Roles Testing -->
<!-- caption -->
<div role="table">
<div role="caption" data-testname="div role is caption (in div with table role)" data-expectedrole="caption" class="ex">x</div>
</div>
<p role="caption" data-testname="orphan p role is caption" data-expectedrole="caption" class="ex">x</p>
<!-- cell -->
<div role="table">
<div role="rowgroup">
<div role="row">
<span role="columnheader">x</span>
<span role="columnheader">x</span>
</div>
</div>
<div role="rowgroup">
<div role="row">
<span role="cell" data-testname="span role is cell (in div with row role, in div with rowgroup role, in div with table role)" data-expectedrole="cell" class="ex">x</span>
<span role="cell">x</span>
</div>
</div>
</div>
<span role="cell" data-testname="orphan span role is cell" data-expectedrole="cell" class="ex">x</span>
<!-- columnheader -->
<div role="table">
<div role="rowgroup">
<div role="row">
<span role="columnheader" data-testname="span role is columnheader (in div with row role, in div with rowgroup role, in div with table role)" data-expectedrole="columnheader" class="ex">x</span>
<span role="columnheader">x</span>
<span role="columnheader">x</span>
</div>
</div>
<div role="rowgroup">
<div role="row">
<span role="rowheader">x</span>
<span role="cell">x</span>
<span role="cell">x</span>
</div>
</div>
</div>
<!-- row -->
<div role="table">
<div role="rowgroup">
<div role="row" data-testname="div role is row (in div with rowgroup role, in div with table role)" data-expectedrole="row" class="ex">
<span role="columnheader">x</span>
</div>
</div>
<div role="rowgroup">
<div role="row">
<span role="cell">x</span>
</div>
</div>
</div>
<!-- rowgroup -->
<div role="table">
<div role="rowgroup" data-testname="div role is rowgroup (in div with table role)" data-expectedrole="rowgroup" class="ex">
<div role="row">
<span role="columnheader">x</span>
<span role="columnheader">x</span>
</div>
</div>
<div role="rowgroup">
<div role="row">
<span role="cell">x</span>
<span role="cell">x</span>
</div>
</div>
</div>
<!-- rowheader -->
<div role="table">
<div role="rowgroup">
<div role="row">
<span role="columnheader">x</span>
<span role="columnheader">x</span>
<span role="columnheader">x</span>
</div>
</div>
<div role="rowgroup">
<div role="row">
<span role="rowheader" data-testname="role is rowheader (in div with row role, in div with rowgroup role, in div with table role)" data-expectedrole="rowheader" class="ex">x</span>
<span role="cell">x</span>
<span role="cell">x</span>
<span role="cell">x</span>
</div>
</div>
</div>
<!-- table -->
<div role="table" data-testname="div role is table" data-expectedrole="table" class="ex">
<div role="row">
<span role="columnheader">x</span>
<span role="columnheader">x</span>
</div>
<div role="row">
<span role="cell">x</span>
<span role="cell">x</span>
</div>
</div>
<script>
AriaUtils.verifyRolesBySelector(".ex");
</script>
</body>
</html>