Bug 1667174: Create RotorRule base class to abstract checks duplicated across current rotor rules r=eeejay

Differential Revision: https://phabricator.services.mozilla.com/D91325
This commit is contained in:
Morgan Reschenberg 2020-09-28 22:32:07 +00:00
Родитель d073562ebf
Коммит 39d40dbb3f
3 изменённых файлов: 177 добавлений и 280 удалений

Просмотреть файл

@ -90,9 +90,8 @@ using namespace mozilla::a11y;
NSMutableArray* matches = [[NSMutableArray alloc] init];
for (id key in mSearchKeys) {
if ([key isEqualToString:@"AXAnyTypeSearchKey"]) {
RotorAllRule rule = mImmediateDescendantsOnly
? RotorAllRule(geckoStartAcc)
: RotorAllRule();
RotorRule rule =
mImmediateDescendantsOnly ? RotorRule(geckoStartAcc) : RotorRule();
if (mSearchForward) {
if ([mStartElem isKindOfClass:[MOXWebAreaAccessible class]]) {
@ -124,37 +123,37 @@ using namespace mozilla::a11y;
}
if ([key isEqualToString:@"AXHeadingSearchKey"]) {
RotorHeadingRule rule = mImmediateDescendantsOnly
? RotorHeadingRule(geckoStartAcc)
: RotorHeadingRule();
RotorRoleRule rule = mImmediateDescendantsOnly
? RotorRoleRule(roles::HEADING, geckoStartAcc)
: RotorRoleRule(roles::HEADING);
[matches addObjectsFromArray:[self getMatchesForRule:rule]];
}
if ([key isEqualToString:@"AXArticleSearchKey"]) {
RotorArticleRule rule = mImmediateDescendantsOnly
? RotorArticleRule(geckoStartAcc)
: RotorArticleRule();
RotorRoleRule rule = mImmediateDescendantsOnly
? RotorRoleRule(roles::ARTICLE, geckoStartAcc)
: RotorRoleRule(roles::ARTICLE);
[matches addObjectsFromArray:[self getMatchesForRule:rule]];
}
if ([key isEqualToString:@"AXTableSearchKey"]) {
RotorTableRule rule = mImmediateDescendantsOnly
? RotorTableRule(geckoStartAcc)
: RotorTableRule();
RotorRoleRule rule = mImmediateDescendantsOnly
? RotorRoleRule(roles::TABLE, geckoStartAcc)
: RotorRoleRule(roles::TABLE);
[matches addObjectsFromArray:[self getMatchesForRule:rule]];
}
if ([key isEqualToString:@"AXLandmarkSearchKey"]) {
RotorLandmarkRule rule = mImmediateDescendantsOnly
? RotorLandmarkRule(geckoStartAcc)
: RotorLandmarkRule();
RotorRoleRule rule = mImmediateDescendantsOnly
? RotorRoleRule(roles::LANDMARK, geckoStartAcc)
: RotorRoleRule(roles::LANDMARK);
[matches addObjectsFromArray:[self getMatchesForRule:rule]];
}
if ([key isEqualToString:@"AXListSearchKey"]) {
RotorListRule rule = mImmediateDescendantsOnly
? RotorListRule(geckoStartAcc)
: RotorListRule();
RotorRoleRule rule = mImmediateDescendantsOnly
? RotorRoleRule(roles::LIST, geckoStartAcc)
: RotorRoleRule(roles::LIST);
[matches addObjectsFromArray:[self getMatchesForRule:rule]];
}
@ -180,9 +179,9 @@ using namespace mozilla::a11y;
}
if ([key isEqualToString:@"AXButtonSearchKey"]) {
RotorButtonRule rule = mImmediateDescendantsOnly
? RotorButtonRule(geckoStartAcc)
: RotorButtonRule();
RotorRoleRule rule = mImmediateDescendantsOnly
? RotorRoleRule(roles::PUSHBUTTON, geckoStartAcc)
: RotorRoleRule(roles::PUSHBUTTON);
[matches addObjectsFromArray:[self getMatchesForRule:rule]];
}
@ -194,16 +193,16 @@ using namespace mozilla::a11y;
}
if ([key isEqualToString:@"AXFrameSearchKey"]) {
RotorFrameRule rule = mImmediateDescendantsOnly
? RotorFrameRule(geckoStartAcc)
: RotorFrameRule();
RotorRoleRule rule = mImmediateDescendantsOnly
? RotorRoleRule(roles::DOCUMENT, geckoStartAcc)
: RotorRoleRule(roles::DOCUMENT);
[matches addObjectsFromArray:[self getMatchesForRule:rule]];
}
if ([key isEqualToString:@"AXImageSearchKey"]) {
RotorImageRule rule = mImmediateDescendantsOnly
? RotorImageRule(geckoStartAcc)
: RotorImageRule();
RotorRoleRule rule = mImmediateDescendantsOnly
? RotorRoleRule(roles::GRAPHIC, geckoStartAcc)
: RotorRoleRule(roles::GRAPHIC);
[matches addObjectsFromArray:[self getMatchesForRule:rule]];
}
}

