Bug 1749505: Implement conditional role mapping for aside element, r=Jamie

This revision implements the HTML-AAM spec's rules for role mapping of the aside
element. The aside element might be either 'complementary' or 'generic'
depending on the ancestor and presence of accessible name. This revision
implements these rules via a new class, HTMLAsideAccessible, which has a
NativeRole override. This revision also updates the HTMLMarkupMap to map HTML
aside elements to HTMLAsideAccessible. Finally, this revision removes related
expected failures from web platform tests.

Differential Revision: https://phabricator.services.mozilla.com/D203192
This commit is contained in:
Nathan LaPre 2024-03-04 18:55:09 +00:00
parent 13906c252f
commit 329ac88f51
5 changed files with 53 additions and 17 deletions

View File

@ -34,7 +34,12 @@ MARKUPMAP(address, New_HyperText, roles::GROUPING)
MARKUPMAP(article, New_HyperText, roles::ARTICLE, Attr(xmlroles, article))
MARKUPMAP(aside, New_HyperText, roles::LANDMARK)
MARKUPMAP(
aside,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
return new HTMLAsideAccessible(aElement, aContext->Document());
},
0)
MARKUPMAP(blockquote, New_HyperText, roles::BLOCKQUOTE)

View File

@ -220,6 +220,35 @@ role HTMLHeaderOrFooterAccessible::NativeRole() const {
return roles::SECTION;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLAsideAccessible
////////////////////////////////////////////////////////////////////////////////
role HTMLAsideAccessible::NativeRole() const {
// Per the HTML-AAM spec, there are two cases for aside elements:
// 1. scoped to body or main elements -> 'complementary' role
// 2. scoped to sectioning content elements
// -> if the element has an accessible name, 'complementary' role
// -> otherwise, 'generic' role
// To implement this, walk ancestors until we find a sectioning content
// element, or a body/main element, then take actions based on the rules
// above.
nsIContent* parent = mContent->GetParent();
while (parent) {
if (parent->IsAnyOfHTMLElements(nsGkAtoms::article, nsGkAtoms::aside,
nsGkAtoms::nav, nsGkAtoms::section)) {
return !NameIsEmpty() ? roles::LANDMARK : roles::SECTION;
}
if (parent->IsAnyOfHTMLElements(nsGkAtoms::main, nsGkAtoms::body)) {
return roles::LANDMARK;
}
parent = parent->GetParent();
}
// Fall back to landmark, though we always expect to find a body element.
return roles::LANDMARK;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLSectionAccessible
////////////////////////////////////////////////////////////////////////////////

View File

@ -135,6 +135,23 @@ class HTMLHeaderOrFooterAccessible : public HyperTextAccessible {
virtual ~HTMLHeaderOrFooterAccessible() {}
};
/**
* Used for aside elements.
*/
class HTMLAsideAccessible : public HyperTextAccessible {
public:
HTMLAsideAccessible(nsIContent* aContent, DocAccessible* aDoc)
: HyperTextAccessible(aContent, aDoc) {}
NS_INLINE_DECL_REFCOUNTING_INHERITED(HTMLAsideAccessible, HyperTextAccessible)
// LocalAccessible
virtual a11y::role NativeRole() const override;
protected:
virtual ~HTMLAsideAccessible() = default;
};
/**
* Used for HTML section element.
*/

View File

@ -161,7 +161,7 @@
id="nav_overflow">overflow nav</nav>
<header style="overflow: hidden;"
id="header_overflow">overflow header</header>
<aside style="overflow: hidden;"
<aside style="overflow: hidden;" aria-label="aside"
id="aside_overflow">overflow aside</aside>
<footer style="overflow: hidden;"
id="footer_overflow">overflow footer</footer>

View File

@ -1,15 +0,0 @@
[roles-contextual.html]
[el-aside-in-article-in-main]
expected: FAIL
[el-aside-in-article]
expected: FAIL
[el-aside-in-aside]
expected: FAIL
[el-aside-in-nav]
expected: FAIL
[el-aside-in-section]
expected: FAIL