Index: content/browser/accessibility/accessibility_tree_search.cc |
diff --git a/content/browser/accessibility/accessibility_tree_search.cc b/content/browser/accessibility/accessibility_tree_search.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bb7559e0fc585a0f8ce410aacf84b59ff64d4a28 |
--- /dev/null |
+++ b/content/browser/accessibility/accessibility_tree_search.cc |
@@ -0,0 +1,157 @@ |
+// Copyright (c) 2015 The Chromium Authors. All rights reserved. |
David Tseng
2015/05/08 21:58:24
nit: remove (c)?
dmazzoni
2015/05/13 04:22:19
Done.
|
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/accessibility/accessibility_tree_search.h" |
+ |
+#include "base/i18n/case_conversion.h" |
+#include "base/strings/string16.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "content/browser/accessibility/browser_accessibility.h" |
+#include "content/browser/accessibility/browser_accessibility_manager.h" |
+ |
+namespace content { |
+ |
+// Given a node, populate a vector with all of the strings from that node's |
+// attributes that might be relevant for a text search. |
+void GetNodeStrings(BrowserAccessibility* node, |
+ std::vector<base::string16>* strings) { |
+ if (node->HasStringAttribute(ui::AX_ATTR_NAME)) |
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_NAME)); |
+ if (node->HasStringAttribute(ui::AX_ATTR_DESCRIPTION)) |
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_DESCRIPTION)); |
+ if (node->HasStringAttribute(ui::AX_ATTR_HELP)) |
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_HELP)); |
+ if (node->HasStringAttribute(ui::AX_ATTR_VALUE)) |
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_VALUE)); |
+ if (node->HasStringAttribute(ui::AX_ATTR_PLACEHOLDER)) |
+ strings->push_back(node->GetString16Attribute(ui::AX_ATTR_PLACEHOLDER)); |
David Tseng
2015/05/08 21:58:24
What about shortcut and url?
dmazzoni
2015/05/13 04:22:20
I don't think those are text. shortcut is the acce
|
+} |
+ |
+AccessibilityTreeSearch::AccessibilityTreeSearch( |
+ BrowserAccessibilityManager* tree) |
+ : tree_(tree), |
David Tseng
2015/05/08 21:58:24
nit: +4 indent
dmazzoni
2015/05/13 04:22:19
I think this is right? It's +4 from the left edge
|
+ start_node_(nullptr), |
+ direction_(AccessibilityTreeSearch::FORWARDS), |
+ result_limit_(-1), |
David Tseng
2015/05/08 21:58:24
nit: -1 means what? (error/unlimited)?
dmazzoni
2015/05/13 04:22:19
Done.
|
+ immediate_descendants_only_(false), |
+ visible_only_(false), |
+ did_search_(false) { |
+} |
+ |
+AccessibilityTreeSearch::~AccessibilityTreeSearch() { |
+} |
+ |
+void AccessibilityTreeSearch::SetStartNode(BrowserAccessibility* start_node) { |
+ DCHECK(!did_search_); |
+ start_node_ = start_node; |
+} |
+ |
+void AccessibilityTreeSearch::SetDirection(Direction direction) { |
+ DCHECK(!did_search_); |
+ direction_ = direction; |
+} |
+ |
+void AccessibilityTreeSearch::SetResultLimit(int result_limit) { |
+ DCHECK(!did_search_); |
+ result_limit_ = result_limit; |
+} |
+ |
+void AccessibilityTreeSearch::SetImmediateDescendantsOnly( |
+ bool immediate_descendants_only) { |
+ DCHECK(!did_search_); |
+ immediate_descendants_only_ = immediate_descendants_only; |
+} |
+ |
+void AccessibilityTreeSearch::SetVisibleOnly(bool visible_only) { |
+ DCHECK(!did_search_); |
+ visible_only_ = visible_only; |
+} |
+ |
+void AccessibilityTreeSearch::SetSearchText(const std::string& text) { |
+ DCHECK(!did_search_); |
+ search_text_ = text; |
+} |
+ |
+void AccessibilityTreeSearch::AddPredicate( |
+ AccessibilityMatchPredicate predicate) { |
+ DCHECK(!did_search_); |
+ predicates_.push_back(predicate); |
+} |
+ |
+size_t AccessibilityTreeSearch::CountMatches() { |
+ if (!did_search_) |
+ DoSearch(); |
+ |
+ return matches_.size(); |
+} |
+ |
+BrowserAccessibility* AccessibilityTreeSearch::GetMatchAtIndex(size_t index) { |
+ if (!did_search_) |
+ DoSearch(); |
+ |
+ DCHECK(index < matches_.size()); |
David Tseng
2015/05/08 21:58:24
Should this be a DCHECK?
dmazzoni
2015/05/13 04:22:19
Done.
|
+ return matches_[index]; |
+} |
+ |
+void AccessibilityTreeSearch::DoSearch() |
+{ |
+ BrowserAccessibility* node = nullptr; |
+ if (start_node_) { |
David Tseng
2015/05/08 21:58:24
Is it expected that the search starts from the dir
dmazzoni
2015/05/13 04:22:19
Yes, the search does not include the start node it
|
+ if (direction_ == FORWARDS) |
+ node = tree_->NextInTreeOrder(start_node_); |
+ else |
+ node = tree_->PreviousInTreeOrder(start_node_); |
+ } else { |
+ start_node_ = tree_->GetRoot(); |
+ node = start_node_; |
+ } |
+ |
+ while (node && (result_limit_ < 0 || |
+ static_cast<int>(matches_.size()) < result_limit_)) { |
+ if (immediate_descendants_only_ && start_node_) { |
David Tseng
2015/05/08 21:58:24
Isn't start_node_ always going to be non-null here
dmazzoni
2015/05/13 04:22:20
Done.
|
+ if (!node->IsDescendantOf(start_node_)) |
David Tseng
2015/05/08 21:58:24
This check could be part of your traversal.
dmazzoni
2015/05/13 04:22:20
Done.
|
+ return; |
+ } |
+ |
+ bool is_match = true; |
+ for (size_t i = 0; i < predicates_.size() && is_match; ++i) { |
David Tseng
2015/05/08 21:58:24
Maybe add a CHECK to ensure the caller has actuall
dmazzoni
2015/05/13 04:22:19
Not required - it's okay to use this just to get t
|
+ if (!predicates_[i](start_node_, node)) |
+ is_match = false; |
+ } |
+ |
+ if (visible_only_) { |
+ if (node->HasState(ui::AX_STATE_INVISIBLE) || |
+ node->HasState(ui::AX_STATE_OFFSCREEN)) { |
+ is_match = false; |
+ } |
+ } |
+ |
+ if (!search_text_.empty()) { |
+ base::string16 search_text_lower = |
+ base::i18n::ToLower(base::UTF8ToUTF16(search_text_)); |
+ std::vector<base::string16> node_strings; |
+ GetNodeStrings(node, &node_strings); |
+ bool found_text_match = false; |
+ for (size_t i = 0; i < node_strings.size(); ++i) { |
+ base::string16 node_string_lower = base::i18n::ToLower(node_strings[i]); |
+ if (node_string_lower.find(search_text_lower) != base::string16::npos) { |
David Tseng
2015/05/08 21:58:25
Does Mac expect case insensitive searches?
dmazzoni
2015/05/13 04:22:20
Yes, this matches their implementation. We could m
|
+ found_text_match = true; |
+ break; |
+ } |
+ } |
+ if (!found_text_match) |
+ is_match = false; |
+ } |
+ |
+ if (is_match) |
+ matches_.push_back(node); |
+ |
+ if (direction_ == FORWARDS) |
+ node = tree_->NextInTreeOrder(node); |
+ else |
+ node = tree_->PreviousInTreeOrder(node); |
+ } |
+} |
+ |
+} // namespace content |