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 <oleacc.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/accessibility/browser_accessibility_manager.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/accessibility/browser_accessibility_win.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/iaccessible2/ia2_api_all.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/win/atl_module.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using base::StringPrintf;
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char* ALL_ATTRIBUTES[] = {
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "name",
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "value",
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "states",
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "attributes",
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "role_name",
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "currentValue",
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "minimumValue",
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "maximumValue",
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "description",
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "default_action",
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "keyboard_shortcut",
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "location",
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "size",
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "index_in_parent",
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "n_relations",
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "group_level",
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "similar_items_in_group",
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "position_in_group",
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "table_rows",
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "table_columns",
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "row_index",
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "column_index",
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "n_characters",
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "caret_offset",
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "n_selections",
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "selection_start",
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    "selection_end"
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AccessibilityTreeFormatter::Initialize() {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::win::CreateATLModuleIfNeeded();
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AccessibilityTreeFormatter::AddProperties(
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const BrowserAccessibility& node, base::DictionaryValue* dict) {
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  BrowserAccessibilityWin* acc_obj =
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const_cast<BrowserAccessibility*>(&node)->ToBrowserAccessibilityWin();
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VARIANT variant_self;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  variant_self.vt = VT_I4;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  variant_self.lVal = CHILDID_SELF;
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->SetString("role", IAccessible2RoleToString(acc_obj->ia2_role()));
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CComBSTR msaa_variant;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hresult = acc_obj->get_accName(variant_self, &msaa_variant);
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (hresult == S_OK)
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetString("name", msaa_variant.m_str);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hresult = acc_obj->get_accValue(variant_self, &msaa_variant);
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (hresult == S_OK)
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetString("value", msaa_variant.m_str);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<base::string16> state_strings;
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int32 ia_state = acc_obj->ia_state();
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Avoid flakiness: these states depend on whether the window is focused
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // and the position of the mouse cursor.
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ia_state &= ~STATE_SYSTEM_HOTTRACKED;
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ia_state &= ~STATE_SYSTEM_OFFSCREEN;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IAccessibleStateToStringVector(ia_state, &state_strings);
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  IAccessible2StateToStringVector(acc_obj->ia2_state(), &state_strings);
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::ListValue* states = new base::ListValue;
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (std::vector<base::string16>::const_iterator it = state_strings.begin();
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != state_strings.end();
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       ++it) {
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    states->AppendString(base::UTF16ToUTF8(*it));
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->Set("states", states);
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const std::vector<base::string16>& ia2_attributes = acc_obj->ia2_attributes();
977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  base::ListValue* attributes = new base::ListValue;
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (std::vector<base::string16>::const_iterator it = ia2_attributes.begin();
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != ia2_attributes.end();
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       ++it) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    attributes->AppendString(base::UTF16ToUTF8(*it));
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->Set("attributes", attributes);
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->SetString("role_name", acc_obj->role_name());
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VARIANT currentValue;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_currentValue(&currentValue) == S_OK)
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetDouble("currentValue", V_R8(&currentValue));
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VARIANT minimumValue;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_minimumValue(&minimumValue) == S_OK)
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetDouble("minimumValue", V_R8(&minimumValue));
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VARIANT maximumValue;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_maximumValue(&maximumValue) == S_OK)
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetDouble("maximumValue", V_R8(&maximumValue));
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  hresult = acc_obj->get_accDescription(variant_self, &msaa_variant);
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (hresult == S_OK)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetString("description", msaa_variant.m_str);
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  hresult = acc_obj->get_accDefaultAction(variant_self, &msaa_variant);
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (hresult == S_OK)
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetString("default_action", msaa_variant.m_str);
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  hresult = acc_obj->get_accKeyboardShortcut(variant_self, &msaa_variant);
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (hresult == S_OK)
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetString("keyboard_shortcut", msaa_variant.m_str);
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  hresult = acc_obj->get_accHelp(variant_self, &msaa_variant);
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (S_OK == hresult)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetString("help", msaa_variant.m_str);
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  BrowserAccessibility* root = node.manager()->GetRoot();
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG left, top, width, height;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG root_left, root_top, root_width, root_height;
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (acc_obj->accLocation(&left, &top, &width, &height, variant_self)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      != S_FALSE
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      && root->ToBrowserAccessibilityWin()->accLocation(
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          &root_left, &root_top, &root_width, &root_height, variant_self)
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      != S_FALSE) {
1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::DictionaryValue* location = new base::DictionaryValue;
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    location->SetInteger("x", left - root_left);
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    location->SetInteger("y", top - root_top);
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->Set("location", location);
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::DictionaryValue* size = new base::DictionaryValue;
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size->SetInteger("width", width);
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size->SetInteger("height", height);
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->Set("size", size);
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG index_in_parent;
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_indexInParent(&index_in_parent) == S_OK)
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("index_in_parent", index_in_parent);
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG n_relations;
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_nRelations(&n_relations) == S_OK)
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("n_relations", n_relations);
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG group_level, similar_items_in_group, position_in_group;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_groupPosition(&group_level,
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 &similar_items_in_group,
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 &position_in_group) == S_OK) {
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("group_level", group_level);
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("similar_items_in_group", similar_items_in_group);
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("position_in_group", position_in_group);
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG table_rows;
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_nRows(&table_rows) == S_OK)
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("table_rows", table_rows);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG table_columns;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_nRows(&table_columns) == S_OK)
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("table_columns", table_columns);
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG row_index;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_rowIndex(&row_index) == S_OK)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("row_index", row_index);
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG column_index;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_columnIndex(&column_index) == S_OK)
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("column_index", column_index);
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG n_characters;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_nCharacters(&n_characters) == S_OK)
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("n_characters", n_characters);
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG caret_offset;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_caretOffset(&caret_offset) == S_OK)
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("caret_offset", caret_offset);
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG n_selections;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (acc_obj->get_nSelections(&n_selections) == S_OK) {
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    dict->SetInteger("n_selections", n_selections);
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (n_selections > 0) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LONG start, end;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (acc_obj->get_selection(0, &start, &end) == S_OK) {
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        dict->SetInteger("selection_start", start);
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        dict->SetInteger("selection_end", end);
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::string16 AccessibilityTreeFormatter::ToString(
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::DictionaryValue& dict,
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& indent) {
204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 line;
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 role_value;
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict.GetString("role", &role_value);
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WriteAttribute(true, base::UTF16ToUTF8(role_value), &line);
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 name_value;
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict.GetString("name", &name_value);
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WriteAttribute(true, base::StringPrintf(L"name='%ls'", name_value.c_str()),
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 &line);
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 0; i < arraysize(ALL_ATTRIBUTES); i++) {
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const char* attribute_name = ALL_ATTRIBUTES[i];
2177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const base::Value* value;
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!dict.Get(attribute_name, &value))
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    switch (value->GetType()) {
2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      case base::Value::TYPE_STRING: {
223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        base::string16 string_value;
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        value->GetAsString(&string_value);
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        WriteAttribute(false,
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       StringPrintf(L"%ls='%ls'",
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    base::UTF8ToUTF16(attribute_name).c_str(),
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    string_value.c_str()),
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       &line);
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      case base::Value::TYPE_INTEGER: {
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        int int_value;
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        value->GetAsInteger(&int_value);
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        WriteAttribute(false,
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       base::StringPrintf(L"%ls=%d",
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          base::UTF8ToUTF16(
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              attribute_name).c_str(),
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                          int_value),
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       &line);
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
2437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      case base::Value::TYPE_DOUBLE: {
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        double double_value;
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        value->GetAsDouble(&double_value);
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        WriteAttribute(false,
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       base::StringPrintf(L"%ls=%.2f",
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                          base::UTF8ToUTF16(
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                              attribute_name).c_str(),
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                          double_value),
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       &line);
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
2547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      case base::Value::TYPE_LIST: {
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Currently all list values are string and are written without
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // attribute names.
2577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        const base::ListValue* list_value;
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        value->GetAsList(&list_value);
2597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        for (base::ListValue::const_iterator it = list_value->begin();
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)             it != list_value->end();
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)             ++it) {
262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          base::string16 string_value;
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          if ((*it)->GetAsString(&string_value))
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            WriteAttribute(false, string_value, &line);
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
2687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      case base::Value::TYPE_DICTIONARY: {
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Currently all dictionary values are coordinates.
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Revisit this if that changes.
2717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        const base::DictionaryValue* dict_value;
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        value->GetAsDictionary(&dict_value);
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (strcmp(attribute_name, "size") == 0) {
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          WriteAttribute(false,
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         FormatCoordinates("size", "width", "height",
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           *dict_value),
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         &line);
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        } else if (strcmp(attribute_name, "location") == 0) {
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          WriteAttribute(false,
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         FormatCoordinates("location", "x", "y", *dict_value),
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         &line);
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      default:
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        NOTREACHED();
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        break;
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return indent + line + base::ASCIIToUTF16("\n");
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::StringType
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AccessibilityTreeFormatter::GetActualFileSuffix() {
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return FILE_PATH_LITERAL("-actual-win.txt");
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::StringType
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AccessibilityTreeFormatter::GetExpectedFileSuffix() {
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return FILE_PATH_LITERAL("-expected-win.txt");
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string AccessibilityTreeFormatter::GetAllowEmptyString() {
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "@WIN-ALLOW-EMPTY:";
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string AccessibilityTreeFormatter::GetAllowString() {
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "@WIN-ALLOW:";
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string AccessibilityTreeFormatter::GetDenyString() {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "@WIN-DENY:";
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
322