зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1816346 part 2: If we force an Accessible to be created due to transform/fixed/sticky despite it being presentational, make it a generic Accessible. r=nlapre
Otherwise, semantics are exposed (e.g. for a table), which completely defeats the author's intent that this be treated as presentational. Differential Revision: https://phabricator.services.mozilla.com/D170165
This commit is contained in:
Родитель
75092d8fb0
Коммит
f826326f5f
|
@ -112,20 +112,6 @@ static bool MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// If the frame has been transformed, and the content has any children, we
|
||||
// should create an Accessible so that we can account for the transform when
|
||||
// calculating the Accessible's bounds using the parent process cache.
|
||||
// Ditto for content which is position: fixed or sticky.
|
||||
// However, don't do this for XUL widgets, as this breaks XUL a11y code
|
||||
// expectations in some cases. XUL widgets are only used in the parent
|
||||
// process and can't be cached anyway.
|
||||
if (aContent->HasChildren() && !aContent->IsXULElement() &&
|
||||
(frame->IsTransformed() || frame->IsStickyPositioned() ||
|
||||
(frame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
|
||||
nsLayoutUtils::IsReallyFixedPos(frame)))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aContent->IsElement()) {
|
||||
uint32_t attrCount = aContent->AsElement()->GetAttrCount();
|
||||
for (uint32_t attrIdx = 0; attrIdx < attrCount; attrIdx++) {
|
||||
|
@ -162,6 +148,34 @@ static bool MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the element must be a generic Accessible, even if it has been
|
||||
* marked presentational with role="presentation", etc. MustBeAccessible causes
|
||||
* an Accessible to be created as if it weren't marked presentational at all;
|
||||
* e.g. <table role="presentation" tabindex="0"> will expose roles::TABLE and
|
||||
* support TableAccessibleBase. In contrast, this function causes a generic
|
||||
* Accessible to be created; e.g. <table role="presentation" style="position:
|
||||
* fixed;"> will expose roles::TEXT_CONTAINER and will not support
|
||||
* TableAccessibleBase. This is necessary in certain cases for the
|
||||
* RemoteAccessible cache.
|
||||
*/
|
||||
static bool MustBeGenericAccessible(nsIContent* aContent,
|
||||
DocAccessible* aDocument) {
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
MOZ_ASSERT(frame);
|
||||
// If the frame has been transformed, and the content has any children, we
|
||||
// should create an Accessible so that we can account for the transform when
|
||||
// calculating the Accessible's bounds using the parent process cache.
|
||||
// Ditto for content which is position: fixed or sticky.
|
||||
// However, don't do this for XUL widgets, as this breaks XUL a11y code
|
||||
// expectations in some cases. XUL widgets are only used in the parent
|
||||
// process and can't be cached anyway.
|
||||
return aContent->HasChildren() && !aContent->IsXULElement() &&
|
||||
(frame->IsTransformed() || frame->IsStickyPositioned() ||
|
||||
(frame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
|
||||
nsLayoutUtils::IsReallyFixedPos(frame)));
|
||||
}
|
||||
|
||||
bool nsAccessibilityService::ShouldCreateImgAccessible(
|
||||
mozilla::dom::Element* aElement, DocAccessible* aDocument) {
|
||||
// The element must have a layout frame for us to proceed. If there is no
|
||||
|
@ -1110,14 +1124,23 @@ LocalAccessible* nsAccessibilityService::CreateAccessible(
|
|||
|
||||
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(content->AsElement());
|
||||
|
||||
// If the element is focusable or global ARIA attribute is applied to it or
|
||||
// it is referenced by ARIA relationship then treat role="presentation" on
|
||||
// the element as the role is not there.
|
||||
if (roleMapEntry && (roleMapEntry->Is(nsGkAtoms::presentation) ||
|
||||
roleMapEntry->Is(nsGkAtoms::none))) {
|
||||
if (!MustBeAccessible(content, document)) return nullptr;
|
||||
|
||||
roleMapEntry = nullptr;
|
||||
if (MustBeAccessible(content, document)) {
|
||||
// If the element is focusable, a global ARIA attribute is applied to it
|
||||
// or it is referenced by an ARIA relationship, then treat
|
||||
// role="presentation" on the element as if the role is not there.
|
||||
roleMapEntry = nullptr;
|
||||
} else if (MustBeGenericAccessible(content, document)) {
|
||||
// Clear roleMapEntry so that we use the generic role specified below.
|
||||
// Otherwise, we'd expose roles::NOTHING as specified for presentation in
|
||||
// ARIAMap.
|
||||
roleMapEntry = nullptr;
|
||||
newAcc = new EnumRoleHyperTextAccessible<roles::TEXT_CONTAINER>(content,
|
||||
document);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!newAcc && content->IsHTMLElement()) { // HTML accessibles
|
||||
|
@ -1304,6 +1327,9 @@ LocalAccessible* nsAccessibilityService::CreateAccessible(
|
|||
// Interesting generic non-HTML container
|
||||
newAcc = new AccessibleWrap(content, document);
|
||||
}
|
||||
} else if (!newAcc && MustBeGenericAccessible(content, document)) {
|
||||
newAcc = new EnumRoleHyperTextAccessible<roles::TEXT_CONTAINER>(content,
|
||||
document);
|
||||
}
|
||||
|
||||
if (newAcc) {
|
||||
|
|
|
@ -131,7 +131,7 @@ addAccessibleTask(
|
|||
</div>
|
||||
`,
|
||||
async function(browser, docAcc) {
|
||||
const tree = { SECTION: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }] };
|
||||
const tree = { TEXT_CONTAINER: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }] };
|
||||
|
||||
const divWithTransform = findAccessibleChildByID(docAcc, "container")
|
||||
.firstChild;
|
||||
|
@ -159,7 +159,7 @@ addAccessibleTask(
|
|||
`,
|
||||
async function(browser, docAcc) {
|
||||
let divToTransform = findAccessibleChildByID(docAcc, "div-to-transform");
|
||||
ok(!divToTransform, "There should not be a section accessible.");
|
||||
ok(!divToTransform, "There should not be a div accessible.");
|
||||
|
||||
// Translate the div.
|
||||
await invokeContentTask(browser, [], () => {
|
||||
|
@ -171,7 +171,7 @@ addAccessibleTask(
|
|||
// Verify that the SECTION accessible appeared after we gave it a transform.
|
||||
divToTransform = findAccessibleChildByID(docAcc, "div-to-transform");
|
||||
const tree = {
|
||||
SECTION: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }],
|
||||
TEXT_CONTAINER: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }],
|
||||
};
|
||||
testAccessibleTree(divToTransform, tree);
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
loadScripts({ name: "layout.js", dir: MOCHITESTS_DIR });
|
||||
/* import-globals-from ../../mochitest/role.js */
|
||||
loadScripts(
|
||||
{ name: "layout.js", dir: MOCHITESTS_DIR },
|
||||
{ name: "role.js", dir: MOCHITESTS_DIR }
|
||||
);
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const appUnitsPerDevPixel = 60;
|
||||
|
@ -320,13 +324,17 @@ addAccessibleTask(
|
|||
*/
|
||||
addAccessibleTask(
|
||||
`
|
||||
<div id="fixed" role="presentation" style="position: fixed;">fixed</div>
|
||||
<table id="fixed" role="presentation" style="position: fixed;">
|
||||
<tr><th>fixed</th></tr>
|
||||
</table>
|
||||
<div id="mutate" role="presentation">mutate</div>
|
||||
<hr style="height: 200vh;">
|
||||
<p>bottom</p>
|
||||
`,
|
||||
async function(browser, docAcc) {
|
||||
ok(findAccessibleChildByID(docAcc, "fixed"), "fixed is accessible");
|
||||
const fixed = findAccessibleChildByID(docAcc, "fixed");
|
||||
ok(fixed, "fixed is accessible");
|
||||
isnot(fixed.role, ROLE_TABLE, "fixed doesn't have ROLE_TABLE");
|
||||
ok(!findAccessibleChildByID(docAcc, "mutate"), "mutate inaccessible");
|
||||
info("Setting position: fixed on mutate");
|
||||
let shown = waitForEvent(EVENT_SHOW, "mutate");
|
||||
|
|
Загрузка…
Ссылка в новой задаче