12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/accessibility/accessibility_tree_formatter.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/accessibility/browser_accessibility_manager.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/browser/renderer_host/render_widget_host_view_base.h"
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/web_contents/web_contents_impl.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/web_contents.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kIndentSpaces = 4;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char* kSkipString = "@NO_DUMP";
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char* kChildrenDictAttr = "children";
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AccessibilityTreeFormatter::AccessibilityTreeFormatter(
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    BrowserAccessibility* root)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : root_(root) {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Initialize();
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AccessibilityTreeFormatter* AccessibilityTreeFormatter::Create(
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    WebContents* web_contents) {
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserAccessibilityManager* manager =
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      static_cast<WebContentsImpl*>(web_contents)->
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          GetRootBrowserAccessibilityManager();
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!manager)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserAccessibility* root = manager->GetRoot();
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new AccessibilityTreeFormatter(root);
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AccessibilityTreeFormatter::~AccessibilityTreeFormatter() {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)scoped_ptr<base::DictionaryValue>
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)AccessibilityTreeFormatter::BuildAccessibilityTree() {
507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RecursiveBuildAccessibilityTree(*root_, dict.get());
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return dict.Pass();
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AccessibilityTreeFormatter::FormatAccessibilityTree(
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16* contents) {
577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> dict = BuildAccessibilityTree();
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RecursiveFormatAccessibilityTree(*(dict.get()), contents);
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AccessibilityTreeFormatter::RecursiveBuildAccessibilityTree(
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const BrowserAccessibility& node, base::DictionaryValue* dict) {
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  AddProperties(node, dict);
647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ListValue* children = new base::ListValue;
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->Set(kChildrenDictAttr, children);
677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  for (size_t i = 0; i < node.PlatformChildCount(); ++i) {
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    BrowserAccessibility* child_node = node.PlatformGetChild(i);
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::DictionaryValue* child_dict = new base::DictionaryValue;
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    children->Append(child_dict);
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RecursiveBuildAccessibilityTree(*child_node, child_dict);
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AccessibilityTreeFormatter::RecursiveFormatAccessibilityTree(
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::DictionaryValue& dict, base::string16* contents, int depth) {
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 line =
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ToString(dict, base::string16(depth * kIndentSpaces, ' '));
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (line.find(base::ASCIIToUTF16(kSkipString)) != base::string16::npos)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *contents += line;
847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* children;
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict.GetList(kChildrenDictAttr, &children);
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::DictionaryValue* child_dict;
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < children->GetSize(); i++) {
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    children->GetDictionary(i, &child_dict);
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    RecursiveFormatAccessibilityTree(*child_dict, contents, depth + 1);
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#if (!defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_ANDROID))
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AccessibilityTreeFormatter::AddProperties(const BrowserAccessibility& node,
957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                               base::DictionaryValue* dict) {
96a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  dict->SetInteger("id", node.GetId());
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::string16 AccessibilityTreeFormatter::ToString(
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::DictionaryValue& node,
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& indent) {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int id_value;
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  node.GetInteger("id", &id_value);
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return indent + base::IntToString16(id_value) +
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       base::ASCIIToUTF16("\n");
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AccessibilityTreeFormatter::Initialize() {}
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::StringType
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AccessibilityTreeFormatter::GetActualFileSuffix() {
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::FilePath::StringType();
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::StringType
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AccessibilityTreeFormatter::GetExpectedFileSuffix() {
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::FilePath::StringType();
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string AccessibilityTreeFormatter::GetAllowEmptyString() {
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string();
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string AccessibilityTreeFormatter::GetAllowString() {
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string();
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string AccessibilityTreeFormatter::GetDenyString() {
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return std::string();
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AccessibilityTreeFormatter::SetFilters(
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<Filter>& filters) {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  filters_ = filters;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AccessibilityTreeFormatter::MatchesFilters(
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& text, bool default_result) const {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<Filter>::const_iterator iter = filters_.begin();
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool allow = default_result;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (iter = filters_.begin(); iter != filters_.end(); ++iter) {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (MatchPattern(text, iter->match_str)) {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (iter->type == Filter::ALLOW_EMPTY)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        allow = true;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else if (iter->type == Filter::ALLOW)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        allow = (!MatchPattern(text, base::UTF8ToUTF16("*=''")));
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        allow = false;
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return allow;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::string16 AccessibilityTreeFormatter::FormatCoordinates(
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const char* name, const char* x_name, const char* y_name,
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const base::DictionaryValue& value) {
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int x, y;
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  value.GetInteger(x_name, &x);
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  value.GetInteger(y_name, &y);
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string xy_str(base::StringPrintf("%s=(%d, %d)", name, x, y));
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::UTF8ToUTF16(xy_str);
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AccessibilityTreeFormatter::WriteAttribute(
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    bool include_by_default, const std::string& attr, base::string16* line) {
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WriteAttribute(include_by_default, base::UTF8ToUTF16(attr), line);
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AccessibilityTreeFormatter::WriteAttribute(
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    bool include_by_default, const base::string16& attr, base::string16* line) {
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (attr.empty())
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!MatchesFilters(attr, include_by_default))
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!line->empty())
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *line += base::ASCIIToUTF16(" ");
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  *line += attr;
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
188