1// Copyright 2014 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 "chrome/browser/extensions/api/automation_internal/automation_util.h" 6 7#include <string> 8#include <utility> 9 10#include "base/values.h" 11#include "chrome/common/extensions/api/automation_internal.h" 12#include "extensions/browser/event_router.h" 13#include "ui/accessibility/ax_enums.h" 14#include "ui/accessibility/ax_node_data.h" 15 16namespace extensions { 17 18namespace { 19 20void PopulateNodeData(const ui::AXNodeData& node_data, 21 linked_ptr< api::automation_internal::AXNodeData>& out_node_data) { 22 out_node_data->id = node_data.id; 23 out_node_data->role = ToString(node_data.role); 24 25 uint32 state_pos = 0, state_shifter = node_data.state; 26 while (state_shifter) { 27 if (state_shifter & 1) { 28 out_node_data->state.additional_properties.SetBoolean( 29 ToString(static_cast<ui::AXState>(state_pos)), true); 30 } 31 state_shifter = state_shifter >> 1; 32 state_pos++; 33 } 34 35 out_node_data->location.left = node_data.location.x(); 36 out_node_data->location.top = node_data.location.y(); 37 out_node_data->location.width = node_data.location.width(); 38 out_node_data->location.height = node_data.location.height(); 39 40 if (!node_data.bool_attributes.empty()) { 41 out_node_data->bool_attributes.reset( 42 new api::automation_internal::AXNodeData::BoolAttributes()); 43 for (size_t i = 0; i < node_data.bool_attributes.size(); ++i) { 44 std::pair<ui::AXBoolAttribute, bool> attr = 45 node_data.bool_attributes[i]; 46 out_node_data->bool_attributes->additional_properties.SetBoolean( 47 ToString(attr.first), attr.second); 48 } 49 } 50 51 if (!node_data.float_attributes.empty()) { 52 out_node_data->float_attributes.reset( 53 new api::automation_internal::AXNodeData::FloatAttributes()); 54 for (size_t i = 0; i < node_data.float_attributes.size(); ++i) { 55 std::pair<ui::AXFloatAttribute, float> attr = 56 node_data.float_attributes[i]; 57 out_node_data->float_attributes->additional_properties.SetDouble( 58 ToString(attr.first), attr.second); 59 } 60 } 61 62 if (!node_data.html_attributes.empty()) { 63 out_node_data->html_attributes.reset( 64 new api::automation_internal::AXNodeData::HtmlAttributes()); 65 for (size_t i = 0; i < node_data.html_attributes.size(); ++i) { 66 std::pair<std::string, std::string> attr = node_data.html_attributes[i]; 67 out_node_data->html_attributes->additional_properties.SetString( 68 attr.first, attr.second); 69 } 70 } 71 72 if (!node_data.int_attributes.empty()) { 73 out_node_data->int_attributes.reset( 74 new api::automation_internal::AXNodeData::IntAttributes()); 75 for (size_t i = 0; i < node_data.int_attributes.size(); ++i) { 76 std::pair<ui::AXIntAttribute, int> attr = node_data.int_attributes[i]; 77 out_node_data->int_attributes->additional_properties.SetInteger( 78 ToString(attr.first), attr.second); 79 } 80 } 81 82 if (!node_data.intlist_attributes.empty()) { 83 out_node_data->intlist_attributes.reset( 84 new api::automation_internal::AXNodeData::IntlistAttributes()); 85 for (size_t i = 0; i < node_data.intlist_attributes.size(); ++i) { 86 std::pair<ui::AXIntListAttribute, std::vector<int32> > attr = 87 node_data.intlist_attributes[i]; 88 base::ListValue* intlist = new base::ListValue(); 89 for (size_t j = 0; j < attr.second.size(); ++j) 90 intlist->AppendInteger(attr.second[j]); 91 out_node_data->intlist_attributes->additional_properties.Set( 92 ToString(attr.first), intlist); 93 } 94 } 95 96 if (!node_data.string_attributes.empty()) { 97 out_node_data->string_attributes.reset( 98 new api::automation_internal::AXNodeData::StringAttributes()); 99 for (size_t i = 0; i < node_data.string_attributes.size(); ++i) { 100 std::pair<ui::AXStringAttribute, std::string> attr = 101 node_data.string_attributes[i]; 102 out_node_data->string_attributes->additional_properties.SetString( 103 ToString(attr.first), attr.second); 104 } 105 } 106 107 for (size_t i = 0; i < node_data.child_ids.size(); ++i) { 108 out_node_data->child_ids.push_back(node_data.child_ids[i]); 109 } 110} 111 112void DispatchEventInternal(content::BrowserContext* context, 113 const std::string& event_name, 114 scoped_ptr<base::ListValue> args) { 115 if (context && EventRouter::Get(context)) { 116 scoped_ptr<Event> event(new Event(event_name, args.Pass())); 117 event->restrict_to_browser_context = context; 118 EventRouter::Get(context)->BroadcastEvent(event.Pass()); 119 } 120} 121 122} // namespace 123 124namespace automation_util { 125 126void DispatchAccessibilityEventsToAutomation( 127 const std::vector<content::AXEventNotificationDetails>& details, 128 content::BrowserContext* browser_context, 129 const gfx::Vector2d& location_offset) { 130 using api::automation_internal::AXEventParams; 131 using api::automation_internal::AXTreeUpdate; 132 133 std::vector<content::AXEventNotificationDetails>::const_iterator iter = 134 details.begin(); 135 for (; iter != details.end(); ++iter) { 136 const content::AXEventNotificationDetails& event = *iter; 137 138 AXEventParams ax_event_params; 139 ax_event_params.process_id = event.process_id; 140 ax_event_params.routing_id = event.routing_id; 141 ax_event_params.event_type = ToString(iter->event_type); 142 ax_event_params.target_id = event.id; 143 144 AXTreeUpdate& ax_tree_update = ax_event_params.update; 145 ax_tree_update.node_id_to_clear = event.node_id_to_clear; 146 for (size_t i = 0; i < event.nodes.size(); ++i) { 147 ui::AXNodeData src = event.nodes[i]; 148 src.location.Offset(location_offset); 149 linked_ptr<api::automation_internal::AXNodeData> out_node( 150 new api::automation_internal::AXNodeData()); 151 PopulateNodeData(src, out_node); 152 ax_tree_update.nodes.push_back(out_node); 153 } 154 155 // TODO(dtseng/aboxhall): Why are we sending only one update at a time? We 156 // should match the behavior from renderer -> browser and send a 157 // collection of tree updates over (to the extension); see 158 // |AccessibilityHostMsg_EventParams| and |AccessibilityHostMsg_Events|. 159 DispatchEventInternal( 160 browser_context, 161 api::automation_internal::OnAccessibilityEvent::kEventName, 162 api::automation_internal::OnAccessibilityEvent::Create( 163 ax_event_params)); 164 } 165} 166 167void DispatchTreeDestroyedEventToAutomation( 168 int process_id, 169 int routing_id, 170 content::BrowserContext* browser_context) { 171 DispatchEventInternal( 172 browser_context, 173 api::automation_internal::OnAccessibilityTreeDestroyed::kEventName, 174 api::automation_internal::OnAccessibilityTreeDestroyed::Create( 175 process_id, routing_id)); 176} 177 178} // namespace automation_util 179 180} // namespace extensions 181