Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / accessibility / accessibility_tree_formatter_win.cc
blob3df2dafc6060eb00e3b76782b1ebd132623844a7
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.
5 #include "content/browser/accessibility/accessibility_tree_formatter.h"
7 #include <oleacc.h>
9 #include <string>
11 #include "base/files/file_path.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/win/scoped_bstr.h"
18 #include "base/win/scoped_comptr.h"
19 #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
20 #include "content/browser/accessibility/browser_accessibility_manager.h"
21 #include "content/browser/accessibility/browser_accessibility_win.h"
22 #include "third_party/iaccessible2/ia2_api_all.h"
23 #include "ui/base/win/atl_module.h"
25 using base::StringPrintf;
27 namespace content {
29 const char* ALL_ATTRIBUTES[] = {
30 "name",
31 "value",
32 "states",
33 "attributes",
34 "role_name",
35 "currentValue",
36 "minimumValue",
37 "maximumValue",
38 "description",
39 "default_action",
40 "keyboard_shortcut",
41 "location",
42 "size",
43 "index_in_parent",
44 "n_relations",
45 "group_level",
46 "similar_items_in_group",
47 "position_in_group",
48 "table_rows",
49 "table_columns",
50 "row_index",
51 "column_index",
52 "n_characters",
53 "caret_offset",
54 "n_selections",
55 "selection_start",
56 "selection_end"
59 void AccessibilityTreeFormatter::Initialize() {
60 ui::win::CreateATLModuleIfNeeded();
63 void AccessibilityTreeFormatter::AddProperties(
64 const BrowserAccessibility& node, base::DictionaryValue* dict) {
65 dict->SetInteger("id", node.GetId());
66 BrowserAccessibilityWin* ax_object =
67 const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityWin();
68 DCHECK(ax_object);
70 VARIANT variant_self;
71 variant_self.vt = VT_I4;
72 variant_self.lVal = CHILDID_SELF;
74 dict->SetString("role", IAccessible2RoleToString(ax_object->ia2_role()));
76 base::win::ScopedBstr temp_bstr;
77 if (SUCCEEDED(ax_object->get_accName(variant_self, temp_bstr.Receive())))
78 dict->SetString("name", base::string16(temp_bstr, temp_bstr.Length()));
79 temp_bstr.Reset();
81 if (SUCCEEDED(ax_object->get_accValue(variant_self, temp_bstr.Receive())))
82 dict->SetString("value", base::string16(temp_bstr, temp_bstr.Length()));
83 temp_bstr.Reset();
85 std::vector<base::string16> state_strings;
86 int32 ia_state = ax_object->ia_state();
88 // Avoid flakiness: these states depend on whether the window is focused
89 // and the position of the mouse cursor.
90 ia_state &= ~STATE_SYSTEM_HOTTRACKED;
91 ia_state &= ~STATE_SYSTEM_OFFSCREEN;
93 IAccessibleStateToStringVector(ia_state, &state_strings);
94 IAccessible2StateToStringVector(ax_object->ia2_state(), &state_strings);
95 base::ListValue* states = new base::ListValue;
96 for (auto it = state_strings.begin(); it != state_strings.end(); ++it)
97 states->AppendString(base::UTF16ToUTF8(*it));
98 dict->Set("states", states);
100 const std::vector<base::string16>& ia2_attributes =
101 ax_object->ia2_attributes();
102 base::ListValue* attributes = new base::ListValue;
103 for (auto it = ia2_attributes.begin(); it != ia2_attributes.end(); ++it)
104 attributes->AppendString(base::UTF16ToUTF8(*it));
105 dict->Set("attributes", attributes);
107 dict->SetString("role_name", ax_object->role_name());
109 VARIANT currentValue;
110 if (ax_object->get_currentValue(&currentValue) == S_OK)
111 dict->SetDouble("currentValue", V_R8(&currentValue));
113 VARIANT minimumValue;
114 if (ax_object->get_minimumValue(&minimumValue) == S_OK)
115 dict->SetDouble("minimumValue", V_R8(&minimumValue));
117 VARIANT maximumValue;
118 if (ax_object->get_maximumValue(&maximumValue) == S_OK)
119 dict->SetDouble("maximumValue", V_R8(&maximumValue));
121 if (SUCCEEDED(ax_object->get_accDescription(variant_self,
122 temp_bstr.Receive()))) {
123 dict->SetString("description", base::string16(temp_bstr,
124 temp_bstr.Length()));
126 temp_bstr.Reset();
128 if (SUCCEEDED(ax_object->get_accDefaultAction(variant_self,
129 temp_bstr.Receive()))) {
130 dict->SetString("default_action", base::string16(temp_bstr,
131 temp_bstr.Length()));
133 temp_bstr.Reset();
135 if (SUCCEEDED(
136 ax_object->get_accKeyboardShortcut(variant_self, temp_bstr.Receive()))) {
137 dict->SetString("keyboard_shortcut", base::string16(temp_bstr,
138 temp_bstr.Length()));
140 temp_bstr.Reset();
142 if (SUCCEEDED(ax_object->get_accHelp(variant_self, temp_bstr.Receive())))
143 dict->SetString("help", base::string16(temp_bstr, temp_bstr.Length()));
144 temp_bstr.Reset();
146 BrowserAccessibility* root = node.manager()->GetRoot();
147 LONG left, top, width, height;
148 LONG root_left, root_top, root_width, root_height;
149 if (SUCCEEDED(ax_object->accLocation(
150 &left, &top, &width, &height, variant_self)) &&
151 SUCCEEDED(root->ToBrowserAccessibilityWin()->accLocation(
152 &root_left, &root_top, &root_width, &root_height, variant_self))) {
153 base::DictionaryValue* location = new base::DictionaryValue;
154 location->SetInteger("x", left - root_left);
155 location->SetInteger("y", top - root_top);
156 dict->Set("location", location);
158 base::DictionaryValue* size = new base::DictionaryValue;
159 size->SetInteger("width", width);
160 size->SetInteger("height", height);
161 dict->Set("size", size);
164 LONG index_in_parent;
165 if (SUCCEEDED(ax_object->get_indexInParent(&index_in_parent)))
166 dict->SetInteger("index_in_parent", index_in_parent);
168 LONG n_relations;
169 if (SUCCEEDED(ax_object->get_nRelations(&n_relations)))
170 dict->SetInteger("n_relations", n_relations);
172 LONG group_level, similar_items_in_group, position_in_group;
173 if (SUCCEEDED(ax_object->get_groupPosition(&group_level,
174 &similar_items_in_group,
175 &position_in_group))) {
176 dict->SetInteger("group_level", group_level);
177 dict->SetInteger("similar_items_in_group", similar_items_in_group);
178 dict->SetInteger("position_in_group", position_in_group);
181 LONG table_rows;
182 if (SUCCEEDED(ax_object->get_nRows(&table_rows)))
183 dict->SetInteger("table_rows", table_rows);
185 LONG table_columns;
186 if (SUCCEEDED(ax_object->get_nRows(&table_columns)))
187 dict->SetInteger("table_columns", table_columns);
189 LONG row_index;
190 if (SUCCEEDED(ax_object->get_rowIndex(&row_index)))
191 dict->SetInteger("row_index", row_index);
193 LONG column_index;
194 if (SUCCEEDED(ax_object->get_columnIndex(&column_index)))
195 dict->SetInteger("column_index", column_index);
197 LONG n_characters;
198 if (SUCCEEDED(ax_object->get_nCharacters(&n_characters)))
199 dict->SetInteger("n_characters", n_characters);
201 LONG caret_offset;
202 if (ax_object->get_caretOffset(&caret_offset) == S_OK)
203 dict->SetInteger("caret_offset", caret_offset);
205 LONG n_selections;
206 if (SUCCEEDED(ax_object->get_nSelections(&n_selections))) {
207 dict->SetInteger("n_selections", n_selections);
208 if (n_selections > 0) {
209 LONG start, end;
210 if (SUCCEEDED(ax_object->get_selection(0, &start, &end))) {
211 dict->SetInteger("selection_start", start);
212 dict->SetInteger("selection_end", end);
218 base::string16 AccessibilityTreeFormatter::ToString(
219 const base::DictionaryValue& dict) {
220 base::string16 line;
222 if (show_ids_) {
223 int id_value;
224 dict.GetInteger("id", &id_value);
225 WriteAttribute(true, base::IntToString16(id_value), &line);
228 base::string16 role_value;
229 dict.GetString("role", &role_value);
230 WriteAttribute(true, base::UTF16ToUTF8(role_value), &line);
232 for (int i = 0; i < arraysize(ALL_ATTRIBUTES); i++) {
233 const char* attribute_name = ALL_ATTRIBUTES[i];
234 const base::Value* value;
235 if (!dict.Get(attribute_name, &value))
236 continue;
238 switch (value->GetType()) {
239 case base::Value::TYPE_STRING: {
240 base::string16 string_value;
241 value->GetAsString(&string_value);
242 WriteAttribute(false,
243 StringPrintf(L"%ls='%ls'",
244 base::UTF8ToUTF16(attribute_name).c_str(),
245 string_value.c_str()),
246 &line);
247 break;
249 case base::Value::TYPE_INTEGER: {
250 int int_value;
251 value->GetAsInteger(&int_value);
252 WriteAttribute(false,
253 base::StringPrintf(L"%ls=%d",
254 base::UTF8ToUTF16(
255 attribute_name).c_str(),
256 int_value),
257 &line);
258 break;
260 case base::Value::TYPE_DOUBLE: {
261 double double_value;
262 value->GetAsDouble(&double_value);
263 WriteAttribute(false,
264 base::StringPrintf(L"%ls=%.2f",
265 base::UTF8ToUTF16(
266 attribute_name).c_str(),
267 double_value),
268 &line);
269 break;
271 case base::Value::TYPE_LIST: {
272 // Currently all list values are string and are written without
273 // attribute names.
274 const base::ListValue* list_value;
275 value->GetAsList(&list_value);
276 for (base::ListValue::const_iterator it = list_value->begin();
277 it != list_value->end();
278 ++it) {
279 base::string16 string_value;
280 if ((*it)->GetAsString(&string_value))
281 WriteAttribute(false, string_value, &line);
283 break;
285 case base::Value::TYPE_DICTIONARY: {
286 // Currently all dictionary values are coordinates.
287 // Revisit this if that changes.
288 const base::DictionaryValue* dict_value;
289 value->GetAsDictionary(&dict_value);
290 if (strcmp(attribute_name, "size") == 0) {
291 WriteAttribute(false,
292 FormatCoordinates("size", "width", "height",
293 *dict_value),
294 &line);
295 } else if (strcmp(attribute_name, "location") == 0) {
296 WriteAttribute(false,
297 FormatCoordinates("location", "x", "y", *dict_value),
298 &line);
300 break;
302 default:
303 NOTREACHED();
304 break;
308 return line;
311 // static
312 const base::FilePath::StringType
313 AccessibilityTreeFormatter::GetActualFileSuffix() {
314 return FILE_PATH_LITERAL("-actual-win.txt");
317 // static
318 const base::FilePath::StringType
319 AccessibilityTreeFormatter::GetExpectedFileSuffix() {
320 return FILE_PATH_LITERAL("-expected-win.txt");
323 // static
324 const std::string AccessibilityTreeFormatter::GetAllowEmptyString() {
325 return "@WIN-ALLOW-EMPTY:";
328 // static
329 const std::string AccessibilityTreeFormatter::GetAllowString() {
330 return "@WIN-ALLOW:";
333 // static
334 const std::string AccessibilityTreeFormatter::GetDenyString() {
335 return "@WIN-DENY:";
338 } // namespace content