From 95e4d6df8e422b4e9752930ecdaa096abecaa3ff Mon Sep 17 00:00:00 2001 From: Morgan Reschenberg Date: Tue, 28 Jul 2020 22:35:24 +0000 Subject: [PATCH] Bug 1652809: Convert Pivot framework to use AccessibleOrProxy objects r=eeejay Differential Revision: https://phabricator.services.mozilla.com/D83671 --- accessible/android/AccessibleWrap.cpp | 11 +- accessible/android/DocAccessibleWrap.cpp | 10 +- accessible/android/TraversalRule.cpp | 5 +- accessible/android/TraversalRule.h | 4 +- accessible/base/AccessibleOrProxy.h | 27 ++++ accessible/base/Pivot.cpp | 186 ++++++++++++++--------- accessible/base/Pivot.h | 44 +++--- accessible/base/nsAccessiblePivot.cpp | 92 +++++++---- accessible/generic/Accessible.cpp | 11 +- 9 files changed, 257 insertions(+), 133 deletions(-) diff --git a/accessible/android/AccessibleWrap.cpp b/accessible/android/AccessibleWrap.cpp index 6a8828dd706f..72a0b636a71e 100644 --- a/accessible/android/AccessibleWrap.cpp +++ b/accessible/android/AccessibleWrap.cpp @@ -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 event = diff --git a/accessible/android/DocAccessibleWrap.cpp b/accessible/android/DocAccessibleWrap.cpp index f24d48f36e77..d004e7da3239 100644 --- a/accessible/android/DocAccessibleWrap.cpp +++ b/accessible/android/DocAccessibleWrap.cpp @@ -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()) { @@ -295,4 +297,4 @@ void DocAccessibleWrap::UpdateFocusPathBounds() { } } -#undef UNIQUE_ID \ No newline at end of file +#undef UNIQUE_ID diff --git a/accessible/android/TraversalRule.cpp b/accessible/android/TraversalRule.cpp index 551a7b1f0daf..6bc0cda40ca2 100644 --- a/accessible/android/TraversalRule.cpp +++ b/accessible/android/TraversalRule.cpp @@ -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)) { diff --git a/accessible/android/TraversalRule.h b/accessible/android/TraversalRule.h index f6f0c605ba54..46d8d264a4ba 100644 --- a/accessible/android/TraversalRule.h +++ b/accessible/android/TraversalRule.h @@ -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); @@ -53,4 +53,4 @@ class TraversalRule final : public PivotRule { } // namespace a11y } // namespace mozilla -#endif \ No newline at end of file +#endif diff --git a/accessible/base/AccessibleOrProxy.h b/accessible/base/AccessibleOrProxy.h index f2f3708ae77d..9f95333c9b9c 100644 --- a/accessible/base/AccessibleOrProxy.h +++ b/accessible/base/AccessibleOrProxy.h @@ -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(); diff --git a/accessible/base/Pivot.cpp b/accessible/base/Pivot.cpp index 2b18fcf313ef..715daf63bdf3 100644 --- a/accessible/base/Pivot.cpp +++ b/accessible/base/Pivot.cpp @@ -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, - uint16_t* aFilterResult) { - Accessible* matched = aAnchor; +AccessibleOrProxy Pivot::AdjustStartPosition(AccessibleOrProxy& aAnchor, + PivotRule& aRule, + uint16_t* aFilterResult) { + 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 nullptr; + return AccessibleOrProxy(); } +// TODO: This method does not work for proxy accessibles HyperTextAccessible* Pivot::SearchForText(Accessible* aAnchor, bool aBackward) { + if (!mRoot.IsAccessible()) { + return nullptr; + } 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, - bool aIncludeStart) { +AccessibleOrProxy Pivot::Next(AccessibleOrProxy& aAnchor, PivotRule& aRule, + bool aIncludeStart) { return SearchForward(aAnchor, aRule, aIncludeStart); } -Accessible* Pivot::Prev(Accessible* aAnchor, PivotRule& aRule, - bool aIncludeStart) { +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(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; } diff --git a/accessible/base/Pivot.h b/accessible/base/Pivot.h index f13793b27a1d..466c259548dd 100644 --- a/accessible/base/Pivot.h +++ b/accessible/base/Pivot.h @@ -9,6 +9,7 @@ #include #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, - bool aIncludeStart = false); + 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, - bool aIncludeStart = false); + 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, - uint16_t* aFilterResult); + 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, - bool aSearchCurrent); + 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, - bool aSearchCurrent); + 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 diff --git a/accessible/base/nsAccessiblePivot.cpp b/accessible/base/nsAccessiblePivot.cpp index 3b057e4cd0e0..456f6cbde3c2 100644 --- a/accessible/base/nsAccessiblePivot.cpp +++ b/accessible/base/nsAccessiblePivot.cpp @@ -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 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 rv = mRule->Match(ToXPC(aAccessible), &matchResult); + DebugOnly rv = mRule->Match(ToXPC(aAccOrProxy), &matchResult); MOZ_ASSERT(NS_SUCCEEDED(rv)); return result | matchResult; diff --git a/accessible/generic/Accessible.cpp b/accessible/generic/Accessible.cpp index eebd0ec964a9..bb15fa9ef3c5 100644 --- a/accessible/generic/Accessible.cpp +++ b/accessible/generic/Accessible.cpp @@ -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); } }