Просмотреть файл

@ -11,78 +11,46 @@
using namespace mozilla::a11y;
/**
* These rules match accessibles on a given role, filtering out non-direct
* descendants if necessary.
* This rule matches all accessibles that satisfy the "boilerplate"
* pivot conditions and have a corresponding native accessible.
*/
class RotorHeadingRule final : public PivotRoleRule {
class RotorRule : public PivotRule {
public:
explicit RotorHeadingRule();
explicit RotorHeadingRule(AccessibleOrProxy& aDirectDescendantsFrom);
};
class RotorArticleRule final : public PivotRoleRule {
public:
explicit RotorArticleRule();
explicit RotorArticleRule(AccessibleOrProxy& aDirectDescendantsFrom);
};
class RotorTableRule final : public PivotRoleRule {
public:
explicit RotorTableRule();
explicit RotorTableRule(AccessibleOrProxy& aDirectDescendantsFrom);
};
class RotorLandmarkRule final : public PivotRoleRule {
public:
explicit RotorLandmarkRule();
explicit RotorLandmarkRule(AccessibleOrProxy& aDirectDescendantsFrom);
};
class RotorListRule final : public PivotRoleRule {
public:
explicit RotorListRule();
explicit RotorListRule(AccessibleOrProxy& aDirectDescendantsFrom);
};
class RotorButtonRule final : public PivotRoleRule {
public:
explicit RotorButtonRule();
explicit RotorButtonRule(AccessibleOrProxy& aDirectDescendantsFrom);
};
class RotorFrameRule final : public PivotRoleRule {
public:
explicit RotorFrameRule();
explicit RotorFrameRule(AccessibleOrProxy& aDirectDescendantsFrom);
};
class RotorImageRule final : public PivotRoleRule {
public:
explicit RotorImageRule();
explicit RotorImageRule(AccessibleOrProxy& aDirectDescendantsFrom);
};
class RotorControlRule final : public PivotRule {
public:
explicit RotorControlRule(AccessibleOrProxy& aDirectDescendantsFrom);
explicit RotorControlRule();
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
explicit RotorRule(AccessibleOrProxy& aDirectDescendantsFrom);
explicit RotorRule();
uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
private:
AccessibleOrProxy mDirectDescendantsFrom;
};
class RotorLinkRule : public PivotRule {
/**
* This rule matches all accessibles of a given role.
*/
class RotorRoleRule final : public RotorRule {
public:
explicit RotorRoleRule(role aRole, AccessibleOrProxy& aDirectDescendantsFrom);
explicit RotorRoleRule(role aRole);
uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
private:
role mRole;
};
class RotorControlRule final : public RotorRule {
public:
explicit RotorControlRule(AccessibleOrProxy& aDirectDescendantsFrom);
explicit RotorControlRule();
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
};
class RotorLinkRule : public RotorRule {
public:
explicit RotorLinkRule();
explicit RotorLinkRule(AccessibleOrProxy& aDirectDescendantsFrom);
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
protected:
AccessibleOrProxy mDirectDescendantsFrom;
};
class RotorVisitedLinkRule final : public RotorLinkRule {
@ -100,18 +68,3 @@ class RotorUnvisitedLinkRule final : public RotorLinkRule {
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
};
/**
* This rule matches all accessibles, filtering out non-direct
* descendants if necessary.
*/
class RotorAllRule final : public PivotRule {
public:
explicit RotorAllRule(AccessibleOrProxy& aDirectDescendantsFrom);
explicit RotorAllRule();
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
private:
AccessibleOrProxy mDirectDescendantsFrom;
};

Просмотреть файл

@ -12,54 +12,14 @@
using namespace mozilla::a11y;
// Role Rules
// Generic Rotor Rule
RotorHeadingRule::RotorHeadingRule() : PivotRoleRule(roles::HEADING) {}
RotorHeadingRule::RotorHeadingRule(AccessibleOrProxy& aDirectDescendantsFrom)
: PivotRoleRule(roles::HEADING, aDirectDescendantsFrom) {}
RotorArticleRule::RotorArticleRule() : PivotRoleRule(roles::ARTICLE) {}
RotorArticleRule::RotorArticleRule(AccessibleOrProxy& aDirectDescendantsFrom)
: PivotRoleRule(roles::ARTICLE, aDirectDescendantsFrom) {}
RotorTableRule::RotorTableRule() : PivotRoleRule(roles::TABLE) {}
RotorTableRule::RotorTableRule(AccessibleOrProxy& aDirectDescendantsFrom)
: PivotRoleRule(roles::TABLE, aDirectDescendantsFrom) {}
RotorLandmarkRule::RotorLandmarkRule() : PivotRoleRule(roles::LANDMARK) {}
RotorLandmarkRule::RotorLandmarkRule(AccessibleOrProxy& aDirectDescendantsFrom)
: PivotRoleRule(roles::LANDMARK, aDirectDescendantsFrom) {}
RotorListRule::RotorListRule() : PivotRoleRule(roles::LIST) {}
RotorListRule::RotorListRule(AccessibleOrProxy& aDirectDescendantsFrom)
: PivotRoleRule(roles::LIST, aDirectDescendantsFrom) {}
RotorButtonRule::RotorButtonRule() : PivotRoleRule(roles::PUSHBUTTON) {}
RotorButtonRule::RotorButtonRule(AccessibleOrProxy& aDirectDescendantsFrom)
: PivotRoleRule(roles::PUSHBUTTON, aDirectDescendantsFrom) {}
RotorFrameRule::RotorFrameRule() : PivotRoleRule(roles::DOCUMENT) {}
RotorFrameRule::RotorFrameRule(AccessibleOrProxy& aDirectDescendantsFrom)
: PivotRoleRule(roles::DOCUMENT, aDirectDescendantsFrom) {}
RotorImageRule::RotorImageRule() : PivotRoleRule(roles::GRAPHIC) {}
RotorImageRule::RotorImageRule(AccessibleOrProxy& aDirectDescendantsFrom)
: PivotRoleRule(roles::GRAPHIC, aDirectDescendantsFrom) {}
RotorControlRule::RotorControlRule(AccessibleOrProxy& aDirectDescendantsFrom)
RotorRule::RotorRule(AccessibleOrProxy& aDirectDescendantsFrom)
: mDirectDescendantsFrom(aDirectDescendantsFrom) {}
RotorControlRule::RotorControlRule() : mDirectDescendantsFrom(nullptr) {}
RotorRule::RotorRule() : mDirectDescendantsFrom(nullptr) {}
uint16_t RotorControlRule::Match(const AccessibleOrProxy& aAccOrProxy) {
uint16_t RotorRule::Match(const AccessibleOrProxy& aAccOrProxy) {
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
if (nsAccUtils::MustPrune(aAccOrProxy)) {
@ -71,84 +31,125 @@ uint16_t RotorControlRule::Match(const AccessibleOrProxy& aAccOrProxy) {
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
switch (aAccOrProxy.Role()) {
case roles::PUSHBUTTON:
case roles::SPINBUTTON:
case roles::DETAILS:
case roles::CHECKBUTTON:
case roles::COLOR_CHOOSER:
case roles::BUTTONDROPDOWNGRID: // xul colorpicker
case roles::LISTBOX:
case roles::COMBOBOX:
case roles::EDITCOMBOBOX:
case roles::RADIOBUTTON:
case roles::RADIO_GROUP:
case roles::PAGETAB:
case roles::SLIDER:
case roles::SWITCH:
case roles::ENTRY:
case roles::OUTLINE:
case roles::PASSWORD_TEXT:
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
break;
case roles::GROUPING: {
// Groupings are sometimes used (like radio groups) to denote
// sets of controls. If that's the case, we want to surface
// them. We also want to surface grouped time and date controls.
for (unsigned int i = 0; i < aAccOrProxy.ChildCount(); i++) {
AccessibleOrProxy currChild = aAccOrProxy.ChildAt(i);
if (currChild.Role() == roles::CHECKBUTTON ||
currChild.Role() == roles::SWITCH ||
currChild.Role() == roles::SPINBUTTON ||
currChild.Role() == roles::RADIOBUTTON) {
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
break;
}
}
break;
}
case roles::DATE_EDITOR:
case roles::TIME_EDITOR:
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
break;
default:
break;
if ([GetNativeFromGeckoAccessible(aAccOrProxy) isAccessibilityElement]) {
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
}
return result;
}
RotorLinkRule::RotorLinkRule() : mDirectDescendantsFrom(nullptr) {}
// Rotor Role Rule
RotorRoleRule::RotorRoleRule(role aRole,
AccessibleOrProxy& aDirectDescendantsFrom)
: RotorRule(aDirectDescendantsFrom), mRole(aRole){};
RotorRoleRule::RotorRoleRule(role aRole) : RotorRule(), mRole(aRole){};
uint16_t RotorRoleRule::Match(const AccessibleOrProxy& aAccOrProxy) {
uint16_t result = RotorRule::Match(aAccOrProxy);
// if a match was found in the base-class's Match function,
// it is valid to consider that match again here. if it is
// not of the desired role, we flip the match bit to "unmatch"
// otherwise, the match persists.
if ((result & nsIAccessibleTraversalRule::FILTER_MATCH) &&
aAccOrProxy.Role() != mRole) {
result &= ~nsIAccessibleTraversalRule::FILTER_MATCH;
}
return result;
}
// Rotor Control Rule
RotorControlRule::RotorControlRule(AccessibleOrProxy& aDirectDescendantsFrom)
: RotorRule(aDirectDescendantsFrom){};
RotorControlRule::RotorControlRule() : RotorRule(){};
uint16_t RotorControlRule::Match(const AccessibleOrProxy& aAccOrProxy) {
uint16_t result = RotorRule::Match(aAccOrProxy);
// if a match was found in the base-class's Match function,
// it is valid to consider that match again here. if it is
// not of the desired role, we flip the match bit to "unmatch"
// otherwise, the match persists.
if ((result & nsIAccessibleTraversalRule::FILTER_MATCH)) {
switch (aAccOrProxy.Role()) {
case roles::PUSHBUTTON:
case roles::SPINBUTTON:
case roles::DETAILS:
case roles::CHECKBUTTON:
case roles::COLOR_CHOOSER:
case roles::BUTTONDROPDOWNGRID: // xul colorpicker
case roles::LISTBOX:
case roles::COMBOBOX:
case roles::EDITCOMBOBOX:
case roles::RADIOBUTTON:
case roles::RADIO_GROUP:
case roles::PAGETAB:
case roles::SLIDER:
case roles::SWITCH:
case roles::ENTRY:
case roles::OUTLINE:
case roles::PASSWORD_TEXT:
return result;
case roles::DATE_EDITOR:
case roles::TIME_EDITOR:
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
return result;
case roles::GROUPING: {
// Groupings are sometimes used (like radio groups) to denote
// sets of controls. If that's the case, we want to surface
// them. We also want to surface grouped time and date controls.
for (unsigned int i = 0; i < aAccOrProxy.ChildCount(); i++) {
AccessibleOrProxy currChild = aAccOrProxy.ChildAt(i);
if (currChild.Role() == roles::CHECKBUTTON ||
currChild.Role() == roles::SWITCH ||
currChild.Role() == roles::SPINBUTTON ||
currChild.Role() == roles::RADIOBUTTON) {
return result;
}
}
// if we iterated through the groups children and didn't
// find a control with one of the roles above, we should
// ignore this grouping
result &= ~nsIAccessibleTraversalRule::FILTER_MATCH;
return result;
}
default:
// if we did not match on any above role, we should
// ignore this accessible.
result &= ~nsIAccessibleTraversalRule::FILTER_MATCH;
}
}
return result;
}
// Rotor Link Rule
RotorLinkRule::RotorLinkRule(AccessibleOrProxy& aDirectDescendantsFrom)
: mDirectDescendantsFrom(aDirectDescendantsFrom) {}
: RotorRule(aDirectDescendantsFrom){};
RotorLinkRule::RotorLinkRule() : RotorRule(){};
uint16_t RotorLinkRule::Match(const AccessibleOrProxy& aAccOrProxy) {
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
uint16_t result = RotorRule::Match(aAccOrProxy);
if (nsAccUtils::MustPrune(aAccOrProxy)) {
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
if (!mDirectDescendantsFrom.IsNull() &&
(aAccOrProxy != mDirectDescendantsFrom)) {
// If we've specified mDirectDescendantsFrom, we should ignore
// non-direct descendants of from the specified AoP. Because
// pivot performs a preorder traversal, the first aAccOrProxy
// object(s) that don't equal mDirectDescendantsFrom will be
// mDirectDescendantsFrom's children. We'll process them, but ignore
// their subtrees thereby processing direct descendants of
// mDirectDescendantsFrom only.
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
if (mozAccessible* nativeMatch = GetNativeFromGeckoAccessible(aAccOrProxy)) {
if ([[nativeMatch moxRole] isEqualToString:@"AXLink"]) {
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
// if a match was found in the base-class's Match function,
// it is valid to consider that match again here. if it is
// not of the desired role, we flip the match bit to "unmatch"
// otherwise, the match persists.
if ((result & nsIAccessibleTraversalRule::FILTER_MATCH)) {
mozAccessible* nativeMatch = GetNativeFromGeckoAccessible(aAccOrProxy);
if (![[nativeMatch moxRole] isEqualToString:@"AXLink"]) {
result &= ~nsIAccessibleTraversalRule::FILTER_MATCH;
}
}
@ -162,28 +163,12 @@ RotorVisitedLinkRule::RotorVisitedLinkRule(
: RotorLinkRule(aDirectDescendantsFrom) {}
uint16_t RotorVisitedLinkRule::Match(const AccessibleOrProxy& aAccOrProxy) {
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
uint16_t result = RotorLinkRule::Match(aAccOrProxy);
if (nsAccUtils::MustPrune(aAccOrProxy)) {
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
if (!mDirectDescendantsFrom.IsNull() &&
(aAccOrProxy != mDirectDescendantsFrom)) {
// If we've specified mDirectDescendantsFrom, we should ignore
// non-direct descendants of from the specified AoP. Because
// pivot performs a preorder traversal, the first aAccOrProxy
// object(s) that don't equal mDirectDescendantsFrom will be
// mDirectDescendantsFrom's children. We'll process them, but ignore
// their subtrees thereby processing direct descendants of
// mDirectDescendantsFrom only.
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
if (mozAccessible* nativeMatch = GetNativeFromGeckoAccessible(aAccOrProxy)) {
if ([[nativeMatch moxRole] isEqualToString:@"AXLink"] &&
[[nativeMatch moxVisited] boolValue] == YES) {
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
if (result & nsIAccessibleTraversalRule::FILTER_MATCH) {
mozAccessible* nativeMatch = GetNativeFromGeckoAccessible(aAccOrProxy);
if (![[nativeMatch moxVisited] boolValue]) {
result &= ~nsIAccessibleTraversalRule::FILTER_MATCH;
}
}
@ -197,54 +182,14 @@ RotorUnvisitedLinkRule::RotorUnvisitedLinkRule(
: RotorLinkRule(aDirectDescendantsFrom) {}
uint16_t RotorUnvisitedLinkRule::Match(const AccessibleOrProxy& aAccOrProxy) {
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
uint16_t result = RotorLinkRule::Match(aAccOrProxy);
if (nsAccUtils::MustPrune(aAccOrProxy)) {
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
if (!mDirectDescendantsFrom.IsNull() &&
(aAccOrProxy != mDirectDescendantsFrom)) {
// If we've specified mDirectDescendantsFrom, we should ignore
// non-direct descendants of from the specified AoP. Because
// pivot performs a preorder traversal, the first aAccOrProxy
// object(s) that don't equal mDirectDescendantsFrom will be
// mDirectDescendantsFrom's children. We'll process them, but ignore
// their subtrees thereby processing direct descendants of
// mDirectDescendantsFrom only.
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
if (mozAccessible* nativeMatch = GetNativeFromGeckoAccessible(aAccOrProxy)) {
if ([[nativeMatch moxRole] isEqualToString:@"AXLink"] &&
[[nativeMatch moxVisited] boolValue] == NO) {
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
if (result & nsIAccessibleTraversalRule::FILTER_MATCH) {
mozAccessible* nativeMatch = GetNativeFromGeckoAccessible(aAccOrProxy);
if ([[nativeMatch moxVisited] boolValue]) {
result &= ~nsIAccessibleTraversalRule::FILTER_MATCH;
}
}
return result;
}
// Match All Rule
RotorAllRule::RotorAllRule(AccessibleOrProxy& aDirectDescendantsFrom)
: mDirectDescendantsFrom(aDirectDescendantsFrom) {}
RotorAllRule::RotorAllRule() : mDirectDescendantsFrom(nullptr) {}
uint16_t RotorAllRule::Match(const AccessibleOrProxy& aAccOrProxy) {
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
if (nsAccUtils::MustPrune(aAccOrProxy)) {
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
if (!mDirectDescendantsFrom.IsNull() &&
(aAccOrProxy != mDirectDescendantsFrom)) {
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
}
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
return result;
}