зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1652809: Convert Pivot framework to use AccessibleOrProxy objects r=eeejay
Differential Revision: https://phabricator.services.mozilla.com/D83671
This commit is contained in:
Родитель
2c9e686a8d
Коммит
95e4d6df8e
|
@ -296,10 +296,13 @@ bool AccessibleWrap::GetSelectionBounds(int32_t* aStartOffset,
|
|||
|
||||
void AccessibleWrap::Pivot(int32_t aGranularity, bool aForward,
|
||||
bool aInclusive) {
|
||||
a11y::Pivot pivot(RootAccessible());
|
||||
AccessibleOrProxy accOrProxyRoot = AccessibleOrProxy(RootAccessible());
|
||||
a11y::Pivot pivot(accOrProxyRoot);
|
||||
TraversalRule rule(aGranularity);
|
||||
Accessible* result = aForward ? pivot.Next(this, rule, aInclusive)
|
||||
: pivot.Prev(this, rule, aInclusive);
|
||||
AccessibleOrProxy accOrProxy = AccessibleOrProxy(this);
|
||||
Accessible* result =
|
||||
aForward ? pivot.Next(accOrProxy, rule, aInclusive).AsAccessible()
|
||||
: pivot.Prev(accOrProxy, rule, aInclusive).AsAccessible();
|
||||
if (result && (result != this || aInclusive)) {
|
||||
PivotMoveReason reason = aForward ? nsIAccessiblePivot::REASON_NEXT
|
||||
: nsIAccessiblePivot::REASON_PREV;
|
||||
|
@ -314,7 +317,7 @@ void AccessibleWrap::ExploreByTouch(float aX, float aY) {
|
|||
a11y::Pivot pivot(RootAccessible());
|
||||
TraversalRule rule;
|
||||
|
||||
Accessible* result = pivot.AtPoint(aX, aY, rule);
|
||||
Accessible* result = pivot.AtPoint(aX, aY, rule).AsAccessible();
|
||||
|
||||
if (result && result != this) {
|
||||
RefPtr<AccEvent> event =
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "AccessibleOrProxy.h"
|
||||
#include "DocAccessibleChild.h"
|
||||
#include "DocAccessibleWrap.h"
|
||||
#include "nsIDocShell.h"
|
||||
|
@ -157,10 +158,11 @@ void DocAccessibleWrap::CacheViewportCallback(nsITimer* aTimer,
|
|||
}
|
||||
|
||||
if (docAcc->mCachePivotBoundaries) {
|
||||
a11y::Pivot pivot(docAcc);
|
||||
AccessibleOrProxy accOrProxy = AccessibleOrProxy(docAcc);
|
||||
a11y::Pivot pivot(accOrProxy);
|
||||
TraversalRule rule(java::SessionAccessibility::HTML_GRANULARITY_DEFAULT);
|
||||
Accessible* first = pivot.First(rule);
|
||||
Accessible* last = pivot.Last(rule);
|
||||
Accessible* first = pivot.First(rule).AsAccessible();
|
||||
Accessible* last = pivot.Last(rule).AsAccessible();
|
||||
|
||||
// If first/last are null, pass the root document as pivot boundary.
|
||||
if (IPCAccessibilityActive()) {
|
||||
|
|
|
@ -25,7 +25,10 @@ TraversalRule::TraversalRule()
|
|||
TraversalRule::TraversalRule(int32_t aGranularity)
|
||||
: mGranularity(aGranularity) {}
|
||||
|
||||
uint16_t TraversalRule::Match(Accessible* aAccessible) {
|
||||
uint16_t TraversalRule::Match(const AccessibleOrProxy& aAccOrProxy) {
|
||||
MOZ_ASSERT(aAccOrProxy.IsAccessible(),
|
||||
"Should only receive accessibles when processing on android.");
|
||||
Accessible* aAccessible = aAccOrProxy.AsAccessible();
|
||||
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
|
||||
if (nsAccUtils::MustPrune(aAccessible)) {
|
||||
|
|
|
@ -24,7 +24,7 @@ class TraversalRule final : public PivotRule {
|
|||
|
||||
~TraversalRule() = default;
|
||||
|
||||
virtual uint16_t Match(Accessible* aAccessible) override;
|
||||
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
|
||||
|
||||
private:
|
||||
bool IsSingleLineage(Accessible* aAccessible);
|
||||
|
|
|
@ -61,6 +61,11 @@ class AccessibleOrProxy {
|
|||
return AsAccessible()->ChildCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the object has children, false otherwise
|
||||
*/
|
||||
bool HasChildren() const { return ChildCount() > 0; }
|
||||
|
||||
/**
|
||||
* Return the child object either an accessible or a proxied accessible at
|
||||
* the given index.
|
||||
|
@ -110,6 +115,28 @@ class AccessibleOrProxy {
|
|||
return AsAccessible()->LastChild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next sibling object.
|
||||
*/
|
||||
AccessibleOrProxy NextSibling() {
|
||||
if (IsProxy()) {
|
||||
return AsProxy()->NextSibling();
|
||||
}
|
||||
|
||||
return AsAccessible()->NextSibling();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prev sibling object.
|
||||
*/
|
||||
AccessibleOrProxy PrevSibling() {
|
||||
if (IsProxy()) {
|
||||
return AsProxy()->PrevSibling();
|
||||
}
|
||||
|
||||
return AsAccessible()->PrevSibling();
|
||||
}
|
||||
|
||||
role Role() const {
|
||||
if (IsProxy()) {
|
||||
return AsProxy()->Role();
|
||||
|
|
|
@ -21,18 +21,21 @@ using namespace mozilla::a11y;
|
|||
// Pivot
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Pivot::Pivot(Accessible* aRoot) : mRoot(aRoot) { MOZ_COUNT_CTOR(Pivot); }
|
||||
Pivot::Pivot(const AccessibleOrProxy& aRoot) : mRoot(aRoot) {
|
||||
MOZ_COUNT_CTOR(Pivot);
|
||||
}
|
||||
|
||||
Pivot::~Pivot() { MOZ_COUNT_DTOR(Pivot); }
|
||||
|
||||
Accessible* Pivot::AdjustStartPosition(Accessible* aAnchor, PivotRule& aRule,
|
||||
AccessibleOrProxy Pivot::AdjustStartPosition(AccessibleOrProxy& aAnchor,
|
||||
PivotRule& aRule,
|
||||
uint16_t* aFilterResult) {
|
||||
Accessible* matched = aAnchor;
|
||||
AccessibleOrProxy matched = aAnchor;
|
||||
*aFilterResult = aRule.Match(aAnchor);
|
||||
|
||||
if (aAnchor != mRoot) {
|
||||
for (Accessible* temp = aAnchor->Parent(); temp && temp != mRoot;
|
||||
temp = temp->Parent()) {
|
||||
for (AccessibleOrProxy temp = aAnchor.Parent();
|
||||
!temp.IsNull() && temp != mRoot; temp = temp.Parent()) {
|
||||
uint16_t filtered = aRule.Match(temp);
|
||||
if (filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) {
|
||||
*aFilterResult = filtered;
|
||||
|
@ -44,111 +47,120 @@ Accessible* Pivot::AdjustStartPosition(Accessible* aAnchor, PivotRule& aRule,
|
|||
return matched;
|
||||
}
|
||||
|
||||
Accessible* Pivot::SearchBackward(Accessible* aAnchor, PivotRule& aRule,
|
||||
bool aSearchCurrent) {
|
||||
// Initial position could be unset, in that case return null.
|
||||
if (!aAnchor) {
|
||||
return nullptr;
|
||||
AccessibleOrProxy Pivot::SearchBackward(AccessibleOrProxy& aAnchor,
|
||||
PivotRule& aRule, bool aSearchCurrent) {
|
||||
// Initial position could be unset, in that case return null AoP.
|
||||
if (aAnchor.IsNull()) {
|
||||
return aAnchor;
|
||||
}
|
||||
|
||||
uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
|
||||
Accessible* accessible = AdjustStartPosition(aAnchor, aRule, &filtered);
|
||||
AccessibleOrProxy accOrProxy = AdjustStartPosition(aAnchor, aRule, &filtered);
|
||||
|
||||
if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)) {
|
||||
return accessible;
|
||||
return accOrProxy;
|
||||
}
|
||||
|
||||
while (accessible != mRoot) {
|
||||
Accessible* parent = accessible->Parent();
|
||||
int32_t idxInParent = accessible->IndexInParent();
|
||||
while (accOrProxy != mRoot) {
|
||||
AccessibleOrProxy parent = accOrProxy.Parent();
|
||||
int32_t idxInParent = accOrProxy.IndexInParent();
|
||||
while (idxInParent > 0) {
|
||||
if (!(accessible = parent->GetChildAt(--idxInParent))) {
|
||||
accOrProxy = parent.ChildAt(--idxInParent);
|
||||
if (accOrProxy.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filtered = aRule.Match(accessible);
|
||||
filtered = aRule.Match(accOrProxy);
|
||||
|
||||
Accessible* lastChild = nullptr;
|
||||
AccessibleOrProxy lastChild = accOrProxy.LastChild();
|
||||
while (!(filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) &&
|
||||
(lastChild = accessible->LastChild())) {
|
||||
parent = accessible;
|
||||
accessible = lastChild;
|
||||
idxInParent = accessible->IndexInParent();
|
||||
filtered = aRule.Match(accessible);
|
||||
!lastChild.IsNull()) {
|
||||
parent = accOrProxy;
|
||||
accOrProxy = lastChild;
|
||||
idxInParent = accOrProxy.IndexInParent();
|
||||
filtered = aRule.Match(accOrProxy);
|
||||
lastChild = accOrProxy.LastChild();
|
||||
}
|
||||
|
||||
if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH) {
|
||||
return accessible;
|
||||
return accOrProxy;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(accessible = parent)) {
|
||||
accOrProxy = parent;
|
||||
if (accOrProxy.IsNull()) {
|
||||
break;
|
||||
}
|
||||
|
||||
filtered = aRule.Match(accessible);
|
||||
filtered = aRule.Match(accOrProxy);
|
||||
|
||||
if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH) {
|
||||
return accessible;
|
||||
return accOrProxy;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return AccessibleOrProxy();
|
||||
}
|
||||
|
||||
Accessible* Pivot::SearchForward(Accessible* aAnchor, PivotRule& aRule,
|
||||
bool aSearchCurrent) {
|
||||
AccessibleOrProxy Pivot::SearchForward(AccessibleOrProxy& aAnchor,
|
||||
PivotRule& aRule, bool aSearchCurrent) {
|
||||
// Initial position could be not set, in that case begin search from root.
|
||||
Accessible* accessible = aAnchor ? aAnchor : mRoot;
|
||||
AccessibleOrProxy accOrProxy = !aAnchor.IsNull() ? aAnchor : mRoot;
|
||||
|
||||
uint16_t filtered = nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
accessible = AdjustStartPosition(accessible, aRule, &filtered);
|
||||
accOrProxy = AdjustStartPosition(accOrProxy, aRule, &filtered);
|
||||
if (aSearchCurrent && (filtered & nsIAccessibleTraversalRule::FILTER_MATCH)) {
|
||||
return accessible;
|
||||
return accOrProxy;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
Accessible* firstChild = nullptr;
|
||||
AccessibleOrProxy firstChild = accOrProxy.FirstChild();
|
||||
while (!(filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) &&
|
||||
(firstChild = accessible->FirstChild())) {
|
||||
accessible = firstChild;
|
||||
filtered = aRule.Match(accessible);
|
||||
!firstChild.IsNull()) {
|
||||
accOrProxy = firstChild;
|
||||
filtered = aRule.Match(accOrProxy);
|
||||
|
||||
if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH) {
|
||||
return accessible;
|
||||
return accOrProxy;
|
||||
}
|
||||
firstChild = accOrProxy.FirstChild();
|
||||
}
|
||||
|
||||
Accessible* sibling = nullptr;
|
||||
Accessible* temp = accessible;
|
||||
AccessibleOrProxy sibling = AccessibleOrProxy();
|
||||
AccessibleOrProxy temp = accOrProxy;
|
||||
do {
|
||||
if (temp == mRoot) {
|
||||
break;
|
||||
}
|
||||
|
||||
sibling = temp->NextSibling();
|
||||
sibling = temp.NextSibling();
|
||||
|
||||
if (sibling) {
|
||||
if (!sibling.IsNull()) {
|
||||
break;
|
||||
}
|
||||
} while ((temp = temp->Parent()));
|
||||
temp = temp.Parent();
|
||||
} while (!temp.IsNull());
|
||||
|
||||
if (!sibling) {
|
||||
if (sibling.IsNull()) {
|
||||
break;
|
||||
}
|
||||
|
||||
accessible = sibling;
|
||||
filtered = aRule.Match(accessible);
|
||||
accOrProxy = sibling;
|
||||
filtered = aRule.Match(accOrProxy);
|
||||
if (filtered & nsIAccessibleTraversalRule::FILTER_MATCH) {
|
||||
return accessible;
|
||||
return accOrProxy;
|
||||
}
|
||||
}
|
||||
|
||||
return AccessibleOrProxy();
|
||||
}
|
||||
|
||||
// TODO: This method does not work for proxy accessibles
|
||||
HyperTextAccessible* Pivot::SearchForText(Accessible* aAnchor, bool aBackward) {
|
||||
if (!mRoot.IsAccessible()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HyperTextAccessible* Pivot::SearchForText(Accessible* aAnchor, bool aBackward) {
|
||||
Accessible* accessible = aAnchor;
|
||||
while (true) {
|
||||
Accessible* child = nullptr;
|
||||
|
@ -164,7 +176,7 @@ HyperTextAccessible* Pivot::SearchForText(Accessible* aAnchor, bool aBackward) {
|
|||
Accessible* sibling = nullptr;
|
||||
Accessible* temp = accessible;
|
||||
do {
|
||||
if (temp == mRoot) {
|
||||
if (temp == mRoot.AsAccessible()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -196,35 +208,40 @@ HyperTextAccessible* Pivot::SearchForText(Accessible* aAnchor, bool aBackward) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Accessible* Pivot::Next(Accessible* aAnchor, PivotRule& aRule,
|
||||
AccessibleOrProxy Pivot::Next(AccessibleOrProxy& aAnchor, PivotRule& aRule,
|
||||
bool aIncludeStart) {
|
||||
return SearchForward(aAnchor, aRule, aIncludeStart);
|
||||
}
|
||||
|
||||
Accessible* Pivot::Prev(Accessible* aAnchor, PivotRule& aRule,
|
||||
AccessibleOrProxy Pivot::Prev(AccessibleOrProxy& aAnchor, PivotRule& aRule,
|
||||
bool aIncludeStart) {
|
||||
return SearchBackward(aAnchor, aRule, aIncludeStart);
|
||||
}
|
||||
|
||||
Accessible* Pivot::First(PivotRule& aRule) {
|
||||
AccessibleOrProxy Pivot::First(PivotRule& aRule) {
|
||||
return SearchForward(mRoot, aRule, true);
|
||||
}
|
||||
|
||||
Accessible* Pivot::Last(PivotRule& aRule) {
|
||||
Accessible* lastAccessible = mRoot;
|
||||
AccessibleOrProxy Pivot::Last(PivotRule& aRule) {
|
||||
AccessibleOrProxy lastAccOrProxy = mRoot;
|
||||
|
||||
// First go to the last accessible in pre-order
|
||||
while (lastAccessible->HasChildren()) {
|
||||
lastAccessible = lastAccessible->LastChild();
|
||||
while (lastAccOrProxy.HasChildren()) {
|
||||
lastAccOrProxy = lastAccOrProxy.LastChild();
|
||||
}
|
||||
|
||||
// Search backwards from last accessible and find the last occurrence in the
|
||||
// doc
|
||||
return SearchBackward(lastAccessible, aRule, true);
|
||||
return SearchBackward(lastAccOrProxy, aRule, true);
|
||||
}
|
||||
|
||||
// TODO: This method does not work for proxy accessibles
|
||||
Accessible* Pivot::NextText(Accessible* aAnchor, int32_t* aStartOffset,
|
||||
int32_t* aEndOffset, int32_t aBoundaryType) {
|
||||
if (!mRoot.IsAccessible()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t tempStart = *aStartOffset, tempEnd = *aEndOffset;
|
||||
Accessible* tempPosition = aAnchor;
|
||||
|
||||
|
@ -272,7 +289,7 @@ Accessible* Pivot::NextText(Accessible* aAnchor, int32_t* aStartOffset,
|
|||
// If there's no more text on the current node, try to find the next text
|
||||
// node; if there isn't one, bail out.
|
||||
if (tempEnd == static_cast<int32_t>(text->CharacterCount())) {
|
||||
if (tempPosition == mRoot) {
|
||||
if (tempPosition == mRoot.AsAccessible()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -357,8 +374,13 @@ Accessible* Pivot::NextText(Accessible* aAnchor, int32_t* aStartOffset,
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: This method does not work for proxy accessibles
|
||||
Accessible* Pivot::PrevText(Accessible* aAnchor, int32_t* aStartOffset,
|
||||
int32_t* aEndOffset, int32_t aBoundaryType) {
|
||||
if (!mRoot.IsAccessible()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t tempStart = *aStartOffset, tempEnd = *aEndOffset;
|
||||
Accessible* tempPosition = aAnchor;
|
||||
|
||||
|
@ -411,7 +433,7 @@ Accessible* Pivot::PrevText(Accessible* aAnchor, int32_t* aStartOffset,
|
|||
// If there's no more text on the current node, try to find the previous
|
||||
// text node; if there isn't one, bail out.
|
||||
if (tempStart == 0) {
|
||||
if (tempPosition == mRoot) {
|
||||
if (tempPosition == mRoot.AsAccessible()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -507,20 +529,24 @@ Accessible* Pivot::PrevText(Accessible* aAnchor, int32_t* aStartOffset,
|
|||
}
|
||||
}
|
||||
|
||||
Accessible* Pivot::AtPoint(int32_t aX, int32_t aY, PivotRule& aRule) {
|
||||
Accessible* match = nullptr;
|
||||
Accessible* child = mRoot->ChildAtPoint(aX, aY, Accessible::eDeepestChild);
|
||||
while (child && mRoot != child) {
|
||||
AccessibleOrProxy Pivot::AtPoint(int32_t aX, int32_t aY, PivotRule& aRule) {
|
||||
AccessibleOrProxy match = AccessibleOrProxy();
|
||||
AccessibleOrProxy child =
|
||||
mRoot.ChildAtPoint(aX, aY, Accessible::eDeepestChild);
|
||||
while (!child.IsNull() && (mRoot != child)) {
|
||||
uint16_t filtered = aRule.Match(child);
|
||||
|
||||
// Ignore any matching nodes that were below this one
|
||||
if (filtered & nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE) {
|
||||
match = nullptr;
|
||||
match = AccessibleOrProxy();
|
||||
}
|
||||
|
||||
// Match if no node below this is a match
|
||||
if ((filtered & nsIAccessibleTraversalRule::FILTER_MATCH) && !match) {
|
||||
nsIntRect childRect = child->Bounds();
|
||||
if ((filtered & nsIAccessibleTraversalRule::FILTER_MATCH) &&
|
||||
match.IsNull()) {
|
||||
nsIntRect childRect = child.IsAccessible()
|
||||
? child.AsAccessible()->Bounds()
|
||||
: child.AsProxy()->Bounds();
|
||||
// Double-check child's bounds since the deepest child may have been out
|
||||
// of bounds. This assures we don't return a false positive.
|
||||
if (childRect.Contains(aX, aY)) {
|
||||
|
@ -528,7 +554,7 @@ Accessible* Pivot::AtPoint(int32_t aX, int32_t aY, PivotRule& aRule) {
|
|||
}
|
||||
}
|
||||
|
||||
child = child->Parent();
|
||||
child = child.Parent();
|
||||
}
|
||||
|
||||
return match;
|
||||
|
@ -538,14 +564,28 @@ Accessible* Pivot::AtPoint(int32_t aX, int32_t aY, PivotRule& aRule) {
|
|||
|
||||
PivotRoleRule::PivotRoleRule(mozilla::a11y::role aRole) : mRole(aRole) {}
|
||||
|
||||
uint16_t PivotRoleRule::Match(Accessible* aAccessible) {
|
||||
uint16_t PivotRoleRule::Match(const AccessibleOrProxy& aAccOrProxy) {
|
||||
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
|
||||
if (nsAccUtils::MustPrune(aAccessible)) {
|
||||
if (nsAccUtils::MustPrune(aAccOrProxy)) {
|
||||
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
|
||||
if (aAccessible->Role() == mRole) {
|
||||
if (aAccOrProxy.Role() == mRole) {
|
||||
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Match All Rule
|
||||
|
||||
uint16_t PivotMatchAllRule::Match(const AccessibleOrProxy& aAccOrProxy) {
|
||||
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
|
||||
if (nsAccUtils::MustPrune(aAccOrProxy)) {
|
||||
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
} else {
|
||||
result |= nsIAccessibleTraversalRule::FILTER_MATCH;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <stdint.h>
|
||||
#include "Role.h"
|
||||
#include "mozilla/dom/ChildIterator.h"
|
||||
#include "AccessibleOrProxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
@ -23,7 +24,7 @@ class PivotRule {
|
|||
// nsIAccessibleTraversalRule: FILTER_IGNORE (0x0): Don't match this
|
||||
// accessible. FILTER_MATCH (0x1): Match this accessible FILTER_IGNORE_SUBTREE
|
||||
// (0x2): Ignore accessible's subtree.
|
||||
virtual uint16_t Match(Accessible* aAccessible) = 0;
|
||||
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) = 0;
|
||||
};
|
||||
|
||||
// The Pivot class is used for searching for accessible nodes in a given subtree
|
||||
|
@ -31,7 +32,7 @@ class PivotRule {
|
|||
// this class is meant to be used primarily on the stack.
|
||||
class Pivot final {
|
||||
public:
|
||||
explicit Pivot(Accessible* aRoot);
|
||||
explicit Pivot(const AccessibleOrProxy& aRoot);
|
||||
Pivot() = delete;
|
||||
Pivot(const Pivot&) = delete;
|
||||
Pivot& operator=(const Pivot&) = delete;
|
||||
|
@ -40,19 +41,19 @@ class Pivot final {
|
|||
|
||||
// Return the next accessible after aAnchor in pre-order that matches the
|
||||
// given rule. If aIncludeStart, return aAnchor if it matches the rule.
|
||||
Accessible* Next(Accessible* aAnchor, PivotRule& aRule,
|
||||
AccessibleOrProxy Next(AccessibleOrProxy& aAnchor, PivotRule& aRule,
|
||||
bool aIncludeStart = false);
|
||||
|
||||
// Return the previous accessible before aAnchor in pre-order that matches the
|
||||
// given rule. If aIncludeStart, return aAnchor if it matches the rule.
|
||||
Accessible* Prev(Accessible* aAnchor, PivotRule& aRule,
|
||||
AccessibleOrProxy Prev(AccessibleOrProxy& aAnchor, PivotRule& aRule,
|
||||
bool aIncludeStart = false);
|
||||
|
||||
// Return the first accessible within the root that matches the pivot rule.
|
||||
Accessible* First(PivotRule& aRule);
|
||||
AccessibleOrProxy First(PivotRule& aRule);
|
||||
|
||||
// Return the last accessible within the root that matches the pivot rule.
|
||||
Accessible* Last(PivotRule& aRule);
|
||||
AccessibleOrProxy Last(PivotRule& aRule);
|
||||
|
||||
// Return the next range of text according to the boundary type.
|
||||
Accessible* NextText(Accessible* aAnchor, int32_t* aStartOffset,
|
||||
|
@ -64,24 +65,25 @@ class Pivot final {
|
|||
|
||||
// Return the accessible at the given screen coordinate if it matches the
|
||||
// pivot rule.
|
||||
Accessible* AtPoint(int32_t aX, int32_t aY, PivotRule& aRule);
|
||||
AccessibleOrProxy AtPoint(int32_t aX, int32_t aY, PivotRule& aRule);
|
||||
|
||||
private:
|
||||
Accessible* AdjustStartPosition(Accessible* aAnchor, PivotRule& aRule,
|
||||
AccessibleOrProxy AdjustStartPosition(AccessibleOrProxy& aAnchor,
|
||||
PivotRule& aRule,
|
||||
uint16_t* aFilterResult);
|
||||
|
||||
// Search in preorder for the first accessible to match the rule.
|
||||
Accessible* SearchForward(Accessible* aAnchor, PivotRule& aRule,
|
||||
AccessibleOrProxy SearchForward(AccessibleOrProxy& aAnchor, PivotRule& aRule,
|
||||
bool aSearchCurrent);
|
||||
|
||||
// Reverse search in preorder for the first accessible to match the rule.
|
||||
Accessible* SearchBackward(Accessible* aAnchor, PivotRule& aRule,
|
||||
AccessibleOrProxy SearchBackward(AccessibleOrProxy& aAnchor, PivotRule& aRule,
|
||||
bool aSearchCurrent);
|
||||
|
||||
// Search in preorder for the first text accessible.
|
||||
HyperTextAccessible* SearchForText(Accessible* aAnchor, bool aBackward);
|
||||
|
||||
Accessible* mRoot;
|
||||
AccessibleOrProxy mRoot;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -91,12 +93,20 @@ class PivotRoleRule final : public PivotRule {
|
|||
public:
|
||||
explicit PivotRoleRule(role aRole);
|
||||
|
||||
virtual uint16_t Match(Accessible* aAccessible) override;
|
||||
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
|
||||
|
||||
private:
|
||||
role mRole;
|
||||
};
|
||||
|
||||
/**
|
||||
* This rule matches all accessibles.
|
||||
*/
|
||||
class PivotMatchAllRule final : public PivotRule {
|
||||
public:
|
||||
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class RuleCache : public PivotRule {
|
|||
: mRule(aRule), mPreFilter{0} {}
|
||||
~RuleCache() {}
|
||||
|
||||
virtual uint16_t Match(Accessible* aAccessible) override;
|
||||
virtual uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIAccessibleTraversalRule> mRule;
|
||||
|
@ -204,11 +204,17 @@ nsAccessiblePivot::MoveNext(nsIAccessibleTraversalRule* aRule,
|
|||
|
||||
Pivot pivot(GetActiveRoot());
|
||||
RuleCache rule(aRule);
|
||||
|
||||
if (Accessible* newPos =
|
||||
pivot.Next(anchor, rule, (aArgc > 1) ? aIncludeStart : false)) {
|
||||
*aResult = MovePivotInternal(newPos, nsIAccessiblePivot::REASON_NEXT,
|
||||
AccessibleOrProxy wrappedAnchor = AccessibleOrProxy(anchor);
|
||||
AccessibleOrProxy newPos =
|
||||
pivot.Next(wrappedAnchor, rule, (aArgc > 1) ? aIncludeStart : false);
|
||||
if (!newPos.IsNull() && newPos.IsAccessible()) {
|
||||
*aResult = MovePivotInternal(newPos.AsAccessible(),
|
||||
nsIAccessiblePivot::REASON_NEXT,
|
||||
(aArgc > 2) ? aIsFromUserInput : true);
|
||||
} else if (newPos.IsProxy()) {
|
||||
// we shouldn't ever end up with a proxy here, but if we do for some
|
||||
// reason something is wrong. we should still return OK if we're null
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -232,11 +238,17 @@ nsAccessiblePivot::MovePrevious(nsIAccessibleTraversalRule* aRule,
|
|||
|
||||
Pivot pivot(GetActiveRoot());
|
||||
RuleCache rule(aRule);
|
||||
|
||||
if (Accessible* newPos =
|
||||
pivot.Prev(anchor, rule, (aArgc > 1) ? aIncludeStart : false)) {
|
||||
*aResult = MovePivotInternal(newPos, nsIAccessiblePivot::REASON_PREV,
|
||||
AccessibleOrProxy wrappedAnchor = AccessibleOrProxy(anchor);
|
||||
AccessibleOrProxy newPos =
|
||||
pivot.Prev(wrappedAnchor, rule, (aArgc > 1) ? aIncludeStart : false);
|
||||
if (!newPos.IsNull() && newPos.IsAccessible()) {
|
||||
*aResult = MovePivotInternal(newPos.AsAccessible(),
|
||||
nsIAccessiblePivot::REASON_PREV,
|
||||
(aArgc > 2) ? aIsFromUserInput : true);
|
||||
} else if (newPos.IsProxy()) {
|
||||
// we shouldn't ever end up with a proxy here, but if we do for some
|
||||
// reason something is wrong. we should still return OK if we're null
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -254,10 +266,15 @@ nsAccessiblePivot::MoveFirst(nsIAccessibleTraversalRule* aRule,
|
|||
|
||||
Pivot pivot(GetActiveRoot());
|
||||
RuleCache rule(aRule);
|
||||
|
||||
if (Accessible* newPos = pivot.First(rule)) {
|
||||
*aResult = MovePivotInternal(newPos, nsIAccessiblePivot::REASON_FIRST,
|
||||
AccessibleOrProxy newPos = pivot.First(rule);
|
||||
if (!newPos.IsNull() && newPos.IsAccessible()) {
|
||||
*aResult = MovePivotInternal(newPos.AsAccessible(),
|
||||
nsIAccessiblePivot::REASON_FIRST,
|
||||
(aArgc > 0) ? aIsFromUserInput : true);
|
||||
} else if (newPos.IsProxy()) {
|
||||
// we shouldn't ever end up with a proxy here, but if we do for some
|
||||
// reason something is wrong. we should still return OK if we're null
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -275,10 +292,15 @@ nsAccessiblePivot::MoveLast(nsIAccessibleTraversalRule* aRule,
|
|||
|
||||
Pivot pivot(root);
|
||||
RuleCache rule(aRule);
|
||||
|
||||
if (Accessible* newPos = pivot.Last(rule)) {
|
||||
*aResult = MovePivotInternal(newPos, nsIAccessiblePivot::REASON_LAST,
|
||||
AccessibleOrProxy newPos = pivot.Last(rule);
|
||||
if (!newPos.IsNull() && newPos.IsAccessible()) {
|
||||
*aResult = MovePivotInternal(newPos.AsAccessible(),
|
||||
nsIAccessiblePivot::REASON_LAST,
|
||||
(aArgc > 0) ? aIsFromUserInput : true);
|
||||
} else if (newPos.IsProxy()) {
|
||||
// we shouldn't ever end up with a proxy here, but if we do for some
|
||||
// reason something is wrong. we should still return OK if we're null
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -295,8 +317,8 @@ nsAccessiblePivot::MoveNextByText(TextBoundaryType aBoundary,
|
|||
Pivot pivot(GetActiveRoot());
|
||||
|
||||
int32_t newStart = mStartOffset, newEnd = mEndOffset;
|
||||
if (Accessible* newPos =
|
||||
pivot.NextText(mPosition, &newStart, &newEnd, aBoundary)) {
|
||||
Accessible* newPos = pivot.NextText(mPosition, &newStart, &newEnd, aBoundary);
|
||||
if (newPos) {
|
||||
*aResult = true;
|
||||
int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
|
||||
Accessible* oldPos = mPosition;
|
||||
|
@ -322,8 +344,8 @@ nsAccessiblePivot::MovePreviousByText(TextBoundaryType aBoundary,
|
|||
Pivot pivot(GetActiveRoot());
|
||||
|
||||
int32_t newStart = mStartOffset, newEnd = mEndOffset;
|
||||
if (Accessible* newPos =
|
||||
pivot.PrevText(mPosition, &newStart, &newEnd, aBoundary)) {
|
||||
Accessible* newPos = pivot.PrevText(mPosition, &newStart, &newEnd, aBoundary);
|
||||
if (newPos) {
|
||||
*aResult = true;
|
||||
int32_t oldStart = mStartOffset, oldEnd = mEndOffset;
|
||||
Accessible* oldPos = mPosition;
|
||||
|
@ -354,10 +376,16 @@ nsAccessiblePivot::MoveToPoint(nsIAccessibleTraversalRule* aRule, int32_t aX,
|
|||
RuleCache rule(aRule);
|
||||
Pivot pivot(root);
|
||||
|
||||
Accessible* newPos = pivot.AtPoint(aX, aY, rule);
|
||||
if (newPos || !aIgnoreNoMatch) {
|
||||
*aResult = MovePivotInternal(newPos, nsIAccessiblePivot::REASON_POINT,
|
||||
AccessibleOrProxy newPos = pivot.AtPoint(aX, aY, rule);
|
||||
if ((!newPos.IsNull() && newPos.IsAccessible()) ||
|
||||
!aIgnoreNoMatch) { // TODO does this need a proxy check?
|
||||
*aResult = MovePivotInternal(newPos.AsAccessible(),
|
||||
nsIAccessiblePivot::REASON_POINT,
|
||||
(aArgc > 0) ? aIsFromUserInput : true);
|
||||
} else if (newPos.IsProxy()) {
|
||||
// we shouldn't ever end up with a proxy here, but if we do for some
|
||||
// reason something is wrong. we should still return OK if we're null
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -427,7 +455,7 @@ bool nsAccessiblePivot::NotifyOfPivotChange(Accessible* aOldPosition,
|
|||
return true;
|
||||
}
|
||||
|
||||
uint16_t RuleCache::Match(Accessible* aAccessible) {
|
||||
uint16_t RuleCache::Match(const AccessibleOrProxy& aAccOrProxy) {
|
||||
uint16_t result = nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
|
||||
if (!mAcceptRoles) {
|
||||
|
@ -439,10 +467,15 @@ uint16_t RuleCache::Match(Accessible* aAccessible) {
|
|||
}
|
||||
|
||||
if (mPreFilter) {
|
||||
uint64_t state = aAccessible->State();
|
||||
uint64_t state;
|
||||
if (aAccOrProxy.IsAccessible()) {
|
||||
state = aAccOrProxy.AsAccessible()->State();
|
||||
} else {
|
||||
state = aAccOrProxy.AsProxy()->State();
|
||||
}
|
||||
|
||||
if ((nsIAccessibleTraversalRule::PREFILTER_PLATFORM_PRUNED & mPreFilter) &&
|
||||
nsAccUtils::MustPrune(aAccessible)) {
|
||||
nsAccUtils::MustPrune(aAccOrProxy)) {
|
||||
result |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
|
||||
|
@ -458,9 +491,10 @@ uint16_t RuleCache::Match(Accessible* aAccessible) {
|
|||
!(state & states::FOCUSABLE))
|
||||
return result;
|
||||
|
||||
if ((nsIAccessibleTraversalRule::PREFILTER_TRANSPARENT & mPreFilter) &&
|
||||
if (aAccOrProxy.IsAccessible() &&
|
||||
(nsIAccessibleTraversalRule::PREFILTER_TRANSPARENT & mPreFilter) &&
|
||||
!(state & states::OPAQUE1)) {
|
||||
nsIFrame* frame = aAccessible->GetFrame();
|
||||
nsIFrame* frame = aAccOrProxy.AsAccessible()->GetFrame();
|
||||
if (frame->StyleEffects()->mOpacity == 0.0f) {
|
||||
return result | nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
|
||||
}
|
||||
|
@ -468,7 +502,7 @@ uint16_t RuleCache::Match(Accessible* aAccessible) {
|
|||
}
|
||||
|
||||
if (mAcceptRoles->Length() > 0) {
|
||||
uint32_t accessibleRole = aAccessible->Role();
|
||||
uint32_t accessibleRole = aAccOrProxy.Role();
|
||||
bool matchesRole = false;
|
||||
for (uint32_t idx = 0; idx < mAcceptRoles->Length(); idx++) {
|
||||
matchesRole = mAcceptRoles->ElementAt(idx) == accessibleRole;
|
||||
|
@ -481,7 +515,7 @@ uint16_t RuleCache::Match(Accessible* aAccessible) {
|
|||
}
|
||||
|
||||
uint16_t matchResult = nsIAccessibleTraversalRule::FILTER_IGNORE;
|
||||
DebugOnly<nsresult> rv = mRule->Match(ToXPC(aAccessible), &matchResult);
|
||||
DebugOnly<nsresult> rv = mRule->Match(ToXPC(aAccOrProxy), &matchResult);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
return result | matchResult;
|
||||
|
|
|
@ -1718,9 +1718,14 @@ Relation Accessible::RelationByType(RelationType aType) const {
|
|||
* was called from, which is expected. */
|
||||
Pivot p = Pivot(currParent);
|
||||
PivotRoleRule rule(roles::RADIOBUTTON);
|
||||
Accessible* match = currParent;
|
||||
while ((match = p.Next(match, rule))) {
|
||||
rel.AppendTarget(match);
|
||||
AccessibleOrProxy wrappedParent = AccessibleOrProxy(currParent);
|
||||
AccessibleOrProxy match = p.Next(wrappedParent, rule);
|
||||
while (!match.IsNull()) {
|
||||
MOZ_ASSERT(
|
||||
!match.IsProxy(),
|
||||
"We shouldn't find any proxy's while building our relation!");
|
||||
rel.AppendTarget(match.AsAccessible());
|
||||
match = p.Next(match, rule);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче