Chromium Code Reviews| 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 |