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"
11 #include "base/files/file_path.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
16 #include "content/browser/accessibility/browser_accessibility_manager.h"
17 #include "content/browser/accessibility/browser_accessibility_win.h"
18 #include "third_party/iaccessible2/ia2_api_all.h"
19 #include "ui/base/win/atl_module.h"
21 using base::StringPrintf
;
25 const char* ALL_ATTRIBUTES
[] = {
42 "similar_items_in_group",
55 void AccessibilityTreeFormatter::Initialize() {
56 ui::win::CreateATLModuleIfNeeded();
59 void AccessibilityTreeFormatter::AddProperties(
60 const BrowserAccessibility
& node
, base::DictionaryValue
* dict
) {
61 BrowserAccessibilityWin
* acc_obj
=
62 const_cast<BrowserAccessibility
*>(&node
)->ToBrowserAccessibilityWin();
65 variant_self
.vt
= VT_I4
;
66 variant_self
.lVal
= CHILDID_SELF
;
68 dict
->SetString("role", IAccessible2RoleToString(acc_obj
->ia2_role()));
70 CComBSTR msaa_variant
;
71 HRESULT hresult
= acc_obj
->get_accName(variant_self
, &msaa_variant
);
73 dict
->SetString("name", msaa_variant
.m_str
);
74 hresult
= acc_obj
->get_accValue(variant_self
, &msaa_variant
);
76 dict
->SetString("value", msaa_variant
.m_str
);
78 std::vector
<base::string16
> state_strings
;
79 int32 ia_state
= acc_obj
->ia_state();
81 // Avoid flakiness: these states depend on whether the window is focused
82 // and the position of the mouse cursor.
83 ia_state
&= ~STATE_SYSTEM_HOTTRACKED
;
84 ia_state
&= ~STATE_SYSTEM_OFFSCREEN
;
86 IAccessibleStateToStringVector(ia_state
, &state_strings
);
87 IAccessible2StateToStringVector(acc_obj
->ia2_state(), &state_strings
);
88 base::ListValue
* states
= new base::ListValue
;
89 for (std::vector
<base::string16
>::const_iterator it
= state_strings
.begin();
90 it
!= state_strings
.end();
92 states
->AppendString(base::UTF16ToUTF8(*it
));
94 dict
->Set("states", states
);
96 const std::vector
<base::string16
>& ia2_attributes
= acc_obj
->ia2_attributes();
97 base::ListValue
* attributes
= new base::ListValue
;
98 for (std::vector
<base::string16
>::const_iterator it
= ia2_attributes
.begin();
99 it
!= ia2_attributes
.end();
101 attributes
->AppendString(base::UTF16ToUTF8(*it
));
103 dict
->Set("attributes", attributes
);
105 dict
->SetString("role_name", acc_obj
->role_name());
107 VARIANT currentValue
;
108 if (acc_obj
->get_currentValue(¤tValue
) == S_OK
)
109 dict
->SetDouble("currentValue", V_R8(¤tValue
));
111 VARIANT minimumValue
;
112 if (acc_obj
->get_minimumValue(&minimumValue
) == S_OK
)
113 dict
->SetDouble("minimumValue", V_R8(&minimumValue
));
115 VARIANT maximumValue
;
116 if (acc_obj
->get_maximumValue(&maximumValue
) == S_OK
)
117 dict
->SetDouble("maximumValue", V_R8(&maximumValue
));
119 hresult
= acc_obj
->get_accDescription(variant_self
, &msaa_variant
);
121 dict
->SetString("description", msaa_variant
.m_str
);
123 hresult
= acc_obj
->get_accDefaultAction(variant_self
, &msaa_variant
);
125 dict
->SetString("default_action", msaa_variant
.m_str
);
127 hresult
= acc_obj
->get_accKeyboardShortcut(variant_self
, &msaa_variant
);
129 dict
->SetString("keyboard_shortcut", msaa_variant
.m_str
);
131 hresult
= acc_obj
->get_accHelp(variant_self
, &msaa_variant
);
133 dict
->SetString("help", msaa_variant
.m_str
);
135 BrowserAccessibility
* root
= node
.manager()->GetRoot();
136 LONG left
, top
, width
, height
;
137 LONG root_left
, root_top
, root_width
, root_height
;
138 if (acc_obj
->accLocation(&left
, &top
, &width
, &height
, variant_self
)
140 && root
->ToBrowserAccessibilityWin()->accLocation(
141 &root_left
, &root_top
, &root_width
, &root_height
, variant_self
)
143 base::DictionaryValue
* location
= new base::DictionaryValue
;
144 location
->SetInteger("x", left
- root_left
);
145 location
->SetInteger("y", top
- root_top
);
146 dict
->Set("location", location
);
148 base::DictionaryValue
* size
= new base::DictionaryValue
;
149 size
->SetInteger("width", width
);
150 size
->SetInteger("height", height
);
151 dict
->Set("size", size
);
154 LONG index_in_parent
;
155 if (acc_obj
->get_indexInParent(&index_in_parent
) == S_OK
)
156 dict
->SetInteger("index_in_parent", index_in_parent
);
159 if (acc_obj
->get_nRelations(&n_relations
) == S_OK
)
160 dict
->SetInteger("n_relations", n_relations
);
162 LONG group_level
, similar_items_in_group
, position_in_group
;
163 if (acc_obj
->get_groupPosition(&group_level
,
164 &similar_items_in_group
,
165 &position_in_group
) == S_OK
) {
166 dict
->SetInteger("group_level", group_level
);
167 dict
->SetInteger("similar_items_in_group", similar_items_in_group
);
168 dict
->SetInteger("position_in_group", position_in_group
);
171 if (acc_obj
->get_nRows(&table_rows
) == S_OK
)
172 dict
->SetInteger("table_rows", table_rows
);
174 if (acc_obj
->get_nRows(&table_columns
) == S_OK
)
175 dict
->SetInteger("table_columns", table_columns
);
177 if (acc_obj
->get_rowIndex(&row_index
) == S_OK
)
178 dict
->SetInteger("row_index", row_index
);
180 if (acc_obj
->get_columnIndex(&column_index
) == S_OK
)
181 dict
->SetInteger("column_index", column_index
);
183 if (acc_obj
->get_nCharacters(&n_characters
) == S_OK
)
184 dict
->SetInteger("n_characters", n_characters
);
186 if (acc_obj
->get_caretOffset(&caret_offset
) == S_OK
)
187 dict
->SetInteger("caret_offset", caret_offset
);
189 if (acc_obj
->get_nSelections(&n_selections
) == S_OK
) {
190 dict
->SetInteger("n_selections", n_selections
);
191 if (n_selections
> 0) {
193 if (acc_obj
->get_selection(0, &start
, &end
) == S_OK
) {
194 dict
->SetInteger("selection_start", start
);
195 dict
->SetInteger("selection_end", end
);
201 base::string16
AccessibilityTreeFormatter::ToString(
202 const base::DictionaryValue
& dict
,
203 const base::string16
& indent
) {
206 base::string16 role_value
;
207 dict
.GetString("role", &role_value
);
208 WriteAttribute(true, base::UTF16ToUTF8(role_value
), &line
);
210 for (int i
= 0; i
< arraysize(ALL_ATTRIBUTES
); i
++) {
211 const char* attribute_name
= ALL_ATTRIBUTES
[i
];
212 const base::Value
* value
;
213 if (!dict
.Get(attribute_name
, &value
))
216 switch (value
->GetType()) {
217 case base::Value::TYPE_STRING
: {
218 base::string16 string_value
;
219 value
->GetAsString(&string_value
);
220 WriteAttribute(false,
221 StringPrintf(L
"%ls='%ls'",
222 base::UTF8ToUTF16(attribute_name
).c_str(),
223 string_value
.c_str()),
227 case base::Value::TYPE_INTEGER
: {
229 value
->GetAsInteger(&int_value
);
230 WriteAttribute(false,
231 base::StringPrintf(L
"%ls=%d",
233 attribute_name
).c_str(),
238 case base::Value::TYPE_DOUBLE
: {
240 value
->GetAsDouble(&double_value
);
241 WriteAttribute(false,
242 base::StringPrintf(L
"%ls=%.2f",
244 attribute_name
).c_str(),
249 case base::Value::TYPE_LIST
: {
250 // Currently all list values are string and are written without
252 const base::ListValue
* list_value
;
253 value
->GetAsList(&list_value
);
254 for (base::ListValue::const_iterator it
= list_value
->begin();
255 it
!= list_value
->end();
257 base::string16 string_value
;
258 if ((*it
)->GetAsString(&string_value
))
259 WriteAttribute(false, string_value
, &line
);
263 case base::Value::TYPE_DICTIONARY
: {
264 // Currently all dictionary values are coordinates.
265 // Revisit this if that changes.
266 const base::DictionaryValue
* dict_value
;
267 value
->GetAsDictionary(&dict_value
);
268 if (strcmp(attribute_name
, "size") == 0) {
269 WriteAttribute(false,
270 FormatCoordinates("size", "width", "height",
273 } else if (strcmp(attribute_name
, "location") == 0) {
274 WriteAttribute(false,
275 FormatCoordinates("location", "x", "y", *dict_value
),
286 return indent
+ line
+ base::ASCIIToUTF16("\n");
290 const base::FilePath::StringType
291 AccessibilityTreeFormatter::GetActualFileSuffix() {
292 return FILE_PATH_LITERAL("-actual-win.txt");
296 const base::FilePath::StringType
297 AccessibilityTreeFormatter::GetExpectedFileSuffix() {
298 return FILE_PATH_LITERAL("-expected-win.txt");
302 const std::string
AccessibilityTreeFormatter::GetAllowEmptyString() {
303 return "@WIN-ALLOW-EMPTY:";
307 const std::string
AccessibilityTreeFormatter::GetAllowString() {
308 return "@WIN-ALLOW:";
312 const std::string
AccessibilityTreeFormatter::GetDenyString() {
316 } // namespace content