1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/accessibility/accessibility_tree_formatter.h" 6 7 #include "base/logging.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "content/browser/accessibility/browser_accessibility_manager.h" 14 #include "content/port/browser/render_widget_host_view_port.h" 15 #include "content/public/browser/render_view_host.h" 16 #include "content/public/browser/web_contents.h" 17 18 namespace content { 19 namespace { 20 const int kIndentSpaces = 4; 21 const char* kSkipString = "@NO_DUMP"; 22 const char* kChildrenDictAttr = "children"; 23 } 24 25 AccessibilityTreeFormatter::AccessibilityTreeFormatter( 26 BrowserAccessibility* root) 27 : root_(root) { 28 Initialize(); 29 } 30 31 // static 32 AccessibilityTreeFormatter* AccessibilityTreeFormatter::Create( 33 RenderViewHost* rvh) { 34 RenderWidgetHostViewPort* host_view = static_cast<RenderWidgetHostViewPort*>( 35 WebContents::FromRenderViewHost(rvh)->GetRenderWidgetHostView()); 36 37 BrowserAccessibilityManager* manager = 38 host_view->GetBrowserAccessibilityManager(); 39 if (!manager) 40 return NULL; 41 42 BrowserAccessibility* root = manager->GetRoot(); 43 return new AccessibilityTreeFormatter(root); 44 } 45 46 47 AccessibilityTreeFormatter::~AccessibilityTreeFormatter() { 48 } 49 50 scoped_ptr<base::DictionaryValue> 51 AccessibilityTreeFormatter::BuildAccessibilityTree() { 52 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue); 53 RecursiveBuildAccessibilityTree(*root_, dict.get()); 54 return dict.Pass(); 55 } 56 57 void AccessibilityTreeFormatter::FormatAccessibilityTree( 58 string16* contents) { 59 scoped_ptr<base::DictionaryValue> dict = BuildAccessibilityTree(); 60 RecursiveFormatAccessibilityTree(*(dict.get()), contents); 61 } 62 63 void AccessibilityTreeFormatter::RecursiveBuildAccessibilityTree( 64 const BrowserAccessibility& node, base::DictionaryValue* dict) { 65 AddProperties(node, dict); 66 67 base::ListValue* children = new base::ListValue; 68 dict->Set(kChildrenDictAttr, children); 69 if (!IncludeChildren(node)) 70 return; 71 72 for (size_t i = 0; i < node.children().size(); ++i) { 73 BrowserAccessibility* child_node = node.children()[i]; 74 base::DictionaryValue* child_dict = new base::DictionaryValue; 75 children->Append(child_dict); 76 RecursiveBuildAccessibilityTree(*child_node, child_dict); 77 } 78 } 79 80 void AccessibilityTreeFormatter::RecursiveFormatAccessibilityTree( 81 const base::DictionaryValue& dict, string16* contents, int depth) { 82 string16 line = ToString(dict, string16(depth * kIndentSpaces, ' ')); 83 if (line.find(ASCIIToUTF16(kSkipString)) != string16::npos) 84 return; 85 86 *contents += line; 87 const base::ListValue* children; 88 dict.GetList(kChildrenDictAttr, &children); 89 const base::DictionaryValue* child_dict; 90 for (size_t i = 0; i < children->GetSize(); i++) { 91 children->GetDictionary(i, &child_dict); 92 RecursiveFormatAccessibilityTree(*child_dict, contents, depth + 1); 93 } 94 } 95 96 #if !defined(OS_ANDROID) 97 bool AccessibilityTreeFormatter::IncludeChildren( 98 const BrowserAccessibility& node) { 99 return true; 100 } 101 #endif 102 103 #if (!defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && \ 104 !defined(TOOLKIT_GTK)) 105 void AccessibilityTreeFormatter::AddProperties(const BrowserAccessibility& node, 106 base::DictionaryValue* dict) { 107 dict->SetInteger("id", node.renderer_id()); 108 } 109 110 string16 AccessibilityTreeFormatter::ToString(const base::DictionaryValue& node, 111 const string16& indent) { 112 int id_value; 113 node.GetInteger("id", &id_value); 114 return indent + base::IntToString16(id_value) + 115 ASCIIToUTF16("\n"); 116 } 117 118 void AccessibilityTreeFormatter::Initialize() {} 119 120 // static 121 const base::FilePath::StringType 122 AccessibilityTreeFormatter::GetActualFileSuffix() { 123 return base::FilePath::StringType(); 124 } 125 126 // static 127 const base::FilePath::StringType 128 AccessibilityTreeFormatter::GetExpectedFileSuffix() { 129 return base::FilePath::StringType(); 130 } 131 132 // static 133 const std::string AccessibilityTreeFormatter::GetAllowEmptyString() { 134 return std::string(); 135 } 136 137 // static 138 const std::string AccessibilityTreeFormatter::GetAllowString() { 139 return std::string(); 140 } 141 142 // static 143 const std::string AccessibilityTreeFormatter::GetDenyString() { 144 return std::string(); 145 } 146 #endif 147 148 void AccessibilityTreeFormatter::SetFilters( 149 const std::vector<Filter>& filters) { 150 filters_ = filters; 151 } 152 153 bool AccessibilityTreeFormatter::MatchesFilters( 154 const string16& text, bool default_result) const { 155 std::vector<Filter>::const_iterator iter = filters_.begin(); 156 bool allow = default_result; 157 for (iter = filters_.begin(); iter != filters_.end(); ++iter) { 158 if (MatchPattern(text, iter->match_str)) { 159 if (iter->type == Filter::ALLOW_EMPTY) 160 allow = true; 161 else if (iter->type == Filter::ALLOW) 162 allow = (!MatchPattern(text, UTF8ToUTF16("*=''"))); 163 else 164 allow = false; 165 } 166 } 167 return allow; 168 } 169 170 string16 AccessibilityTreeFormatter::FormatCoordinates( 171 const char* name, const char* x_name, const char* y_name, 172 const base::DictionaryValue& value) { 173 int x, y; 174 value.GetInteger(x_name, &x); 175 value.GetInteger(y_name, &y); 176 std::string xy_str(base::StringPrintf("%s=(%d, %d)", name, x, y)); 177 178 return UTF8ToUTF16(xy_str); 179 } 180 181 void AccessibilityTreeFormatter::WriteAttribute( 182 bool include_by_default, const std::string& attr, string16* line) { 183 WriteAttribute(include_by_default, UTF8ToUTF16(attr), line); 184 } 185 186 void AccessibilityTreeFormatter::WriteAttribute( 187 bool include_by_default, const string16& attr, string16* line) { 188 if (attr.empty()) 189 return; 190 if (!MatchesFilters(attr, include_by_default)) 191 return; 192 if (!line->empty()) 193 *line += ASCIIToUTF16(" "); 194 *line += attr; 195 } 196 197 } // namespace content 198