Implemented finding word and line boundaries.

BUG=530826
[email protected], [email protected], [email protected]
TESTED=unit tests

Review-Url: https://codereview.chromium.org/2450393003
Cr-Commit-Position: refs/heads/master@{#438352}
diff --git a/ui/accessibility/ax_node_position.cc b/ui/accessibility/ax_node_position.cc
index 4b91f29b3..30fcbd0 100644
--- a/ui/accessibility/ax_node_position.cc
+++ b/ui/accessibility/ax_node_position.cc
@@ -4,7 +4,7 @@
 
 #include "ui/accessibility/ax_node_position.h"
 
-#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_enums.h"
 
 namespace ui {
@@ -15,6 +15,22 @@
 
 AXNodePosition::~AXNodePosition() {}
 
+AXNodePosition::AXPositionInstance AXNodePosition::Clone() const {
+  return AXPositionInstance(new AXNodePosition(*this));
+}
+
+base::string16 AXNodePosition::GetInnerText() const {
+  if (IsNullPosition())
+    return base::string16();
+
+  DCHECK(GetAnchor());
+  base::string16 value =
+      GetAnchor()->data().GetString16Attribute(AX_ATTR_VALUE);
+  if (!value.empty())
+    return value;
+  return GetAnchor()->data().GetString16Attribute(AX_ATTR_NAME);
+}
+
 void AXNodePosition::AnchorChild(int child_index,
                                  int* tree_id,
                                  int32_t* child_id) const {
@@ -22,8 +38,8 @@
   DCHECK(child_id);
 
   if (!GetAnchor() || child_index < 0 || child_index >= AnchorChildCount()) {
-    *tree_id = AXPosition::INVALID_TREE_ID;
-    *child_id = AXPosition::INVALID_ANCHOR_ID;
+    *tree_id = INVALID_TREE_ID;
+    *child_id = INVALID_ANCHOR_ID;
     return;
   }
 
@@ -38,8 +54,7 @@
 }
 
 int AXNodePosition::AnchorIndexInParent() const {
-  return GetAnchor() ? GetAnchor()->index_in_parent()
-                     : AXPosition::INVALID_INDEX;
+  return GetAnchor() ? GetAnchor()->index_in_parent() : INVALID_INDEX;
 }
 
 void AXNodePosition::AnchorParent(int* tree_id, int32_t* parent_id) const {
@@ -47,8 +62,8 @@
   DCHECK(parent_id);
 
   if (!GetAnchor() || !GetAnchor()->parent()) {
-    *tree_id = AXPosition::INVALID_TREE_ID;
-    *parent_id = AXPosition::INVALID_ANCHOR_ID;
+    *tree_id = INVALID_TREE_ID;
+    *parent_id = INVALID_ANCHOR_ID;
     return;
   }
 
@@ -58,22 +73,68 @@
 }
 
 AXNode* AXNodePosition::GetNodeInTree(int tree_id, int32_t node_id) const {
-  if (!tree_ || node_id == AXPosition::INVALID_ANCHOR_ID)
+  if (!tree_ || node_id == INVALID_ANCHOR_ID)
     return nullptr;
   return AXNodePosition::tree_->GetFromId(node_id);
 }
 
 int AXNodePosition::MaxTextOffset() const {
-  if (IsTextPosition()) {
-    DCHECK(GetAnchor());
-    base::string16 name =
-        GetAnchor()->data().GetString16Attribute(AX_ATTR_NAME);
-    return static_cast<int>(name.length());
-  } else if (IsTreePosition()) {
-    return 0;
-  }
+  if (IsNullPosition())
+    return INVALID_INDEX;
+  return static_cast<int>(GetInnerText().length());
+}
 
-  return AXPosition::INVALID_INDEX;
+// TODO(nektar): There might be other newline characters than '\n'.
+bool AXNodePosition::IsInLineBreak() const {
+  switch (kind()) {
+    case AXPositionKind::NULL_POSITION:
+      return false;
+    case AXPositionKind::TREE_POSITION:
+    case AXPositionKind::TEXT_POSITION:
+      return GetInnerText() == base::UTF8ToUTF16("\n");
+  }
+  NOTREACHED();
+  return false;
+}
+
+std::vector<int32_t> AXNodePosition::GetWordStartOffsets() const {
+  if (IsNullPosition())
+    return std::vector<int32_t>();
+  DCHECK(GetAnchor());
+  return GetAnchor()->data().GetIntListAttribute(ui::AX_ATTR_WORD_STARTS);
+}
+
+std::vector<int32_t> AXNodePosition::GetWordEndOffsets() const {
+  if (IsNullPosition())
+    return std::vector<int32_t>();
+  DCHECK(GetAnchor());
+  return GetAnchor()->data().GetIntListAttribute(ui::AX_ATTR_WORD_ENDS);
+}
+
+int32_t AXNodePosition::GetNextOnLineID(int32_t node_id) const {
+  if (IsNullPosition())
+    return INVALID_ANCHOR_ID;
+  AXNode* node = GetNodeInTree(tree_id(), node_id);
+  int next_on_line_id;
+  if (!node ||
+      !node->data().GetIntAttribute(AX_ATTR_NEXT_ON_LINE_ID,
+                                    &next_on_line_id)) {
+    return INVALID_ANCHOR_ID;
+  }
+  return static_cast<int32_t>(next_on_line_id);
+}
+
+int32_t AXNodePosition::GetPreviousOnLineID(int32_t node_id) const {
+  if (IsNullPosition())
+    return INVALID_ANCHOR_ID;
+  AXNode* node = GetNodeInTree(tree_id(), node_id);
+  int previous_on_line_id;
+  if (!node ||
+      !node->data().GetIntAttribute(AX_ATTR_PREVIOUS_ON_LINE_ID,
+                                    &previous_on_line_id)) {
+    return INVALID_ANCHOR_ID;
+  }
+  return static_cast<int32_t>(previous_on_line_id);
 }
 
 }  // namespace ui