mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1824935 part 3: Add Accessible::ComputedARIARole. r=eeejay
This also exposes this via XPCOM. This will be used by WebDriver and Dev Tools. Differential Revision: https://phabricator.services.mozilla.com/D175583
This commit is contained in:
parent
05cd652e5e
commit
888f2eec3d
@ -529,6 +529,47 @@ nsStaticAtom* Accessible::LandmarkRole() const {
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
nsStaticAtom* Accessible::ComputedARIARole() const {
|
||||
const nsRoleMapEntry* roleMap = ARIARoleMap();
|
||||
if (roleMap && roleMap->roleAtom != nsGkAtoms::_empty &&
|
||||
// region has its own Gecko role and it needs to be handled specially.
|
||||
roleMap->roleAtom != nsGkAtoms::region &&
|
||||
(roleMap->roleRule == kUseNativeRole || roleMap->IsOfType(eLandmark) ||
|
||||
roleMap->roleAtom == nsGkAtoms::alertdialog ||
|
||||
roleMap->roleAtom == nsGkAtoms::feed ||
|
||||
roleMap->roleAtom == nsGkAtoms::rowgroup ||
|
||||
roleMap->roleAtom == nsGkAtoms::searchbox)) {
|
||||
// Explicit ARIA role (e.g. specified via the role attribute) which does not
|
||||
// map to a unique Gecko role.
|
||||
return roleMap->roleAtom;
|
||||
}
|
||||
role geckoRole = Role();
|
||||
if (geckoRole == roles::LANDMARK) {
|
||||
// Landmark role from native markup; e.g. <main>, <nav>.
|
||||
return LandmarkRole();
|
||||
}
|
||||
if (geckoRole == roles::GROUPING) {
|
||||
// Gecko doesn't differentiate between group and rowgroup. It uses
|
||||
// roles::GROUPING for both.
|
||||
nsAtom* tag = TagName();
|
||||
if (tag == nsGkAtoms::tbody || tag == nsGkAtoms::tfoot ||
|
||||
tag == nsGkAtoms::thead) {
|
||||
return nsGkAtoms::rowgroup;
|
||||
}
|
||||
}
|
||||
// Role from native markup or layout.
|
||||
#define ROLE(_geckoRole, stringRole, ariaRole, atkRole, macRole, macSubrole, \
|
||||
msaaRole, ia2Role, androidClass, nameRule) \
|
||||
case roles::_geckoRole: \
|
||||
return ariaRole;
|
||||
switch (geckoRole) {
|
||||
#include "RoleMap.h"
|
||||
}
|
||||
#undef ROLE
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown role");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Accessible::ApplyImplicitState(uint64_t& aState) const {
|
||||
// nsAccessibilityService (and thus FocusManager) can be shut down before
|
||||
// RemoteAccessibles.
|
||||
|
@ -352,6 +352,13 @@ class Accessible {
|
||||
*/
|
||||
virtual void Language(nsAString& aLocale) = 0;
|
||||
|
||||
/**
|
||||
* Get the role of this Accessible as an ARIA role token. This might have been
|
||||
* set explicitly (e.g. role="button") or it might be implicit in native
|
||||
* markup (e.g. <button> returns "button").
|
||||
*/
|
||||
nsStaticAtom* ComputedARIARole() const;
|
||||
|
||||
// Methods that interact with content.
|
||||
|
||||
virtual void TakeFocus() const = 0;
|
||||
|
@ -345,6 +345,13 @@ interface nsIAccessible : nsISupports
|
||||
*/
|
||||
void announce(in AString announcement, in unsigned short priority);
|
||||
|
||||
/**
|
||||
* Get the role of this Accessible as an ARIA role token. This might have been
|
||||
* set explicitly (e.g. role="button") or it might be implicit in native
|
||||
* markup (e.g. <button> returns "button").
|
||||
*/
|
||||
readonly attribute AString computedARIARole;
|
||||
|
||||
[notxpcom, nostdcall] InternalLocalAccessible toInternalAccessible();
|
||||
[notxpcom, nostdcall] InternalAccessible toInternalGeneric();
|
||||
|
||||
|
@ -40,6 +40,7 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
"tests/browser/general/browser.ini",
|
||||
"tests/browser/hittest/browser.ini",
|
||||
"tests/browser/mac/browser.ini",
|
||||
"tests/browser/role/browser.ini",
|
||||
"tests/browser/scroll/browser.ini",
|
||||
"tests/browser/selectable/browser.ini",
|
||||
"tests/browser/states/browser.ini",
|
||||
|
11
accessible/tests/browser/role/browser.ini
Normal file
11
accessible/tests/browser/role/browser.ini
Normal file
@ -0,0 +1,11 @@
|
||||
[DEFAULT]
|
||||
subsuite = a11y
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/shared-head.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
!/accessible/tests/browser/*.mjs
|
||||
prefs =
|
||||
javascript.options.asyncstack_capture_debuggee_only=false
|
||||
|
||||
[browser_computedARIARole.js]
|
88
accessible/tests/browser/role/browser_computedARIARole.js
Normal file
88
accessible/tests/browser/role/browser_computedARIARole.js
Normal file
@ -0,0 +1,88 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="ariaButton" role="button">ARIA button</div>
|
||||
<div id="ariaLog" role="log">ARIA log</div>
|
||||
<div id="ariaMain" role="main">ARIA main</div>
|
||||
<div id="ariaRegion" role="region" aria-label="ARIA region">ARIA region</div>
|
||||
<nav id="ariaUnnamedRegion" role="region">ARIA unnamed region</nav>
|
||||
<div id="ariaDirectory" role="directory">ARIA directory</div>
|
||||
<div id="ariaAlertdialog" role="alertdialog">ARIA alertdialog</div>
|
||||
<div id="ariaFeed" role="feed">ARIA feed</div>
|
||||
<div id="ariaRowgroup" role="rowgroup">ARIA rowgroup</div>
|
||||
<div id="ariaSearchbox" role="searchbox">ARIA searchbox</div>
|
||||
<div id="ariaUnknown" role="unknown">unknown ARIA role</div>
|
||||
<button id="htmlButton">HTML button</button>
|
||||
<button id="toggleButton" aria-pressed="true">toggle button</button>
|
||||
<main id="htmlMain">HTML main</main>
|
||||
<header id="htmlHeader">HTML header</header>
|
||||
<section id="htmlSection">
|
||||
<header id="htmlSectionHeader">HTML header inside section</header>
|
||||
</section>
|
||||
<section id="htmlRegion" aria-label="HTML region">HTML region</section>
|
||||
<fieldset id="htmlFieldset">HTML fieldset</fieldset>
|
||||
<table>
|
||||
<tbody id="htmlTbody" tabindex="-1"><tr><th>HTML tbody</th></tr></tbody>
|
||||
</table>
|
||||
<table role="grid">
|
||||
<tr>
|
||||
<td id="htmlGridcell">HTML implicit gridcell</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div id="htmlDiv">HTML div</div>
|
||||
<span id="htmlSpan" aria-label="HTML span">HTML span</span>
|
||||
<iframe id="iframe"></iframe>
|
||||
`,
|
||||
async function(browser, docAcc) {
|
||||
function testComputedARIARole(id, role) {
|
||||
const acc = findAccessibleChildByID(docAcc, id);
|
||||
is(acc.computedARIARole, role, `computedARIARole for ${id} is correct`);
|
||||
}
|
||||
|
||||
testComputedARIARole("ariaButton", "button");
|
||||
testComputedARIARole("ariaLog", "log");
|
||||
// Landmarks map to a single Gecko role.
|
||||
testComputedARIARole("ariaMain", "main");
|
||||
testComputedARIARole("ariaRegion", "region");
|
||||
// Unnamed ARIA regions should ignore the ARIA role.
|
||||
testComputedARIARole("ariaUnnamedRegion", "navigation");
|
||||
// The directory ARIA role is an alias of list.
|
||||
testComputedARIARole("ariaDirectory", "list");
|
||||
// alertdialog, feed, rowgroup and searchbox map to a Gecko role, but it
|
||||
// isn't unique.
|
||||
testComputedARIARole("ariaAlertdialog", "alertdialog");
|
||||
testComputedARIARole("ariaFeed", "feed");
|
||||
testComputedARIARole("ariaRowgroup", "rowgroup");
|
||||
testComputedARIARole("ariaSearchbox", "searchbox");
|
||||
testComputedARIARole("ariaUnknown", "generic");
|
||||
testComputedARIARole("htmlButton", "button");
|
||||
// There is only a single ARIA role for buttons, but Gecko uses different
|
||||
// roles depending on states.
|
||||
testComputedARIARole("toggleButton", "button");
|
||||
testComputedARIARole("htmlMain", "main");
|
||||
testComputedARIARole("htmlHeader", "banner");
|
||||
// <section> only maps to the region ARIA role if it has a label.
|
||||
testComputedARIARole("htmlSection", "generic");
|
||||
// <header> only maps to the banner role if it is not a child of a
|
||||
// sectioning element.
|
||||
testComputedARIARole("htmlSectionHeader", "generic");
|
||||
testComputedARIARole("htmlRegion", "region");
|
||||
// Gecko doesn't have a rowgroup role. Ensure we differentiate for
|
||||
// computedARIARole.
|
||||
testComputedARIARole("htmlFieldset", "group");
|
||||
testComputedARIARole("htmlTbody", "rowgroup");
|
||||
// <td> inside <table role="grid"> implicitly maps to ARIA gridcell.
|
||||
testComputedARIARole("htmlGridcell", "gridcell");
|
||||
// Test generics.
|
||||
testComputedARIARole("htmlDiv", "generic");
|
||||
testComputedARIARole("htmlSpan", "generic");
|
||||
// Some roles can't be mapped to ARIA role tokens.
|
||||
testComputedARIARole("iframe", "");
|
||||
},
|
||||
{ chrome: true, topLevel: isCacheEnabled }
|
||||
);
|
18
accessible/tests/browser/role/head.js
Normal file
18
accessible/tests/browser/role/head.js
Normal file
@ -0,0 +1,18 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Load the shared-head file first.
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
|
||||
this
|
||||
);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as promisified-events.js.
|
||||
loadScripts(
|
||||
{ name: "common.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "promisified-events.js", dir: MOCHITESTS_DIR }
|
||||
);
|
@ -762,3 +762,17 @@ xpcAccessible::Announce(const nsAString& aAnnouncement, uint16_t aPriority) {
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
xpcAccessible::GetComputedARIARole(nsAString& aRole) {
|
||||
if (!IntlGeneric()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsStaticAtom* ariaRole = IntlGeneric()->ComputedARIARole();
|
||||
if (ariaRole) {
|
||||
ariaRole->ToString(aRole);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -93,6 +93,8 @@ class xpcAccessible : public nsIAccessible {
|
||||
|
||||
NS_IMETHOD Announce(const nsAString& aAnnouncement, uint16_t aPriority) final;
|
||||
|
||||
NS_IMETHOD GetComputedARIARole(nsAString& aRole) final;
|
||||
|
||||
protected:
|
||||
xpcAccessible() {}
|
||||
virtual ~xpcAccessible() {}
|
||||
|
Loading…
Reference in New Issue
Block a user