LibWeb: Fix accname computation for all aria-labelledby cases

This change ensures that:

- if an element for which an accessible name otherwise wouldn’t be
  computed is referenced in an aria-labelledby value, the accessible
  name for the element will be computed as expected.

- if an element has both an aria-label value and also an
  aria-labelledby value, the text from the aria-label value gets
  included in the computation of the element’s accessible name.

Otherwise, without this change, some elements with aria-labelledby
values will unexpectedly end up without accessible names, and some
elements with aria-label values will unexpectedly not have that
aria-label value included in the element’s accessible name.
This commit is contained in:
sideshowbarker 2024-11-16 18:02:10 +09:00 committed by Andreas Kling
parent 13bd52249d
commit ed7ec7a0f8
Notes: github-actions[bot] 2024-11-16 17:22:31 +00:00
3 changed files with 93 additions and 2 deletions

View file

@ -2195,6 +2195,18 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
if (is_element()) {
auto const* element = static_cast<DOM::Element const*>(this);
auto role = element->role_or_default();
bool is_referenced = false;
auto id = element->id();
if (id.has_value()) {
this->root().for_each_in_inclusive_subtree_of_type<HTML::HTMLElement>([&](auto& element) {
auto aria_data = MUST(Web::ARIA::AriaData::build_data(element));
if (aria_data->aria_labelled_by_or_default().contains_slow(id.value())) {
is_referenced = true;
return TraversalDecision::Break;
}
return TraversalDecision::Continue;
});
}
// 2. Compute the text alternative for the current node:
// A. If the current node is hidden and is not directly referenced by aria-labelledby or aria-describedby, nor directly referenced by a native host language text alternative element (e.g. label in HTML) or attribute, return the empty string.
// FIXME: Check for references
@ -2224,7 +2236,13 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
auto node = document.get_element_by_id(MUST(FlyString::from_utf8(id_ref)));
if (!node)
continue;
// AD-HOC: The “For each IDREF” substep in the spec doesnt seem to explicitly require the following
// check for an aria-label value; but the “div group explicitly labelledby self and heading” subtest at
// https://wpt.fyi/results/accname/name/comp_labelledby.html wont pass unless we do this check.
if (target == NameOrDescription::Name && node->aria_label().has_value() && !node->aria_label()->is_empty() && !node->aria_label()->bytes_as_string_view().is_whitespace()) {
total_accumulated_text.append(' ');
total_accumulated_text.append(node->aria_label().value());
}
if (visited_nodes.contains(node->unique_id()))
continue;
// a. Set the current node to the node referenced by the IDREF.
@ -2333,7 +2351,7 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
}
// F. Otherwise, if the current node's role allows name from content, or if the current node is referenced by aria-labelledby, aria-describedby, or is a native host language text alternative element (e.g. label in HTML), or is a descendant of a native host language text alternative element:
if ((role.has_value() && ARIA::allows_name_from_content(role.value())) || is_descendant == IsDescendant::Yes) {
if ((role.has_value() && ARIA::allows_name_from_content(role.value())) || is_referenced || is_descendant == IsDescendant::Yes) {
// i. Set the accumulated text to the empty string.
total_accumulated_text.clear();
// ii. Name From Generated Content: Check for CSS generated textual content associated with the current node and include

View file

@ -0,0 +1,13 @@
Summary
Harness status: OK
Rerun
Found 3 tests
3 Pass
Details
Result Test Name MessagePass div group explicitly labelledby heading
Pass div group explicitly labelledby self and heading
Pass nav with verified spaces appended between each of IDREFS

View file

@ -0,0 +1,60 @@
<!doctype html>
<html>
<head>
<title>Name Comp: Labelledby</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 <a href="https://w3c.github.io/accname/#comp_labelledby">#comp_labelledby</a> portions of the AccName <em>Name Computation</em> algorithm.</p>
<!--
Some overlap with other aria-labelledby tests in:
- /accname/name/comp_label.html (aria-labelledby / aria-label fallback, etc.)
- /accname/name/comp_name_from_content.html
- /accname/name/shadowdom/*
-->
<div role="group" aria-labelledby="h" class="ex" data-expectedlabel="first heading" data-testname="div group explicitly labelledby heading">
<h2 id="h">first heading</h2>
<p>text inside div group</p>
</div>
<div role="group" aria-label="self label" id="g2" aria-labelledby="g2 h2" class="ex" data-expectedlabel="self label + first heading" data-testname="div group explicitly labelledby self and heading">
<h2 id="h2">+ first heading</h2>
<p>text inside div group</p>
</div>
<nav aria-labelledby="s1 s2 s3 s4" class="ex" data-expectedlabel="verify spaces between foreach" data-testname="nav with verified spaces appended between each of IDREFS">
<span id="s1">verify</span><span id="s2">spaces</span><span>FAIL IF INCLUDED</span><span id="s3">between</span><span id="s4">foreach</span>
</nav>
<!--
BLOCKED on https://github.com/w3c/accname/issues/209
Once that's resolved, it may be worthwhile to add a new ./comp_labelledby_recursion.html file,
so that the implementation diffs rolling in don't penalize this Interop 2024 test.
All remaining cases of https://w3c.github.io/accname/#comp_labelledby
- comp_labelledby_reset
- comp_labelledby_foreach
- comp_labelledby_set_current
- comp_labelledby_recursion
- comp_labelledby_append
- comp_labelledby_return
-->
<script>
AriaUtils.verifyLabelsBySelector(".ex");
</script>
</body>
</html>