зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1849160 - Part 3: Orphaned child accessibles fall back to native role, r=Jamie
This revision changes the behavior of the Role function such that, for child roles (in parent/child role relationships), the parent role must be present as an ancestor for the child to have its assigned role. For instance, a "row" node must have a table in its ancestry tree. To implement this, we walk parents. This revision also fixes up and removes expected failures for around 18 web platform tests. Differential Revision: https://phabricator.services.mozilla.com/D202542
This commit is contained in:
Родитель
e9a44ec52c
Коммит
9f61225ecc
|
@ -1891,6 +1891,16 @@ role LocalAccessible::ARIATransformRole(role aRole) const {
|
|||
return roles::COMBOBOX_OPTION;
|
||||
}
|
||||
|
||||
// Orphaned option outside the context of a listbox.
|
||||
const Accessible* listbox = FindAncestorIf([](const Accessible& aAcc) {
|
||||
const role accRole = aAcc.Role();
|
||||
return accRole == roles::LISTBOX ? AncestorSearchOption::Found
|
||||
: accRole == roles::GROUPING ? AncestorSearchOption::Continue
|
||||
: AncestorSearchOption::NotFound;
|
||||
});
|
||||
if (!listbox) {
|
||||
return NativeRole();
|
||||
}
|
||||
} else if (aRole == roles::MENUITEM) {
|
||||
// Menuitem has a submenu.
|
||||
if (mContent->IsElement() &&
|
||||
|
@ -1900,6 +1910,30 @@ role LocalAccessible::ARIATransformRole(role aRole) const {
|
|||
return roles::PARENT_MENUITEM;
|
||||
}
|
||||
|
||||
// Orphaned menuitem outside the context of a menu/menubar.
|
||||
const Accessible* menu = FindAncestorIf([](const Accessible& aAcc) {
|
||||
const role accRole = aAcc.Role();
|
||||
return (accRole == roles::MENUBAR || accRole == roles::MENUPOPUP)
|
||||
? AncestorSearchOption::Found
|
||||
: accRole == roles::GROUPING ? AncestorSearchOption::Continue
|
||||
: AncestorSearchOption::NotFound;
|
||||
});
|
||||
if (!menu) {
|
||||
return NativeRole();
|
||||
}
|
||||
} else if (aRole == roles::RADIO_MENU_ITEM ||
|
||||
aRole == roles::CHECK_MENU_ITEM) {
|
||||
// Orphaned radio/checkbox menuitem outside the context of a menu/menubar.
|
||||
const Accessible* menu = FindAncestorIf([](const Accessible& aAcc) {
|
||||
const role accRole = aAcc.Role();
|
||||
return (accRole == roles::MENUBAR || accRole == roles::MENUPOPUP)
|
||||
? AncestorSearchOption::Found
|
||||
: accRole == roles::GROUPING ? AncestorSearchOption::Continue
|
||||
: AncestorSearchOption::NotFound;
|
||||
});
|
||||
if (!menu) {
|
||||
return NativeRole();
|
||||
}
|
||||
} else if (aRole == roles::CELL) {
|
||||
// A cell inside an ancestor table element that has a grid role needs a
|
||||
// gridcell role
|
||||
|
@ -1908,6 +1942,63 @@ role LocalAccessible::ARIATransformRole(role aRole) const {
|
|||
if (table && table->IsARIARole(nsGkAtoms::grid)) {
|
||||
return roles::GRID_CELL;
|
||||
}
|
||||
} else if (aRole == roles::ROW) {
|
||||
// Orphaned rows outside the context of a table.
|
||||
const LocalAccessible* table = nsAccUtils::TableFor(this);
|
||||
if (!table) {
|
||||
return NativeRole();
|
||||
}
|
||||
} else if (aRole == roles::ROWGROUP) {
|
||||
// Orphaned rowgroups outside the context of a table.
|
||||
const Accessible* table = FindAncestorIf([](const Accessible& aAcc) {
|
||||
return aAcc.IsTable() ? AncestorSearchOption::Found
|
||||
: AncestorSearchOption::NotFound;
|
||||
});
|
||||
if (!table) {
|
||||
return NativeRole();
|
||||
}
|
||||
} else if (aRole == roles::GRID_CELL || aRole == roles::ROWHEADER ||
|
||||
aRole == roles::COLUMNHEADER) {
|
||||
// Orphaned gridcell/rowheader/columnheader outside the context of a row.
|
||||
const Accessible* row = FindAncestorIf([](const Accessible& aAcc) {
|
||||
return aAcc.IsTableRow() ? AncestorSearchOption::Found
|
||||
: AncestorSearchOption::NotFound;
|
||||
});
|
||||
if (!row) {
|
||||
return NativeRole();
|
||||
}
|
||||
} else if (aRole == roles::LISTITEM) {
|
||||
// doc-biblioentry and doc-endnote should not be treated as listitems.
|
||||
const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
|
||||
if (!roleMapEntry || (roleMapEntry->roleAtom != nsGkAtoms::docBiblioentry &&
|
||||
roleMapEntry->roleAtom != nsGkAtoms::docEndnote)) {
|
||||
// Orphaned listitem outside the context of a list.
|
||||
const Accessible* list = FindAncestorIf([](const Accessible& aAcc) {
|
||||
return aAcc.IsList() ? AncestorSearchOption::Found
|
||||
: AncestorSearchOption::Continue;
|
||||
});
|
||||
if (!list) {
|
||||
return NativeRole();
|
||||
}
|
||||
}
|
||||
} else if (aRole == roles::PAGETAB) {
|
||||
// Orphaned tab outside the context of a tablist.
|
||||
const Accessible* tablist = FindAncestorIf([](const Accessible& aAcc) {
|
||||
return aAcc.Role() == roles::PAGETABLIST ? AncestorSearchOption::Found
|
||||
: AncestorSearchOption::NotFound;
|
||||
});
|
||||
if (!tablist) {
|
||||
return NativeRole();
|
||||
}
|
||||
} else if (aRole == roles::OUTLINEITEM) {
|
||||
// Orphaned treeitem outside the context of a tree.
|
||||
const Accessible* tree = FindAncestorIf([](const Accessible& aAcc) {
|
||||
return aAcc.Role() == roles::OUTLINE ? AncestorSearchOption::Found
|
||||
: AncestorSearchOption::Continue;
|
||||
});
|
||||
if (!tree) {
|
||||
return NativeRole();
|
||||
}
|
||||
}
|
||||
|
||||
return aRole;
|
||||
|
@ -2115,12 +2206,14 @@ Relation LocalAccessible::RelationByType(RelationType aType) const {
|
|||
if (roleMapEntry && (roleMapEntry->role == roles::OUTLINEITEM ||
|
||||
roleMapEntry->role == roles::LISTITEM ||
|
||||
roleMapEntry->role == roles::ROW)) {
|
||||
Accessible* parent = const_cast<LocalAccessible*>(this)
|
||||
->GetOrCreateGroupInfo()
|
||||
->ConceptualParent();
|
||||
if (parent) {
|
||||
MOZ_ASSERT(parent->IsLocal());
|
||||
rel.AppendTarget(parent->AsLocal());
|
||||
AccGroupInfo* groupInfo =
|
||||
const_cast<LocalAccessible*>(this)->GetOrCreateGroupInfo();
|
||||
if (groupInfo) {
|
||||
Accessible* parent = groupInfo->ConceptualParent();
|
||||
if (parent) {
|
||||
MOZ_ASSERT(parent->IsLocal());
|
||||
rel.AppendTarget(parent->AsLocal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
[grid-roles.html]
|
||||
[orphaned rowheader outside the context of row]
|
||||
expected: FAIL
|
||||
|
||||
[orphaned columnheader outside the context of row]
|
||||
expected: FAIL
|
||||
|
||||
[orphaned button with gridcell role outside the context of row]
|
||||
expected: FAIL
|
||||
|
||||
[orphaned row outside the context of table]
|
||||
expected: FAIL
|
||||
|
||||
[orphaned rowgroup outside the context of row]
|
||||
expected: FAIL
|
||||
|
||||
[orphaned div with gridcell role outside the context of row]
|
||||
expected: FAIL
|
|
@ -1,6 +0,0 @@
|
|||
[list-roles.html]
|
||||
[orphan p with listitem role]
|
||||
expected: FAIL
|
||||
|
||||
[orphan div with listitem role]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[listbox-roles.html]
|
||||
[orphaned option outside the context of listbox]
|
||||
expected: FAIL
|
|
@ -1,27 +0,0 @@
|
|||
[menu-roles.html]
|
||||
[orphaned menuitem outside the context of menu/menubar]
|
||||
expected: FAIL
|
||||
|
||||
[orphaned menuitemradio outside the context of menu/menubar]
|
||||
expected: FAIL
|
||||
|
||||
[orphaned menuitemcheckbox outside the context of menu/menubar]
|
||||
expected: FAIL
|
||||
|
||||
[orphan button with menuitem role]
|
||||
expected: FAIL
|
||||
|
||||
[orphan button with menuitemcheckbox role]
|
||||
expected: FAIL
|
||||
|
||||
[orphan button with menuitemradio role]
|
||||
expected: FAIL
|
||||
|
||||
[orphan div with menuitem role]
|
||||
expected: FAIL
|
||||
|
||||
[orphan div with menuitemcheckbox role]
|
||||
expected: FAIL
|
||||
|
||||
[orphan div with menuitemradio role]
|
||||
expected: FAIL
|
|
@ -1,6 +0,0 @@
|
|||
[tab-roles.html]
|
||||
[orphan button with tab role]
|
||||
expected: FAIL
|
||||
|
||||
[orphan span with tab role]
|
||||
expected: FAIL
|
|
@ -1,6 +0,0 @@
|
|||
[tree-roles.html]
|
||||
[orphaned treeitem outside the context of tree]
|
||||
expected: FAIL
|
||||
|
||||
[orphaned button with treeitem role outside tree context]
|
||||
expected: FAIL
|
Загрузка…
Ссылка в новой задаче