| Index: ui/accessibility/ax_position.h
|
| diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h
|
| index c38d9511128976a2f0f726799a4a89ff6c464d06..1072586c5cbf00462d72c22f17687503789104a1 100644
|
| --- a/ui/accessibility/ax_position.h
|
| +++ b/ui/accessibility/ax_position.h
|
| @@ -13,11 +13,13 @@
|
| #include <utility>
|
| #include <vector>
|
|
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/stl_util.h"
|
| #include "base/strings/string16.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "ui/accessibility/ax_enums.h"
|
| +#include "ui/accessibility/ax_export.h"
|
|
|
| namespace ui {
|
|
|
| @@ -31,14 +33,19 @@ namespace ui {
|
| enum class AXPositionKind { NULL_POSITION, TREE_POSITION, TEXT_POSITION };
|
|
|
| // Forward declarations.
|
| -template <class AXPositionType, class AXNodeType>
|
| -class AXPosition;
|
| -template <class AXPositionType, class AXNodeType>
|
| -bool operator==(const AXPosition<AXPositionType, AXNodeType>& first,
|
| - const AXPosition<AXPositionType, AXNodeType>& second);
|
| -template <class AXPositionType, class AXNodeType>
|
| -bool operator!=(const AXPosition<AXPositionType, AXNodeType>& first,
|
| - const AXPosition<AXPositionType, AXNodeType>& second);
|
| +class AXPositionBase;
|
| +AX_EXPORT bool operator==(const AXPositionBase& first,
|
| + const AXPositionBase& second);
|
| +AX_EXPORT bool operator!=(const AXPositionBase& first,
|
| + const AXPositionBase& second);
|
| +AX_EXPORT bool operator<(const AXPositionBase& first,
|
| + const AXPositionBase& second);
|
| +AX_EXPORT bool operator<=(const AXPositionBase& first,
|
| + const AXPositionBase& second);
|
| +AX_EXPORT bool operator>(const AXPositionBase& first,
|
| + const AXPositionBase& second);
|
| +AX_EXPORT bool operator>=(const AXPositionBase& first,
|
| + const AXPositionBase& second);
|
|
|
| // A position in the accessibility tree.
|
| //
|
| @@ -69,51 +76,30 @@ bool operator!=(const AXPosition<AXPositionType, AXNodeType>& first,
|
| //
|
| // This class can be copied using the |Clone| method. It is designed to be
|
| // immutable.
|
| -template <class AXPositionType, class AXNodeType>
|
| -class AXPosition {
|
| +class AX_EXPORT AXPositionBase {
|
| public:
|
| - using AXPositionInstance =
|
| - std::unique_ptr<AXPosition<AXPositionType, AXNodeType>>;
|
| -
|
| - static const int INVALID_TREE_ID = -1;
|
| - static const int32_t INVALID_ANCHOR_ID = -1;
|
| - static const int BEFORE_TEXT = -1;
|
| - static const int INVALID_INDEX = -2;
|
| - static const int INVALID_OFFSET = -1;
|
| -
|
| - static AXPositionInstance CreateNullPosition() {
|
| - AXPositionInstance new_position(new AXPositionType());
|
| - new_position->Initialize(AXPositionKind::NULL_POSITION, INVALID_TREE_ID,
|
| - INVALID_ANCHOR_ID, INVALID_INDEX, INVALID_OFFSET,
|
| - AX_TEXT_AFFINITY_DOWNSTREAM);
|
| - return new_position;
|
| - }
|
| -
|
| - static AXPositionInstance CreateTreePosition(int tree_id,
|
| - int32_t anchor_id,
|
| - int child_index) {
|
| - AXPositionInstance new_position(new AXPositionType());
|
| - new_position->Initialize(AXPositionKind::TREE_POSITION, tree_id, anchor_id,
|
| - child_index, INVALID_OFFSET,
|
| - AX_TEXT_AFFINITY_DOWNSTREAM);
|
| - return new_position;
|
| - }
|
| + using AXPositionInstance = std::unique_ptr<AXPositionBase>;
|
| + using OpaqueAnchor = void*;
|
|
|
| - static AXPositionInstance CreateTextPosition(int tree_id,
|
| - int32_t anchor_id,
|
| - int text_offset,
|
| - AXTextAffinity affinity) {
|
| - AXPositionInstance new_position(new AXPositionType());
|
| - new_position->Initialize(AXPositionKind::TEXT_POSITION, tree_id, anchor_id,
|
| - INVALID_INDEX, text_offset, affinity);
|
| - return new_position;
|
| - }
|
| + static constexpr int INVALID_TREE_ID = -1;
|
| + static constexpr int32_t INVALID_ANCHOR_ID = -1;
|
| + static constexpr int BEFORE_TEXT = -1;
|
| + static constexpr int INVALID_INDEX = -2;
|
| + static constexpr int INVALID_OFFSET = -1;
|
|
|
| - AXPosition() {}
|
| - virtual ~AXPosition() {}
|
| + AXPositionBase() {}
|
| + virtual ~AXPositionBase() {}
|
|
|
| virtual AXPositionInstance Clone() const = 0;
|
| -
|
| + virtual AXPositionInstance CreateNullPosition() const = 0;
|
| + virtual AXPositionInstance CreateTreePosition(int tree_id,
|
| + int32_t anchor_id,
|
| + int child_index) const = 0;
|
| + virtual AXPositionInstance CreateTextPosition(
|
| + int tree_id,
|
| + int32_t anchor_id,
|
| + int text_offset,
|
| + AXTextAffinity affinity) const = 0;
|
| std::string ToString() const {
|
| std::string str;
|
| switch (kind_) {
|
| @@ -168,12 +154,12 @@ class AXPosition {
|
| int tree_id() const { return tree_id_; }
|
| int32_t anchor_id() const { return anchor_id_; }
|
|
|
| - AXNodeType* GetAnchor() const {
|
| + OpaqueAnchor GetOpaqueAnchor() const {
|
| if (tree_id_ == INVALID_TREE_ID || anchor_id_ == INVALID_ANCHOR_ID)
|
| return nullptr;
|
| DCHECK_GE(tree_id_, 0);
|
| DCHECK_GE(anchor_id_, 0);
|
| - return GetNodeInTree(tree_id_, anchor_id_);
|
| + return GetOpaqueNodeInTree(tree_id_, anchor_id_);
|
| }
|
|
|
| AXPositionKind kind() const { return kind_; }
|
| @@ -182,19 +168,19 @@ class AXPosition {
|
| AXTextAffinity affinity() const { return affinity_; }
|
|
|
| bool IsNullPosition() const {
|
| - return kind_ == AXPositionKind::NULL_POSITION || !GetAnchor();
|
| + return kind_ == AXPositionKind::NULL_POSITION || !GetOpaqueAnchor();
|
| }
|
|
|
| bool IsTreePosition() const {
|
| - return GetAnchor() && kind_ == AXPositionKind::TREE_POSITION;
|
| + return GetOpaqueAnchor() && kind_ == AXPositionKind::TREE_POSITION;
|
| }
|
|
|
| bool IsTextPosition() const {
|
| - return GetAnchor() && kind_ == AXPositionKind::TEXT_POSITION;
|
| + return GetOpaqueAnchor() && kind_ == AXPositionKind::TEXT_POSITION;
|
| }
|
|
|
| bool AtStartOfAnchor() const {
|
| - if (!GetAnchor())
|
| + if (!GetOpaqueAnchor())
|
| return false;
|
|
|
| switch (kind_) {
|
| @@ -212,7 +198,7 @@ class AXPosition {
|
| }
|
|
|
| bool AtEndOfAnchor() const {
|
| - if (!GetAnchor())
|
| + if (!GetOpaqueAnchor())
|
| return false;
|
|
|
| switch (kind_) {
|
| @@ -310,26 +296,26 @@ class AXPosition {
|
| // Also, this method uses position instead of tree logic to traverse the tree,
|
| // because positions can handle moving across multiple trees, while trees
|
| // cannot.
|
| - AXPositionInstance LowestCommonAncestor(
|
| - const AXPosition<AXPositionType, AXNodeType>& second) const {
|
| + AXPositionInstance LowestCommonAncestor(const AXPositionBase& second) const {
|
| if (IsNullPosition() || second.IsNullPosition())
|
| return CreateNullPosition();
|
| - if (GetAnchor() == second.GetAnchor())
|
| + if (GetOpaqueAnchor() == second.GetOpaqueAnchor())
|
| return Clone();
|
|
|
| std::stack<AXPositionInstance> ancestors1;
|
| - ancestors1.push(std::move(Clone()));
|
| + ancestors1.push(Clone());
|
| while (!ancestors1.top()->IsNullPosition())
|
| - ancestors1.push(std::move(ancestors1.top()->CreateParentPosition()));
|
| + ancestors1.push(ancestors1.top()->CreateParentPosition());
|
|
|
| std::stack<AXPositionInstance> ancestors2;
|
| - ancestors2.push(std::move(second.Clone()));
|
| + ancestors2.push(second.Clone());
|
| while (!ancestors2.top()->IsNullPosition())
|
| - ancestors2.push(std::move(ancestors2.top()->CreateParentPosition()));
|
| + ancestors2.push(ancestors2.top()->CreateParentPosition());
|
|
|
| AXPositionInstance common_ancestor;
|
| while (!ancestors1.empty() && !ancestors2.empty() &&
|
| - ancestors1.top()->GetAnchor() == ancestors2.top()->GetAnchor()) {
|
| + ancestors1.top()->GetOpaqueAnchor() ==
|
| + ancestors2.top()->GetOpaqueAnchor()) {
|
| common_ancestor = std::move(ancestors1.top());
|
| ancestors1.pop();
|
| ancestors2.pop();
|
| @@ -665,7 +651,7 @@ class AXPosition {
|
| // be in the shadow DOM if the original position was not.
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| - if (GetAnchor() == common_ancestor->GetAnchor())
|
| + if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
|
| text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| @@ -714,7 +700,7 @@ class AXPosition {
|
| // be in the shadow DOM if the original position was not.
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| - if (GetAnchor() == common_ancestor->GetAnchor())
|
| + if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
|
| text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| @@ -760,7 +746,7 @@ class AXPosition {
|
| // be in the shadow DOM if the original position was not.
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| - if (GetAnchor() == common_ancestor->GetAnchor())
|
| + if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
|
| text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| @@ -808,7 +794,7 @@ class AXPosition {
|
| // be in the shadow DOM if the original position was not.
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| - if (GetAnchor() == common_ancestor->GetAnchor())
|
| + if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
|
| text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| @@ -842,7 +828,7 @@ class AXPosition {
|
| // be in the shadow DOM if the original position was not.
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| - if (GetAnchor() == common_ancestor->GetAnchor())
|
| + if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
|
| text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| @@ -874,7 +860,7 @@ class AXPosition {
|
| // be in the shadow DOM if the original position was not.
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| - if (GetAnchor() == common_ancestor->GetAnchor())
|
| + if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
|
| text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| @@ -914,7 +900,7 @@ class AXPosition {
|
| // be in the shadow DOM if the original position was not.
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| - if (GetAnchor() == common_ancestor->GetAnchor())
|
| + if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
|
| text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| @@ -950,7 +936,7 @@ class AXPosition {
|
| // be in the shadow DOM if the original position was not.
|
| AXPositionInstance common_ancestor =
|
| text_position->LowestCommonAncestor(*this);
|
| - if (GetAnchor() == common_ancestor->GetAnchor())
|
| + if (GetOpaqueAnchor() == common_ancestor->GetOpaqueAnchor())
|
| text_position = std::move(common_ancestor);
|
|
|
| if (was_tree_position)
|
| @@ -967,16 +953,15 @@ class AXPosition {
|
| virtual base::string16 GetInnerText() const = 0;
|
|
|
| protected:
|
| - AXPosition(const AXPosition<AXPositionType, AXNodeType>& other) = default;
|
| - virtual AXPosition<AXPositionType, AXNodeType>& operator=(
|
| - const AXPosition<AXPositionType, AXNodeType>& other) = default;
|
| -
|
| - virtual void Initialize(AXPositionKind kind,
|
| - int tree_id,
|
| - int32_t anchor_id,
|
| - int child_index,
|
| - int text_offset,
|
| - AXTextAffinity affinity) {
|
| + AXPositionBase(const AXPositionBase& other) = default;
|
| + virtual AXPositionBase& operator=(const AXPositionBase& other) = default;
|
| +
|
| + void Initialize(AXPositionKind kind,
|
| + int tree_id,
|
| + int32_t anchor_id,
|
| + int child_index,
|
| + int text_offset,
|
| + AXTextAffinity affinity) {
|
| kind_ = kind;
|
| tree_id_ = tree_id;
|
| anchor_id_ = anchor_id;
|
| @@ -984,7 +969,7 @@ class AXPosition {
|
| text_offset_ = text_offset;
|
| affinity_ = affinity;
|
|
|
| - if (!GetAnchor() || kind_ == AXPositionKind::NULL_POSITION ||
|
| + if (!GetOpaqueAnchor() || kind_ == AXPositionKind::NULL_POSITION ||
|
| (kind_ == AXPositionKind::TREE_POSITION &&
|
| (child_index_ != BEFORE_TEXT &&
|
| (child_index_ < 0 || child_index_ > AnchorChildCount()))) ||
|
| @@ -1091,14 +1076,15 @@ class AXPosition {
|
| virtual int AnchorChildCount() const = 0;
|
| virtual int AnchorIndexInParent() const = 0;
|
| virtual void AnchorParent(int* tree_id, int32_t* parent_id) const = 0;
|
| - virtual AXNodeType* GetNodeInTree(int tree_id, int32_t node_id) const = 0;
|
| + virtual OpaqueAnchor GetOpaqueNodeInTree(int tree_id,
|
| + int32_t node_id) const = 0;
|
| // Returns the length of the text that is present inside the anchor node,
|
| // including any text found in descendant text nodes.
|
| virtual int MaxTextOffset() const = 0;
|
| // Returns the length of text that this anchor node takes up in its parent.
|
| // On some platforms, embedded objects are represented in their parent with a
|
| // single embedded object character.
|
| - virtual int MaxTextOffsetInParent() const { return MaxTextOffset(); }
|
| + virtual int MaxTextOffsetInParent() const;
|
| virtual bool IsInLineBreak() const = 0;
|
| virtual std::vector<int32_t> GetWordStartOffsets() const = 0;
|
| virtual std::vector<int32_t> GetWordEndOffsets() const = 0;
|
| @@ -1121,77 +1107,80 @@ class AXPosition {
|
| };
|
|
|
| template <class AXPositionType, class AXNodeType>
|
| -const int AXPosition<AXPositionType, AXNodeType>::INVALID_TREE_ID;
|
| -template <class AXPositionType, class AXNodeType>
|
| -const int32_t AXPosition<AXPositionType, AXNodeType>::INVALID_ANCHOR_ID;
|
| -template <class AXPositionType, class AXNodeType>
|
| -const int AXPosition<AXPositionType, AXNodeType>::BEFORE_TEXT;
|
| -template <class AXPositionType, class AXNodeType>
|
| -const int AXPosition<AXPositionType, AXNodeType>::INVALID_INDEX;
|
| -template <class AXPositionType, class AXNodeType>
|
| -const int AXPosition<AXPositionType, AXNodeType>::INVALID_OFFSET;
|
| +class AXPosition : public AXPositionBase {
|
| + public:
|
| + using AXPositionInstance = AXPositionBase::AXPositionInstance;
|
| + using ConcreteNodeType = AXNodeType;
|
| + using ConcreteInstance =
|
| + std::unique_ptr<AXPosition<AXPositionType, AXNodeType>>;
|
|
|
| -template <class AXPositionType, class AXNodeType>
|
| -bool operator==(const AXPosition<AXPositionType, AXNodeType>& first,
|
| - const AXPosition<AXPositionType, AXNodeType>& second) {
|
| - if (first.IsNullPosition() && second.IsNullPosition())
|
| - return true;
|
| - return first.tree_id() == second.tree_id() &&
|
| - first.anchor_id() == second.anchor_id() &&
|
| - first.child_index() == second.child_index() &&
|
| - first.text_offset() == second.text_offset() &&
|
| - first.affinity() == second.affinity();
|
| -}
|
| + static ConcreteInstance CreateConcreteNullPosition() {
|
| + ConcreteInstance new_position(new AXPositionType());
|
| + new_position->Initialize(AXPositionKind::NULL_POSITION, INVALID_TREE_ID,
|
| + INVALID_ANCHOR_ID, INVALID_INDEX, INVALID_OFFSET,
|
| + AX_TEXT_AFFINITY_DOWNSTREAM);
|
| + return new_position;
|
| + }
|
|
|
| -template <class AXPositionType, class AXNodeType>
|
| -bool operator!=(const AXPosition<AXPositionType, AXNodeType>& first,
|
| - const AXPosition<AXPositionType, AXNodeType>& second) {
|
| - return !(first == second);
|
| -}
|
| + static ConcreteInstance CreateConcreteTreePosition(int tree_id,
|
| + int32_t anchor_id,
|
| + int child_index) {
|
| + ConcreteInstance new_position(new AXPositionType());
|
| + new_position->Initialize(AXPositionKind::TREE_POSITION, tree_id, anchor_id,
|
| + child_index, INVALID_OFFSET,
|
| + AX_TEXT_AFFINITY_DOWNSTREAM);
|
| + return new_position;
|
| + }
|
|
|
| -template <class AXPositionType, class AXNodeType>
|
| -bool operator<(const AXPosition<AXPositionType, AXNodeType>& first,
|
| - const AXPosition<AXPositionType, AXNodeType>& second) {
|
| - if (first.IsNullPosition() || second.IsNullPosition())
|
| - return false;
|
| + static ConcreteInstance CreateConcreteTextPosition(int tree_id,
|
| + int32_t anchor_id,
|
| + int text_offset,
|
| + AXTextAffinity affinity) {
|
| + ConcreteInstance new_position(new AXPositionType());
|
| + new_position->Initialize(AXPositionKind::TEXT_POSITION, tree_id, anchor_id,
|
| + INVALID_INDEX, text_offset, affinity);
|
| + return new_position;
|
| + }
|
|
|
| - std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> first_ancestor =
|
| - first.LowestCommonAncestor(second)->AsTreePosition();
|
| - std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> second_ancestor =
|
| - second.LowestCommonAncestor(first)->AsTreePosition();
|
| - DCHECK_EQ(first_ancestor->GetAnchor(), second_ancestor->GetAnchor());
|
| - return !first_ancestor->IsNullPosition() &&
|
| - first_ancestor->AsTextPosition()->text_offset() <
|
| - second_ancestor->AsTextPosition()->text_offset();
|
| -}
|
| + static ConcreteInstance FromBase(AXPositionInstance instance) {
|
| + return ConcreteInstance(static_cast<AXPosition*>(instance.release()));
|
| + }
|
|
|
| -template <class AXPositionType, class AXNodeType>
|
| -bool operator<=(const AXPosition<AXPositionType, AXNodeType>& first,
|
| - const AXPosition<AXPositionType, AXNodeType>& second) {
|
| - return first == second || first < second;
|
| -}
|
| + AXNodeType* GetAnchor() const {
|
| + return static_cast<AXNodeType*>(GetOpaqueAnchor());
|
| + }
|
| + virtual ConcreteInstance CloneConcrete() const = 0;
|
| + virtual AXNodeType* GetNodeInTree(int tree_id, int32_t node_id) const = 0;
|
|
|
| -template <class AXPositionType, class AXNodeType>
|
| -bool operator>(const AXPosition<AXPositionType, AXNodeType>& first,
|
| - const AXPosition<AXPositionType, AXNodeType>& second) {
|
| - if (first.IsNullPosition() || second.IsNullPosition())
|
| - return false;
|
| + AXPositionInstance Clone() const override {
|
| + return base::WrapUnique<AXPositionBase>(CloneConcrete().release());
|
| + }
|
| + virtual OpaqueAnchor GetOpaqueNodeInTree(int tree_id, int32_t node_id) const {
|
| + return GetNodeInTree(tree_id, node_id);
|
| + }
|
|
|
| - std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> first_ancestor =
|
| - first.LowestCommonAncestor(second)->AsTreePosition();
|
| - std::unique_ptr<AXPosition<AXPositionType, AXNodeType>> second_ancestor =
|
| - second.LowestCommonAncestor(first)->AsTreePosition();
|
| - DCHECK_EQ(first_ancestor->GetAnchor(), second_ancestor->GetAnchor());
|
| - return !first_ancestor->IsNullPosition() &&
|
| - first_ancestor->AsTextPosition()->text_offset() >
|
| - second_ancestor->AsTextPosition()->text_offset();
|
| -}
|
| + AXPositionInstance CreateNullPosition() const override {
|
| + return base::WrapUnique<AXPositionBase>(
|
| + CreateConcreteNullPosition().release());
|
| + }
|
|
|
| -template <class AXPositionType, class AXNodeType>
|
| -bool operator>=(const AXPosition<AXPositionType, AXNodeType>& first,
|
| - const AXPosition<AXPositionType, AXNodeType>& second) {
|
| - return first == second || first > second;
|
| -}
|
| + AXPositionInstance CreateTreePosition(int tree_id,
|
| + int32_t anchor_id,
|
| + int child_index) const override {
|
| + return base::WrapUnique<AXPositionBase>(
|
| + CreateConcreteTreePosition(tree_id, anchor_id, child_index).release());
|
| + }
|
| +
|
| + AXPositionInstance CreateTextPosition(
|
| + int tree_id,
|
| + int32_t anchor_id,
|
| + int text_offset,
|
| + AXTextAffinity affinity) const override {
|
| + return base::WrapUnique<AXPositionBase>(
|
| + CreateConcreteTextPosition(tree_id, anchor_id, text_offset, affinity)
|
| + .release());
|
| + }
|
| +};
|
|
|
| } // namespace ui
|
|
|
|
|