LibWeb: Ignore name-required landmark roles which lack accessible names

This change implements the role-checking requirement from the ARIA spec
at https://w3c.github.io/aria/#document-handling_author-errors_roles
that the"form" and "region" roles are required to have accessible names,
and that if they do not have accessible names as required, UAs must
treat them as if they’d not be specified at all.
This commit is contained in:
sideshowbarker 2024-12-19 23:34:18 +09:00
parent 02d18109a1
commit fe2408c44b
No known key found for this signature in database
7 changed files with 152 additions and 0 deletions

View file

@ -7,6 +7,7 @@
#include <LibWeb/ARIA/ARIAMixin.h>
#include <LibWeb/ARIA/Roles.h>
#include <LibWeb/DOM/Element.h>
#include <LibWeb/DOM/Node.h>
#include <LibWeb/Infra/CharacterTypes.h>
namespace Web::ARIA {
@ -130,6 +131,14 @@ Optional<Role> ARIAMixin::role_from_role_attribute_value() const
}
continue;
}
// https://w3c.github.io/aria/#document-handling_author-errors_roles
// Certain landmark roles require names from authors. In situations where an author has not specified names for
// these landmarks, it is considered an authoring error. The user agent MUST treat such elements as if no role
// had been provided. If a valid fallback role had been specified, or if the element had an implicit ARIA role,
// then user agents would continue to expose that role, instead.
if ((role == ARIA::Role::form || role == ARIA::Role::region)
&& to_element()->accessible_name(to_element()->document(), DOM::ShouldComputeRole::No).value().is_empty())
continue;
// 4. Use the first such substring in textual order that matches the name of a non-abstract WAI-ARIA role.
if (!is_abstract_role(*role))
return *role;

View file

@ -0,0 +1,17 @@
Harness status: OK
Found 12 tests
12 Pass
Pass fallback role w/ region with no label
Pass fallback role w/ region with label
Pass aria 1.1 switch role w/ fallback to aria 1.0 checkbox role
Pass div[role=button] ignoring invalid foo role token
Pass unknown[role=button] ignoring invalid foo role token
Pass button ignoring single invalid role token
Pass button ignoring multiple invalid role tokens
Pass div[role=button] ignoring invalid foo role token including punctuation-contaminated known link role
Pass div[role=button] ignoring invalid unicode diacritics etc on link and group role tokens
Pass div[role=button] ignoring tab char
Pass div[role=button] ignoring line break
Pass div[role=button] ignoring braille whitespace char

View file

@ -0,0 +1,7 @@
Harness status: OK
Found 2 tests
2 Pass
Pass form without label
Pass form with label

View file

@ -0,0 +1,7 @@
Harness status: OK
Found 2 tests
2 Pass
Pass region without label
Pass region with label

View file

