Chromium Code Reviews| 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; |
|
tapted
2017/06/15 11:57:44
of course.. plan is to move all these methods to t
|
| 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; |
| + } |
|
tapted
2017/06/15 11:57:44
plan would be to move these Create* methods into a
|
| -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) { |
|
tapted
2017/06/15 11:57:44
I'd hoped to avoid this function.. currently only
|
| + 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 |