mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-31 13:19:05 +00:00
LibWeb: Compute default ARIA roles for SVG elements
This change adds support for computing default ARIA roles for (selected) SVG elements, per the requirements in the SVG Accessibility API Mappings spec at https://w3c.github.io/svg-aam/#mapping_role_table. This only computes roles for the elements which are covered in the WPT test at https://wpt.fyi/results/svg-aam/role/roles.html — that is, the “a”, “g”, and “image” elements.
This commit is contained in:
parent
f3e92f2ae5
commit
f2ac591614
Notes:
github-actions[bot]
2024-12-25 10:59:46 +00:00
Author: https://github.com/sideshowbarker
Commit: f2ac591614
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3033
Reviewed-by: https://github.com/tcl3 ✅
4 changed files with 153 additions and 0 deletions
|
@ -11,8 +11,10 @@
|
|||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
#include <LibWeb/SVG/SVGDescElement.h>
|
||||
#include <LibWeb/SVG/SVGElement.h>
|
||||
#include <LibWeb/SVG/SVGSVGElement.h>
|
||||
#include <LibWeb/SVG/SVGTitleElement.h>
|
||||
#include <LibWeb/SVG/SVGUseElement.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
@ -28,6 +30,38 @@ void SVGElement::initialize(JS::Realm& realm)
|
|||
WEB_SET_PROTOTYPE_FOR_INTERFACE(SVGElement);
|
||||
}
|
||||
|
||||
bool SVGElement::should_include_in_accessibility_tree() const
|
||||
{
|
||||
bool has_title_or_desc = false;
|
||||
auto role = role_from_role_attribute_value();
|
||||
for_each_child_of_type<SVGElement>([&has_title_or_desc](auto& child) {
|
||||
if ((is<SVGTitleElement>(child) || is<SVGDescElement>(child)) && !child.text_content()->trim_ascii_whitespace().value().is_empty()) {
|
||||
has_title_or_desc = true;
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
// https://w3c.github.io/svg-aam/#include_elements
|
||||
// TODO: Add support for the SVG tabindex attribute, and include a check for it here.
|
||||
return has_title_or_desc
|
||||
|| (aria_label().has_value() && !aria_label().value().trim_ascii_whitespace().value().is_empty())
|
||||
|| (aria_labelled_by().has_value() && !aria_labelled_by().value().trim_ascii_whitespace().value().is_empty())
|
||||
|| (aria_described_by().has_value() && !aria_described_by().value().trim_ascii_whitespace().value().is_empty())
|
||||
|| (role.has_value() && ARIA::is_abstract_role(role.value()) && role != ARIA::Role::none && role != ARIA::Role::presentation);
|
||||
}
|
||||
|
||||
Optional<ARIA::Role> SVGElement::default_role() const
|
||||
{
|
||||
// https://w3c.github.io/svg-aam/#mapping_role_table
|
||||
if (local_name() == TagNames::a && (has_attribute(SVG::AttributeNames::href) || has_attribute(AttributeNames::xlink_href)))
|
||||
return ARIA::Role::link;
|
||||
if (local_name() == TagNames::g && should_include_in_accessibility_tree())
|
||||
return ARIA::Role::group;
|
||||
if (local_name() == TagNames::image && should_include_in_accessibility_tree())
|
||||
return ARIA::Role::image;
|
||||
return {};
|
||||
}
|
||||
|
||||
void SVGElement::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
|
|
|
@ -25,6 +25,9 @@ public:
|
|||
GC::Ref<SVGAnimatedString> class_name();
|
||||
GC::Ptr<SVGSVGElement> owner_svg_element();
|
||||
|
||||
bool should_include_in_accessibility_tree() const;
|
||||
virtual Optional<ARIA::Role> default_role() const override;
|
||||
|
||||
protected:
|
||||
SVGElement(DOM::Document&, DOM::QualifiedName);
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 4 tests
|
||||
|
||||
4 Pass
|
||||
Pass el-a[href]
|
||||
Pass el-a[xlink:href]
|
||||
Pass el-g
|
||||
Pass el-image
|
107
Tests/LibWeb/Text/input/wpt-import/svg-aam/role/roles.html
Normal file
107
Tests/LibWeb/Text/input/wpt-import/svg-aam/role/roles.html
Normal file
|
@ -0,0 +1,107 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SVG-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 mappings defined in <a href="https://w3c.github.io/svg-aam/#mapping_role_table">SVG-AAM: 6.2 Element Mapping</a>.<p>
|
||||
|
||||
<h2>Simple Elements With aria-label to Ensure Tree Inclusion</h2>
|
||||
<svg>
|
||||
<!-- Some elements skipped: never-rendered elements can return unpredicable/undefined/unspecified values for computedrole. -->
|
||||
<a href="#" data-testname="el-a[href]" data-expectedrole="link" aria-label="label" class="ex">x</a>
|
||||
<a xlink:href="#" data-testname="el-a[xlink:href]" data-expectedrole="link" aria-label="label" class="ex">x</a>
|
||||
<!-- skipped: animate -->
|
||||
<!-- skipped: animateMotion -->
|
||||
<!-- skipped: animateTransform -->
|
||||
<!-- blocked: audio -> https://github.com/w3c/html-aam/issues/511 -->
|
||||
<!-- todo: canvas -> follow HTML -->
|
||||
<!-- blocked: circle -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- n/a: clipPath -->
|
||||
<!-- n/a: cursor -->
|
||||
<!-- n/a: defs -->
|
||||
<!-- n/a: desc -->
|
||||
<!-- n/a: discard -->
|
||||
<!-- blocked: ellipse -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- n/a: feBlend -->
|
||||
<!-- n/a: feColorMatrix -->
|
||||
<!-- n/a: feComponentTransfer -->
|
||||
<!-- n/a: feComposite -->
|
||||
<!-- n/a: feConvolveMatrix -->
|
||||
<!-- n/a: feDiffuseLighting -->
|
||||
<!-- n/a: feDisplacementMap -->
|
||||
<!-- n/a: feDistantLight -->
|
||||
<!-- n/a: feDropShadow -->
|
||||
<!-- n/a: feFlood -->
|
||||
<!-- n/a: feFuncA -->
|
||||
<!-- n/a: feFuncB -->
|
||||
<!-- n/a: feFuncG -->
|
||||
<!-- n/a: feFuncR -->
|
||||
<!-- n/a: feGaussianBlur -->
|
||||
<!-- n/a: feImage -->
|
||||
<!-- n/a: feMerge -->
|
||||
<!-- n/a: feMergeNode -->
|
||||
<!-- n/a: feMorphology -->
|
||||
<!-- n/a: feOffset -->
|
||||
<!-- n/a: fePointLight -->
|
||||
<!-- n/a: feSpecularLighting -->
|
||||
<!-- n/a: feSpotLight -->
|
||||
<!-- n/a: feTile -->
|
||||
<!-- n/a: feTurbulence -->
|
||||
<!-- n/a: filter -->
|
||||
<!-- todo: foreignObject (spec says `group` role if rendered and labeled) -->
|
||||
<g fill="white" stroke="green" stroke-width="2" data-testname="el-g" data-expectedrole="group" aria-label="label" class="ex">
|
||||
<circle cx="40" cy="40" r="25" />
|
||||
</g>
|
||||
<!-- n/a: hatch -->
|
||||
<!-- n/a: hatchPath -->
|
||||
<!-- todo: iframe -> follow HTML -->
|
||||
<image data-testname="el-image" data-expectedrole="image" aria-label="label" class="ex" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="></image>
|
||||
<!-- blocked: line -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- n/a: linearGradient -->
|
||||
<!-- n/a: marker -->
|
||||
<!-- n/a: mask -->
|
||||
<!-- todo: mesh (spec says `image` role if rendered and labeled) -->
|
||||
<!-- n/a: meshPatch -->
|
||||
<!-- n/a: meshRow -->
|
||||
<!-- n/a: metadata -->
|
||||
<!-- n/a: mpath -->
|
||||
<!-- blocked: path -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- n/a: pattern -->
|
||||
<!-- blocked: polygon -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- blocked: polyline -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- n/a: radialGradient -->
|
||||
<!-- blocked: rect -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- n/a: script -->
|
||||
<!-- n/a: set -->
|
||||
<!-- n/a: solidColor -->
|
||||
<!-- todo: source -> follow HTML -->
|
||||
<!-- n/a: stop -->
|
||||
<!-- n/a: style -->
|
||||
<!-- blocked: svg -> https://github.com/w3c/svg-aam/issues/18 -->
|
||||
<!-- n/a: switch -->
|
||||
<!-- blocked: symbol -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- blocked: text -> https://github.com/w3c/svg-aam/issues/33 -->
|
||||
<!-- blocked: textPath -> https://w3c.github.io/svg-aam/#textpath-tspan-mappings-issue-->
|
||||
<!-- n/a: title -->
|
||||
<!-- todo: track -> follow HTML -->
|
||||
<!-- blocked: tspan -> https://w3c.github.io/svg-aam/#textpath-tspan-mappings-issue -->
|
||||
<!-- blocked: use -> https://github.com/w3c/svg-aam/issues/24 -->
|
||||
<!-- todo: video -> follow HTML -->
|
||||
<!-- n/a: view -->
|
||||
</svg>
|
||||
|
||||
<script>
|
||||
AriaUtils.verifyRolesBySelector(".ex");
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue