| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 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/chromeos/arc/accessibility/ax_tree_source_arc.h" |
| 6 |
| 7 #include <string> |
| 8 |
| 9 #include "chrome/browser/extensions/api/automation_internal/automation_event_rou
ter.h" |
| 10 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" |
| 11 #include "chrome/common/extensions/chrome_extension_messages.h" |
| 12 #include "components/exo/wm_helper.h" |
| 13 #include "ui/accessibility/ax_tree_id_registry.h" |
| 14 #include "ui/aura/window.h" |
| 15 |
| 16 namespace { |
| 17 |
| 18 ui::AXEvent ToAXEvent(arc::mojom::AccessibilityEventType arc_event_type) { |
| 19 switch (arc_event_type) { |
| 20 case arc::mojom::AccessibilityEventType::VIEW_FOCUSED: |
| 21 case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUSED: |
| 22 return ui::AX_EVENT_FOCUS; |
| 23 case arc::mojom::AccessibilityEventType::VIEW_ACCESSIBILITY_FOCUS_CLEARED: |
| 24 return ui::AX_EVENT_BLUR; |
| 25 case arc::mojom::AccessibilityEventType::VIEW_CLICKED: |
| 26 case arc::mojom::AccessibilityEventType::VIEW_LONG_CLICKED: |
| 27 return ui::AX_EVENT_CLICKED; |
| 28 case arc::mojom::AccessibilityEventType::VIEW_TEXT_CHANGED: |
| 29 return ui::AX_EVENT_TEXT_CHANGED; |
| 30 case arc::mojom::AccessibilityEventType::VIEW_TEXT_SELECTION_CHANGED: |
| 31 return ui::AX_EVENT_TEXT_SELECTION_CHANGED; |
| 32 case arc::mojom::AccessibilityEventType::WINDOW_STATE_CHANGED: |
| 33 case arc::mojom::AccessibilityEventType::NOTIFICATION_STATE_CHANGED: |
| 34 case arc::mojom::AccessibilityEventType::WINDOW_CONTENT_CHANGED: |
| 35 case arc::mojom::AccessibilityEventType::WINDOWS_CHANGED: |
| 36 return ui::AX_EVENT_LAYOUT_COMPLETE; |
| 37 case arc::mojom::AccessibilityEventType::VIEW_HOVER_ENTER: |
| 38 return ui::AX_EVENT_HOVER; |
| 39 case arc::mojom::AccessibilityEventType::ANNOUNCEMENT: |
| 40 return ui::AX_EVENT_ALERT; |
| 41 case arc::mojom::AccessibilityEventType::VIEW_SELECTED: |
| 42 case arc::mojom::AccessibilityEventType::VIEW_HOVER_EXIT: |
| 43 case arc::mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_START: |
| 44 case arc::mojom::AccessibilityEventType::TOUCH_EXPLORATION_GESTURE_END: |
| 45 case arc::mojom::AccessibilityEventType::VIEW_SCROLLED: |
| 46 case arc::mojom::AccessibilityEventType:: |
| 47 VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: |
| 48 case arc::mojom::AccessibilityEventType::GESTURE_DETECTION_START: |
| 49 case arc::mojom::AccessibilityEventType::GESTURE_DETECTION_END: |
| 50 case arc::mojom::AccessibilityEventType::TOUCH_INTERACTION_START: |
| 51 case arc::mojom::AccessibilityEventType::TOUCH_INTERACTION_END: |
| 52 case arc::mojom::AccessibilityEventType::VIEW_CONTEXT_CLICKED: |
| 53 case arc::mojom::AccessibilityEventType::ASSIST_READING_CONTEXT: |
| 54 return ui::AX_EVENT_CHILDREN_CHANGED; |
| 55 default: |
| 56 return ui::AX_EVENT_CHILDREN_CHANGED; |
| 57 } |
| 58 return ui::AX_EVENT_CHILDREN_CHANGED; |
| 59 } |
| 60 |
| 61 const gfx::Rect GetBounds(arc::mojom::AccessibilityNodeInfoData* node) { |
| 62 exo::WMHelper* wmHelper = exo::WMHelper::GetInstance(); |
| 63 aura::Window* focused_window = wmHelper->GetFocusedWindow(); |
| 64 gfx::Rect bounds_in_screen = node->boundsInScreen; |
| 65 if (focused_window) { |
| 66 aura::Window* toplevel_window = focused_window->GetToplevelWindow(); |
| 67 return gfx::ScaleToEnclosingRect( |
| 68 bounds_in_screen, |
| 69 1.0f / toplevel_window->layer()->device_scale_factor()); |
| 70 } |
| 71 return bounds_in_screen; |
| 72 } |
| 73 |
| 74 bool GetStringProperty(arc::mojom::AccessibilityNodeInfoData* node, |
| 75 arc::mojom::AccessibilityStringProperty prop, |
| 76 std::string* out_value) { |
| 77 if (!node->stringProperties) |
| 78 return false; |
| 79 |
| 80 auto it = node->stringProperties->find(prop); |
| 81 if (it == node->stringProperties->end()) |
| 82 return false; |
| 83 |
| 84 *out_value = it->second; |
| 85 return true; |
| 86 } |
| 87 |
| 88 } // namespace |
| 89 |
| 90 namespace arc { |
| 91 |
| 92 AXTreeSourceArc::AXTreeSourceArc() |
| 93 : tree_id_(ui::AXTreeIDRegistry::GetInstance()->CreateID()), |
| 94 current_tree_serializer_(new AXTreeArcSerializer(this)), |
| 95 root_id_(-1), |
| 96 focused_node_id_(-1) {} |
| 97 |
| 98 AXTreeSourceArc::~AXTreeSourceArc() { |
| 99 Reset(); |
| 100 } |
| 101 |
| 102 void AXTreeSourceArc::NotifyAccessibilityEvent( |
| 103 mojom::AccessibilityEventData* event_data) { |
| 104 tree_map_.clear(); |
| 105 parent_map_.clear(); |
| 106 root_id_ = -1; |
| 107 focused_node_id_ = -1; |
| 108 for (size_t i = 0; i < event_data->nodeData.size(); ++i) { |
| 109 if (!event_data->nodeData[i]->intListProperties) |
| 110 continue; |
| 111 auto it = event_data->nodeData[i]->intListProperties->find( |
| 112 arc::mojom::AccessibilityIntListProperty::CHILD_NODE_IDS); |
| 113 if (it != event_data->nodeData[i]->intListProperties->end()) { |
| 114 for (size_t j = 0; j < it->second.size(); ++j) |
| 115 parent_map_[it->second[j]] = event_data->nodeData[i]->id; |
| 116 } |
| 117 } |
| 118 |
| 119 for (size_t i = 0; i < event_data->nodeData.size(); ++i) { |
| 120 int32_t id = event_data->nodeData[i]->id; |
| 121 tree_map_[id] = event_data->nodeData[i].get(); |
| 122 if (parent_map_.find(id) == parent_map_.end()) { |
| 123 CHECK_EQ(-1, root_id_) << "Duplicated root"; |
| 124 root_id_ = id; |
| 125 } |
| 126 } |
| 127 |
| 128 ExtensionMsg_AccessibilityEventParams params; |
| 129 params.event_type = ToAXEvent(event_data->eventType); |
| 130 if (params.event_type == ui::AX_EVENT_FOCUS) |
| 131 focused_node_id_ = params.id; |
| 132 params.tree_id = tree_id_; |
| 133 params.id = event_data->sourceId; |
| 134 |
| 135 current_tree_serializer_->SerializeChanges(GetFromId(event_data->sourceId), |
| 136 ¶ms.update); |
| 137 |
| 138 extensions::AutomationEventRouter* router = |
| 139 extensions::AutomationEventRouter::GetInstance(); |
| 140 router->DispatchAccessibilityEvent(params); |
| 141 } |
| 142 |
| 143 bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const { |
| 144 data->tree_id = tree_id_; |
| 145 if (focused_node_id_ >= 0) |
| 146 data->focus_id = focused_node_id_; |
| 147 return true; |
| 148 } |
| 149 |
| 150 mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetRoot() const { |
| 151 mojom::AccessibilityNodeInfoData* root = GetFromId(root_id_); |
| 152 return root; |
| 153 } |
| 154 |
| 155 mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetFromId(int32_t id) const { |
| 156 auto it = tree_map_.find(id); |
| 157 if (it == tree_map_.end()) |
| 158 return nullptr; |
| 159 return it->second; |
| 160 } |
| 161 |
| 162 int32_t AXTreeSourceArc::GetId(mojom::AccessibilityNodeInfoData* node) const { |
| 163 if (!node) |
| 164 return -1; |
| 165 return node->id; |
| 166 } |
| 167 |
| 168 void AXTreeSourceArc::GetChildren( |
| 169 mojom::AccessibilityNodeInfoData* node, |
| 170 std::vector<mojom::AccessibilityNodeInfoData*>* out_children) const { |
| 171 if (!node || !node->intListProperties) |
| 172 return; |
| 173 |
| 174 auto it = node->intListProperties->find( |
| 175 arc::mojom::AccessibilityIntListProperty::CHILD_NODE_IDS); |
| 176 if (it == node->intListProperties->end()) |
| 177 return; |
| 178 |
| 179 for (size_t i = 0; i < it->second.size(); ++i) { |
| 180 out_children->push_back(GetFromId(it->second[i])); |
| 181 } |
| 182 } |
| 183 |
| 184 mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetParent( |
| 185 mojom::AccessibilityNodeInfoData* node) const { |
| 186 if (!node) |
| 187 return nullptr; |
| 188 auto it = parent_map_.find(node->id); |
| 189 if (it != parent_map_.end()) |
| 190 return GetFromId(it->second); |
| 191 return nullptr; |
| 192 } |
| 193 |
| 194 bool AXTreeSourceArc::IsValid(mojom::AccessibilityNodeInfoData* node) const { |
| 195 return node; |
| 196 } |
| 197 |
| 198 bool AXTreeSourceArc::IsEqual(mojom::AccessibilityNodeInfoData* node1, |
| 199 mojom::AccessibilityNodeInfoData* node2) const { |
| 200 if (!node1 || !node2) |
| 201 return false; |
| 202 return node1->id == node2->id; |
| 203 } |
| 204 |
| 205 mojom::AccessibilityNodeInfoData* AXTreeSourceArc::GetNull() const { |
| 206 return nullptr; |
| 207 } |
| 208 |
| 209 void AXTreeSourceArc::SerializeNode(mojom::AccessibilityNodeInfoData* node, |
| 210 ui::AXNodeData* out_data) const { |
| 211 if (!node) |
| 212 return; |
| 213 out_data->id = node->id; |
| 214 out_data->state = 0; |
| 215 |
| 216 using AXStringProperty = arc::mojom::AccessibilityStringProperty; |
| 217 std::string text; |
| 218 if (GetStringProperty(node, AXStringProperty::TEXT, &text)) |
| 219 out_data->SetName(text); |
| 220 else if (GetStringProperty(node, AXStringProperty::CONTENT_DESCRIPTION, |
| 221 &text)) |
| 222 out_data->SetName(text); |
| 223 |
| 224 int32_t id = node->id; |
| 225 if (id == root_id_) |
| 226 out_data->role = ui::AX_ROLE_ROOT_WEB_AREA; |
| 227 else if (!text.empty()) |
| 228 out_data->role = ui::AX_ROLE_STATIC_TEXT; |
| 229 else |
| 230 out_data->role = ui::AX_ROLE_DIV; |
| 231 |
| 232 const gfx::Rect bounds_in_screen = GetBounds(node); |
| 233 out_data->location.SetRect(bounds_in_screen.x(), bounds_in_screen.y(), |
| 234 bounds_in_screen.width(), |
| 235 bounds_in_screen.height()); |
| 236 } |
| 237 |
| 238 void AXTreeSourceArc::Reset() { |
| 239 tree_map_.clear(); |
| 240 parent_map_.clear(); |
| 241 current_tree_serializer_.reset(new AXTreeArcSerializer(this)); |
| 242 root_id_ = -1; |
| 243 focused_node_id_ = -1; |
| 244 extensions::AutomationEventRouter* router = |
| 245 extensions::AutomationEventRouter::GetInstance(); |
| 246 router->DispatchTreeDestroyedEvent(tree_id_, nullptr); |
| 247 } |
| 248 |
| 249 } // namespace arc |
| OLD | NEW |