mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1737944 - P5: Unify GetLevelInternal and GetDefaultLevel as Accessible::GetLevel. r=Jamie
The nsAccUtils method was a "fast" one for calculating set sizes and conceptual parents. Unified it with LocalAccessible::GetLevelInternal in Accessible::GetLevel with an argument. I also fixed select->optgroup->option group attributes. Differential Revision: https://phabricator.services.mozilla.com/D134208
This commit is contained in:
parent
4d4ae8fb45
commit
935107258c
@ -31,7 +31,7 @@ void AccGroupInfo::Update() {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t level = nsAccUtils::GetARIAOrDefaultLevel(mItem);
|
||||
int32_t level = GetARIAOrDefaultLevel(mItem);
|
||||
|
||||
// Compute position in set.
|
||||
mPosInSet = 1;
|
||||
@ -57,7 +57,7 @@ void AccGroupInfo::Update() {
|
||||
// level is lesser than this one then group is ended, if the sibling level
|
||||
// is greater than this one then the group is split by some child elements
|
||||
// (group will be continued).
|
||||
int32_t siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
|
||||
int32_t siblingLevel = GetARIAOrDefaultLevel(sibling);
|
||||
if (siblingLevel < level) {
|
||||
mParent = sibling;
|
||||
break;
|
||||
@ -101,7 +101,7 @@ void AccGroupInfo::Update() {
|
||||
}
|
||||
|
||||
// and check if it's hierarchical flatten structure.
|
||||
int32_t siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
|
||||
int32_t siblingLevel = GetARIAOrDefaultLevel(sibling);
|
||||
if (siblingLevel < level) break;
|
||||
|
||||
// Skip subset.
|
||||
@ -314,3 +314,13 @@ bool AccGroupInfo::ShouldReportRelations(role aRole, role aParentRole) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t AccGroupInfo::GetARIAOrDefaultLevel(
|
||||
const LocalAccessible* aAccessible) {
|
||||
int32_t level = 0;
|
||||
aAccessible->ARIAGroupPosition(&level, nullptr, nullptr);
|
||||
|
||||
if (level != 0) return level;
|
||||
|
||||
return aAccessible->GetLevel(true);
|
||||
}
|
||||
|
@ -94,6 +94,12 @@ class AccGroupInfo {
|
||||
*/
|
||||
static bool ShouldReportRelations(a11y::role aRole, a11y::role aParentRole);
|
||||
|
||||
/**
|
||||
* Return ARIA level value or the default one if ARIA is missed for the
|
||||
* given accessible.
|
||||
*/
|
||||
static int32_t GetARIAOrDefaultLevel(const LocalAccessible* aAccessible);
|
||||
|
||||
uint32_t mPosInSet;
|
||||
uint32_t mSetSize;
|
||||
LocalAccessible* mParent;
|
||||
|
@ -43,31 +43,6 @@ void nsAccUtils::SetAccGroupAttrs(AccAttributes* aAttributes, int32_t aLevel,
|
||||
}
|
||||
}
|
||||
|
||||
int32_t nsAccUtils::GetDefaultLevel(const LocalAccessible* aAccessible) {
|
||||
roles::Role role = aAccessible->Role();
|
||||
|
||||
if (role == roles::OUTLINEITEM) return 1;
|
||||
|
||||
if (role == roles::ROW) {
|
||||
LocalAccessible* parent = aAccessible->LocalParent();
|
||||
// It is a row inside flatten treegrid. Group level is always 1 until it
|
||||
// is overriden by aria-level attribute.
|
||||
if (parent && parent->Role() == roles::TREE_TABLE) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t nsAccUtils::GetARIAOrDefaultLevel(const LocalAccessible* aAccessible) {
|
||||
int32_t level = 0;
|
||||
nsCoreUtils::GetUIntAttr(aAccessible->GetContent(), nsGkAtoms::aria_level,
|
||||
&level);
|
||||
|
||||
if (level != 0) return level;
|
||||
|
||||
return GetDefaultLevel(aAccessible);
|
||||
}
|
||||
|
||||
int32_t nsAccUtils::GetLevelForXULContainerItem(nsIContent* aContent) {
|
||||
nsCOMPtr<nsIDOMXULContainerItemElement> item =
|
||||
aContent->AsElement()->AsXULContainerItem();
|
||||
|
@ -37,17 +37,6 @@ class nsAccUtils {
|
||||
static void SetAccGroupAttrs(AccAttributes* aAttributes, int32_t aLevel,
|
||||
int32_t aSetSize, int32_t aPosInSet);
|
||||
|
||||
/**
|
||||
* Get default value of the level for the given accessible.
|
||||
*/
|
||||
static int32_t GetDefaultLevel(const LocalAccessible* aAcc);
|
||||
|
||||
/**
|
||||
* Return ARIA level value or the default one if ARIA is missed for the
|
||||
* given accessible.
|
||||
*/
|
||||
static int32_t GetARIAOrDefaultLevel(const LocalAccessible* aAccessible);
|
||||
|
||||
/**
|
||||
* Compute group level for nsIDOMXULContainerItemElement node.
|
||||
*/
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "Accessible.h"
|
||||
#include "ARIAMap.h"
|
||||
#include "States.h"
|
||||
#include "mozilla/a11y/HyperTextAccessibleBase.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -77,3 +78,135 @@ uint32_t Accessible::StartOffset() {
|
||||
parent ? parent->AsHyperTextBase() : nullptr;
|
||||
return hyperText ? hyperText->GetChildOffset(this) : 0;
|
||||
}
|
||||
|
||||
int32_t Accessible::GetLevel(bool aFast) const {
|
||||
int32_t level = 0;
|
||||
if (!Parent()) return level;
|
||||
|
||||
roles::Role role = Role();
|
||||
if (role == roles::OUTLINEITEM) {
|
||||
// Always expose 'level' attribute for 'outlineitem' accessible. The number
|
||||
// of nested 'grouping' accessibles containing 'outlineitem' accessible is
|
||||
// its level.
|
||||
level = 1;
|
||||
|
||||
if (!aFast) {
|
||||
const Accessible* parent = this;
|
||||
while ((parent = parent->Parent())) {
|
||||
roles::Role parentRole = parent->Role();
|
||||
|
||||
if (parentRole == roles::OUTLINE) break;
|
||||
if (parentRole == roles::GROUPING) ++level;
|
||||
}
|
||||
}
|
||||
} else if (role == roles::LISTITEM && !aFast) {
|
||||
// Expose 'level' attribute on nested lists. We support two hierarchies:
|
||||
// a) list -> listitem -> list -> listitem (nested list is a last child
|
||||
// of listitem of the parent list);
|
||||
// b) list -> listitem -> group -> listitem (nested listitems are contained
|
||||
// by group that is a last child of the parent listitem).
|
||||
|
||||
// Calculate 'level' attribute based on number of parent listitems.
|
||||
level = 0;
|
||||
const Accessible* parent = this;
|
||||
while ((parent = parent->Parent())) {
|
||||
roles::Role parentRole = parent->Role();
|
||||
|
||||
if (parentRole == roles::LISTITEM) {
|
||||
++level;
|
||||
} else if (parentRole != roles::LIST && parentRole != roles::GROUPING) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (level == 0) {
|
||||
// If this listitem is on top of nested lists then expose 'level'
|
||||
// attribute.
|
||||
parent = Parent();
|
||||
uint32_t siblingCount = parent->ChildCount();
|
||||
for (uint32_t siblingIdx = 0; siblingIdx < siblingCount; siblingIdx++) {
|
||||
Accessible* sibling = parent->ChildAt(siblingIdx);
|
||||
|
||||
Accessible* siblingChild = sibling->LastChild();
|
||||
if (siblingChild) {
|
||||
roles::Role lastChildRole = siblingChild->Role();
|
||||
if (lastChildRole == roles::LIST ||
|
||||
lastChildRole == roles::GROUPING) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
++level; // level is 1-index based
|
||||
}
|
||||
} else if (role == roles::OPTION || role == roles::COMBOBOX_OPTION) {
|
||||
if (const Accessible* parent = Parent()) {
|
||||
if (parent->IsHTMLOptGroup()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (parent->IsListControl() && !parent->ARIARoleMap()) {
|
||||
// This is for HTML selects only.
|
||||
if (aFast) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (Accessible* child = parent->FirstChild(); child;
|
||||
child = child->NextSibling()) {
|
||||
if (child->IsHTMLOptGroup()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (role == roles::HEADING) {
|
||||
nsAtom* tagName = TagName();
|
||||
if (tagName == nsGkAtoms::h1) {
|
||||
return 1;
|
||||
}
|
||||
if (tagName == nsGkAtoms::h2) {
|
||||
return 2;
|
||||
}
|
||||
if (tagName == nsGkAtoms::h3) {
|
||||
return 3;
|
||||
}
|
||||
if (tagName == nsGkAtoms::h4) {
|
||||
return 4;
|
||||
}
|
||||
if (tagName == nsGkAtoms::h5) {
|
||||
return 5;
|
||||
}
|
||||
if (tagName == nsGkAtoms::h6) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
const nsRoleMapEntry* ariaRole = this->ARIARoleMap();
|
||||
if (ariaRole && ariaRole->Is(nsGkAtoms::heading)) {
|
||||
// An aria heading with no aria level has a default level of 2.
|
||||
return 2;
|
||||
}
|
||||
} else if (role == roles::COMMENT) {
|
||||
// For comments, count the ancestor elements with the same role to get the
|
||||
// level.
|
||||
level = 1;
|
||||
|
||||
if (!aFast) {
|
||||
const Accessible* parent = this;
|
||||
while ((parent = parent->Parent())) {
|
||||
roles::Role parentRole = parent->Role();
|
||||
if (parentRole == roles::COMMENT) {
|
||||
++level;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (role == roles::ROW) {
|
||||
// It is a row inside flatten treegrid. Group level is always 1 until it
|
||||
// is overriden by aria-level attribute.
|
||||
const Accessible* parent = Parent();
|
||||
if (parent->Role() == roles::TREE_TABLE) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
@ -300,6 +300,14 @@ class Accessible {
|
||||
virtual void ARIAGroupPosition(int32_t* aLevel, int32_t* aSetSize,
|
||||
int32_t* aPosInSet) const = 0;
|
||||
|
||||
/*
|
||||
* Return calculated group level based on accessible hierarchy.
|
||||
*
|
||||
* @param aFast [in] Don't climb up tree. Calculate level from aria and
|
||||
* roles.
|
||||
*/
|
||||
virtual int32_t GetLevel(bool aFast) const;
|
||||
|
||||
private:
|
||||
static const uint8_t kTypeBits = 6;
|
||||
static const uint8_t kGenericTypesBits = 18;
|
||||
|
@ -1239,13 +1239,6 @@ already_AddRefed<AccAttributes> HyperTextAccessible::DefaultTextAttributes() {
|
||||
return attributes.forget();
|
||||
}
|
||||
|
||||
int32_t HyperTextAccessible::GetLevelInternal() {
|
||||
if (auto* heading = dom::HTMLHeadingElement::FromNode(mContent)) {
|
||||
return heading->AccessibilityLevel();
|
||||
}
|
||||
return AccessibleWrap::GetLevelInternal();
|
||||
}
|
||||
|
||||
void HyperTextAccessible::SetMathMLXMLRoles(AccAttributes* aAttributes) {
|
||||
// Add MathML xmlroles based on the position inside the parent.
|
||||
LocalAccessible* parent = LocalParent();
|
||||
|
@ -51,7 +51,6 @@ class HyperTextAccessible : public AccessibleWrap,
|
||||
|
||||
// LocalAccessible
|
||||
virtual nsAtom* LandmarkRole() const override;
|
||||
virtual int32_t GetLevelInternal() override;
|
||||
virtual already_AddRefed<AccAttributes> NativeAttributes() override;
|
||||
virtual mozilla::a11y::role NativeRole() const override;
|
||||
virtual uint64_t NativeState() const override;
|
||||
|
@ -1467,7 +1467,7 @@ GroupPos LocalAccessible::GroupPosition() {
|
||||
|
||||
// Calculate group level if ARIA is missed.
|
||||
if (groupPos.level == 0) {
|
||||
int32_t level = GetLevelInternal();
|
||||
int32_t level = GetLevel(false);
|
||||
if (level != 0) {
|
||||
groupPos.level = level;
|
||||
} else {
|
||||
@ -3318,83 +3318,6 @@ void LocalAccessible::GetPositionAndSizeInternal(int32_t* aPosInSet,
|
||||
}
|
||||
}
|
||||
|
||||
int32_t LocalAccessible::GetLevelInternal() {
|
||||
int32_t level = nsAccUtils::GetDefaultLevel(this);
|
||||
|
||||
if (!IsBoundToParent()) return level;
|
||||
|
||||
roles::Role role = Role();
|
||||
if (role == roles::OUTLINEITEM) {
|
||||
// Always expose 'level' attribute for 'outlineitem' accessible. The number
|
||||
// of nested 'grouping' accessibles containing 'outlineitem' accessible is
|
||||
// its level.
|
||||
level = 1;
|
||||
|
||||
LocalAccessible* parent = this;
|
||||
while ((parent = parent->LocalParent())) {
|
||||
roles::Role parentRole = parent->Role();
|
||||
|
||||
if (parentRole == roles::OUTLINE) break;
|
||||
if (parentRole == roles::GROUPING) ++level;
|
||||
}
|
||||
|
||||
} else if (role == roles::LISTITEM) {
|
||||
// Expose 'level' attribute on nested lists. We support two hierarchies:
|
||||
// a) list -> listitem -> list -> listitem (nested list is a last child
|
||||
// of listitem of the parent list);
|
||||
// b) list -> listitem -> group -> listitem (nested listitems are contained
|
||||
// by group that is a last child of the parent listitem).
|
||||
|
||||
// Calculate 'level' attribute based on number of parent listitems.
|
||||
level = 0;
|
||||
LocalAccessible* parent = this;
|
||||
while ((parent = parent->LocalParent())) {
|
||||
roles::Role parentRole = parent->Role();
|
||||
|
||||
if (parentRole == roles::LISTITEM) {
|
||||
++level;
|
||||
} else if (parentRole != roles::LIST && parentRole != roles::GROUPING) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (level == 0) {
|
||||
// If this listitem is on top of nested lists then expose 'level'
|
||||
// attribute.
|
||||
parent = LocalParent();
|
||||
uint32_t siblingCount = parent->ChildCount();
|
||||
for (uint32_t siblingIdx = 0; siblingIdx < siblingCount; siblingIdx++) {
|
||||
LocalAccessible* sibling = parent->LocalChildAt(siblingIdx);
|
||||
|
||||
LocalAccessible* siblingChild = sibling->LocalLastChild();
|
||||
if (siblingChild) {
|
||||
roles::Role lastChildRole = siblingChild->Role();
|
||||
if (lastChildRole == roles::LIST ||
|
||||
lastChildRole == roles::GROUPING) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
++level; // level is 1-index based
|
||||
}
|
||||
} else if (role == roles::COMMENT) {
|
||||
// For comments, count the ancestor elements with the same role to get the
|
||||
// level.
|
||||
level = 1;
|
||||
|
||||
LocalAccessible* parent = this;
|
||||
while ((parent = parent->LocalParent())) {
|
||||
roles::Role parentRole = parent->Role();
|
||||
if (parentRole == roles::COMMENT) {
|
||||
++level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
nsAtom* LocalAccessible::TagName() const {
|
||||
return mContent && mContent->IsElement() ? mContent->NodeInfo()->NameAtom()
|
||||
: nullptr;
|
||||
|
@ -271,11 +271,6 @@ class LocalAccessible : public nsISupports, public Accessible {
|
||||
*/
|
||||
virtual LocalAccessible* FocusedChild();
|
||||
|
||||
/**
|
||||
* Return calculated group level based on accessible hierarchy.
|
||||
*/
|
||||
virtual int32_t GetLevelInternal();
|
||||
|
||||
/**
|
||||
* Calculate position in group and group size ('posinset' and 'setsize') based
|
||||
* on accessible hierarchy.
|
||||
|
@ -212,19 +212,6 @@ uint64_t HTMLSelectOptionAccessible::NativeInteractiveState() const {
|
||||
: states::FOCUSABLE | states::SELECTABLE;
|
||||
}
|
||||
|
||||
int32_t HTMLSelectOptionAccessible::GetLevelInternal() {
|
||||
nsIContent* parentContent = mContent->GetParent();
|
||||
|
||||
int32_t level =
|
||||
parentContent->NodeInfo()->Equals(nsGkAtoms::optgroup) ? 2 : 1;
|
||||
|
||||
if (level == 1 && Role() != roles::HEADING) {
|
||||
level = 0; // In a single level list, the level is irrelevant
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
nsRect HTMLSelectOptionAccessible::RelativeBounds(
|
||||
nsIFrame** aBoundingFrame) const {
|
||||
LocalAccessible* combobox = GetCombobox();
|
||||
|
@ -67,7 +67,6 @@ class HTMLSelectOptionAccessible : public HyperTextAccessibleWrap {
|
||||
virtual uint64_t NativeState() const override;
|
||||
virtual uint64_t NativeInteractiveState() const override;
|
||||
|
||||
virtual int32_t GetLevelInternal() override;
|
||||
virtual nsRect RelativeBounds(nsIFrame** aBoundingFrame) const override;
|
||||
virtual void SetSelected(bool aSelect) override;
|
||||
|
||||
|
@ -21,6 +21,15 @@ addAccessibleTask(
|
||||
<select size="4">
|
||||
<option id="opt1">option1</option>
|
||||
<option id="opt2">option2</option>
|
||||
</select>
|
||||
|
||||
<select size="4">
|
||||
<optgroup id="select2_optgroup" label="group">
|
||||
<option id="select2_opt1">option1</option>
|
||||
<option id="select2_opt2">option2</option>
|
||||
</optgroup>
|
||||
<option id="select2_opt3">option3</option>
|
||||
<option id="select2_opt4">option4</option>
|
||||
</select>`,
|
||||
async function(browser, accDoc) {
|
||||
let getAcc = id => findAccessibleChildByID(accDoc, id);
|
||||
@ -39,6 +48,13 @@ addAccessibleTask(
|
||||
// HTML select
|
||||
testGroupAttrs(getAcc("opt1"), 1, 2);
|
||||
testGroupAttrs(getAcc("opt2"), 2, 2);
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// HTML select with optgroup
|
||||
testGroupAttrs(getAcc("select2_opt3"), 1, 2, 1);
|
||||
testGroupAttrs(getAcc("select2_opt4"), 2, 2, 1);
|
||||
testGroupAttrs(getAcc("select2_opt1"), 1, 2, 2);
|
||||
testGroupAttrs(getAcc("select2_opt2"), 2, 2, 2);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -32,13 +32,11 @@
|
||||
testGroupAttrs("opt2", 2, 2);
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// HTML select with options
|
||||
// XXX bug 469123
|
||||
// testGroupAttrs("select2_optgroup", 1, 3, 1);
|
||||
// testGroupAttrs("select2_opt3", 2, 3, 1);
|
||||
// testGroupAttrs("select2_opt4", 3, 3, 1);
|
||||
// testGroupAttrs("select2_opt1", 1, 2, 2);
|
||||
// testGroupAttrs("select2_opt2", 2, 2, 2);
|
||||
// HTML select with optgroup
|
||||
testGroupAttrs("select2_opt3", 1, 2, 1);
|
||||
testGroupAttrs("select2_opt4", 2, 2, 1);
|
||||
testGroupAttrs("select2_opt1", 1, 2, 2);
|
||||
testGroupAttrs("select2_opt2", 2, 2, 2);
|
||||
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// HTML input@type="radio" within form
|
||||
|
@ -240,7 +240,7 @@ role XULMenuitemAccessible::NativeRole() const {
|
||||
return roles::MENUITEM;
|
||||
}
|
||||
|
||||
int32_t XULMenuitemAccessible::GetLevelInternal() {
|
||||
int32_t XULMenuitemAccessible::GetLevel(bool aFast) const {
|
||||
return nsAccUtils::GetLevelForXULContainerItem(mContent);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@ class XULMenuitemAccessible : public AccessibleWrap {
|
||||
virtual a11y::role NativeRole() const override;
|
||||
virtual uint64_t NativeState() const override;
|
||||
virtual uint64_t NativeInteractiveState() const override;
|
||||
virtual int32_t GetLevelInternal() override;
|
||||
|
||||
// ActionAccessible
|
||||
virtual uint8_t ActionCount() const override;
|
||||
@ -43,6 +42,7 @@ class XULMenuitemAccessible : public AccessibleWrap {
|
||||
protected:
|
||||
// LocalAccessible
|
||||
virtual ENameValueFlag NativeName(nsString& aName) const override;
|
||||
virtual int32_t GetLevel(bool aFast) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user