From ed7ec7a0f842684ca51544a56030c4c752e76c3f Mon Sep 17 00:00:00 2001 From: sideshowbarker Date: Sat, 16 Nov 2024 18:02:10 +0900 Subject: [PATCH] LibWeb: Fix accname computation for all aria-labelledby cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- Libraries/LibWeb/DOM/Node.cpp | 22 ++++++- .../accname/name/comp_labelledby.txt | 13 ++++ .../accname/name/comp_labelledby.html | 60 +++++++++++++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/wpt-import/accname/name/comp_labelledby.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/accname/name/comp_labelledby.html diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index b820b16457b..051dd37c8b9 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -2195,6 +2195,18 @@ ErrorOr Node::name_or_description(NameOrDescription target, Document con if (is_element()) { auto const* element = static_cast(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([&](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 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 doesn’t 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 won’t 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 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 diff --git a/Tests/LibWeb/Text/expected/wpt-import/accname/name/comp_labelledby.txt b/Tests/LibWeb/Text/expected/wpt-import/accname/name/comp_labelledby.txt new file mode 100644 index 00000000000..894bad70f80 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/accname/name/comp_labelledby.txt @@ -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 \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/accname/name/comp_labelledby.html b/Tests/LibWeb/Text/input/wpt-import/accname/name/comp_labelledby.html new file mode 100644 index 00000000000..e22612d2cb2 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/accname/name/comp_labelledby.html @@ -0,0 +1,60 @@ + + + + Name Comp: Labelledby + + + + + + + + + +

Tests the #comp_labelledby portions of the AccName Name Computation algorithm.

+ + + +
+

first heading

+

text inside div group

+
+ +
+

+ first heading

+

text inside div group

+
+ + + + + + + + \ No newline at end of file