@ -0,0 +1,57 @@
<!doctype html>
<html>
<head>
<title>Fallback 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/#host_general_role">8.1 Role Attribute</a> role token list selection and <a href="https://w3c.github.io/aria/#document-handling_author-errors_roles">9.1 Roles - handling author errors</a>.</p>
<!-- known el and two known ARIA 1.0 roles -->
<nav role="region group" data-testname="fallback role w/ region with no label" data-expectedrole="group" class="ex">x</nav>
<nav role="region group" data-testname="fallback role w/ region with label" aria-label="x" data-expectedrole="region" class="ex">x</nav>
<!-- known el and known ARIA 1.1 with 1.0 role backup -->
<div role="switch checkbox" aria-checked="true" data-testname="aria 1.1 switch role w/ fallback to aria 1.0 checkbox role" aria-label="x" data-expectedrole="switch" class="ex">x</div>
<!-- known el and invalid role token with valid backup -->
<div role="foo button" data-testname="div[role=button] ignoring invalid foo role token" aria-label="x" data-expectedrole="button" class="ex">x</div>
<!-- unknown el and invalid role token with valid backup -->
<unknown role="foo button" data-testname="unknown[role=button] ignoring invalid foo role token" aria-label="x" data-expectedrole="button" class="ex">x</unknown>
<!-- known el and invalid role(s) -->
<button role="foo" data-testname="button ignoring single invalid role token" aria-label="x" data-expectedrole="button" class="ex">x</unknown>
<button role="foo bar" data-testname="button ignoring multiple invalid role tokens" aria-label="x" data-expectedrole="button" class="ex">x</unknown>
<!-- known el with invalid punctuation -->
<div role="invalid, punctuation, tests, link, button" data-testname="div[role=button] ignoring invalid foo role token including punctuation-contaminated known link role" aria-label="x" data-expectedrole="button" class="ex">x</div>
<!-- extra line breaks here to account for rendering of unicode diacritic etc char glitch tests -->
<div role="l̷̨̢̡̖̻̗̤̺̟̱͚͔͇͍͇̫̫̜͔̗̟̘̫̟̰̼̘͗̌̃͐̔̈́̚͝į̵̡̲̯̠̮͈͖̥̮̲͓̦̗̗̱̞͍̗̪͙͇͚͂̍͐̔̍͌̐̇̏̎͘͝ǹ̶̨̧̢̜̲̫͇̮͉̬͎͎͕̝̱͔̙̱̦̰̦̠̰̣̝͂̓̋̊͜ķ̷̧̧̨̨̨̘̳͕̰͎̮̠̘̪͇͕̥̭̼̼̜̤̫̥̼̤̰̦͖̪̀͒̆͑̒̅͑̓̒͂̽̈́̽̉̀̕͘͜͝ ̷̡̮̦̘͓̫̜͕͖̰̙̘͓̼͎̳̹͇̮͐͂́͛̃́̊̈͌̄̓̌̂̈̇̀̌̈́́̀̈́̍̈́̇̄̊̔͒̾̾̇́͒̽͂̾̕̚͜͜͝͠ͅͅg̸̨̧̧̧̧̛̺̦̣͇͈͙͇͎͕̠̞̳̹̣͋͑̑̓͛̓̉̔̉͑̇́̈́̉̃́̑̍̂̒͐͛͗̑̏̓̾͌̈̅́̇̕̕̚̚͝͝ͅr̶̛̤̲̘̮̟̭̲̋̾̀́́̒̀̀͑̎̀̌̈̀̍̂̏̊̎͐͒͗͗̀͘͘͘͠͠ȍ̴̧̡̢̡̢̞̝̠̙̬̗͍͍͉̺͔͙̫̝̰̮̜̩̙̳͉̻̻̼͍̊͋͐̐͆̈̿̒̊̄͑̈́̔͋̔̃͐̓̓͛́͊̉͑̊̔͆͘͘͜͠ͅu̴̱̯̞̞̞̺̼̳̳͚̞̇̈͒͠p̶̛͉̮̙̯̮̱͉̖͚͉̩̱̺̩̦̺͈̫͍͔̲̣̗̟̜̂̐̌̏͌̈́͗̾͌̿̓͒̋̆͆̾͛̐̈́̓͋̀͘̚͝͝͝ ̶͔͚̩̬͈̍̈́͗͐̀̊̏͛̃̈́͋̅͝ button" data-testname="div[role=button] ignoring invalid unicode diacritics etc on link and group role tokens" aria-label="x" data-expectedrole="button" class="ex">x</div>
<!-- known el and known role with whitespace edge cases -->
<div role=" button" data-testname="div[role=button] ignoring tab char" aria-label="x" data-expectedrole="button" class="ex">x</div>
<div role="
button" data-testname="div[role=button] ignoring line break" aria-label="x" data-expectedrole="button" class="ex">x</div>
<div role=" button" data-testname="div[role=button] ignoring braille whitespace char" aria-label="x" data-expectedrole="button" class="ex">x</div>
<script>
AriaUtils.verifyRolesBySelector(".ex");
</script>
</body>
</html>

View file

@ -0,0 +1,28 @@
<!doctype html>
<html>
<head>
<title>Form 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>Verifies <a href="https://w3c.github.io/aria/#document-handling_author-errors_roles">9.1 Roles - handling author errors</a> and the <a href="https://w3c.github.io/aria/#form">form</a> role.</p>
<!-- no label -->
<nav role="form" data-testname="form without label" data-expectedrole="navigation" class="ex">x</nav>
<!-- w/ label -->
<nav role="form" data-testname="form with label" data-expectedrole="form" aria-label="x" class="ex">x</nav>
<script>
AriaUtils.verifyRolesBySelector(".ex");
</script>
</body>
</html>

View file

@ -0,0 +1,27 @@
<!doctype html>
<html>
<head>
<title>Region 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/#region">region</a> and related roles, as well as the "name from author" rule in <a href="https://w3c.github.io/aria/#document-handling_author-errors_roles">9.1 Roles - handling author errors</a>.</p>
<!-- no label -->
<nav role="region" data-testname="region without label" data-expectedrole="navigation" class="ex">x</nav>
<!-- w/ label -->
<nav role="region" data-testname="region with label" data-expectedrole="region" aria-label="x" class="ex">x</nav>
<script>
AriaUtils.verifyRolesBySelector(".ex");
</script>
</body>
</html>