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