// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/accessibility/one_shot_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* 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)); } OneShotAccessibilityTreeSearch::OneShotAccessibilityTreeSearch( BrowserAccessibilityManager* tree) : tree_(tree), start_node_(nullptr), direction_(OneShotAccessibilityTreeSearch::FORWARDS), result_limit_(UNLIMITED_RESULTS), immediate_descendants_only_(false), visible_only_(false), did_search_(false) { } OneShotAccessibilityTreeSearch::~OneShotAccessibilityTreeSearch() { } void OneShotAccessibilityTreeSearch::SetStartNode( BrowserAccessibility* start_node) { DCHECK(!did_search_); start_node_ = start_node; } void OneShotAccessibilityTreeSearch::SetDirection(Direction direction) { DCHECK(!did_search_); direction_ = direction; } void OneShotAccessibilityTreeSearch::SetResultLimit(int result_limit) { DCHECK(!did_search_); result_limit_ = result_limit; } void OneShotAccessibilityTreeSearch::SetImmediateDescendantsOnly( bool immediate_descendants_only) { DCHECK(!did_search_); immediate_descendants_only_ = immediate_descendants_only; } void OneShotAccessibilityTreeSearch::SetVisibleOnly(bool visible_only) { DCHECK(!did_search_); visible_only_ = visible_only; } void OneShotAccessibilityTreeSearch::SetSearchText(const std::string& text) { DCHECK(!did_search_); search_text_ = text; } void OneShotAccessibilityTreeSearch::AddPredicate( AccessibilityMatchPredicate predicate) { DCHECK(!did_search_); predicates_.push_back(predicate); } size_t OneShotAccessibilityTreeSearch::CountMatches() { if (!did_search_) Search(); return matches_.size(); } BrowserAccessibility* OneShotAccessibilityTreeSearch::GetMatchAtIndex( size_t index) { if (!did_search_) Search(); CHECK(index < matches_.size()); return matches_[index]; } void OneShotAccessibilityTreeSearch::Search() { if (immediate_descendants_only_) { SearchByIteratingOverChildren(); } else { SearchByWalkingTree(); } } void OneShotAccessibilityTreeSearch::SearchByIteratingOverChildren() { if (!start_node_) return; for (unsigned i = 0; i < start_node_->PlatformChildCount() && (result_limit_ == UNLIMITED_RESULTS || static_cast(matches_.size()) < result_limit_); ++i) { BrowserAccessibility* child = start_node_->PlatformGetChild(i); if (Matches(child)) matches_.push_back(child); } } void OneShotAccessibilityTreeSearch::SearchByWalkingTree() { BrowserAccessibility* node = nullptr; if (start_node_) { 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_ == UNLIMITED_RESULTS || static_cast(matches_.size()) < result_limit_)) { if (Matches(node)) matches_.push_back(node); if (direction_ == FORWARDS) node = tree_->NextInTreeOrder(node); else node = tree_->PreviousInTreeOrder(node); } } bool OneShotAccessibilityTreeSearch::Matches(BrowserAccessibility* node) { for (size_t i = 0; i < predicates_.size(); ++i) { if (!predicates_[i](start_node_, node)) return false; } if (visible_only_) { if (node->HasState(ui::AX_STATE_INVISIBLE) || node->HasState(ui::AX_STATE_OFFSCREEN)) { return false; } } if (!search_text_.empty()) { base::string16 search_text_lower = base::i18n::ToLower(base::UTF8ToUTF16(search_text_)); std::vector 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) { found_text_match = true; break; } } if (!found_text_match) return false; } return true; } } // namespace content