OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/browser_accessibility_manager.h" | 5 #include "chrome/browser/browser_accessibility_manager.h" |
6 | 6 |
7 #include "chrome/browser/browser_accessibility.h" | 7 #include "chrome/browser/browser_accessibility.h" |
8 #include "chrome/browser/renderer_host/render_process_host.h" | 8 #include "chrome/browser/renderer_host/render_process_host.h" |
9 #include "chrome/browser/renderer_host/render_widget_host.h" | 9 #include "chrome/browser/renderer_host/render_view_host.h" |
10 #include "chrome/common/notification_service.h" | 10 #include "chrome/common/notification_service.h" |
11 #include "chrome/common/render_messages.h" | 11 #include "chrome/common/render_messages.h" |
12 | 12 |
13 using webkit_glue::WebAccessibility; | 13 using webkit_glue::WebAccessibility; |
14 | 14 |
15 // The time in ms after which we give up and return an error when processing an | 15 // The time in ms after which we give up and return an error when processing an |
16 // accessibility message and no response has been received from the renderer. | 16 // accessibility message and no response has been received from the renderer. |
17 static const int kAccessibilityMessageTimeOut = 10000; | 17 static const int kAccessibilityMessageTimeOut = 10000; |
18 | 18 |
19 // static | 19 // static |
20 BrowserAccessibilityManager* BrowserAccessibilityManager::GetInstance() { | 20 BrowserAccessibilityManager* BrowserAccessibilityManager::GetInstance() { |
21 return Singleton<BrowserAccessibilityManager>::get(); | 21 return Singleton<BrowserAccessibilityManager>::get(); |
22 } | 22 } |
23 | 23 |
24 BrowserAccessibilityManager::BrowserAccessibilityManager() | 24 BrowserAccessibilityManager::BrowserAccessibilityManager() { |
25 : instance_id_(0) { | |
26 NotificationService::current()->AddObserver(this, | 25 NotificationService::current()->AddObserver(this, |
27 NotificationType::RENDERER_PROCESS_TERMINATED, | 26 NotificationType::RENDERER_PROCESS_TERMINATED, |
28 NotificationService::AllSources()); | 27 NotificationService::AllSources()); |
29 } | 28 } |
30 | 29 |
31 BrowserAccessibilityManager::~BrowserAccessibilityManager() { | 30 BrowserAccessibilityManager::~BrowserAccessibilityManager() { |
32 // Clear hashmaps. | 31 // Clear hashmap. |
33 instance_map_.clear(); | |
34 render_process_host_map_.clear(); | 32 render_process_host_map_.clear(); |
35 | 33 |
36 // We don't remove ourselves as an observer because we are a Singleton object, | 34 // We don't remove ourselves as an observer because we are a Singleton object, |
37 // and NotifcationService is likely gone by this point. | 35 // and NotifcationService is likely gone by this point. |
38 } | 36 } |
39 | 37 |
40 STDMETHODIMP BrowserAccessibilityManager::CreateAccessibilityInstance( | 38 STDMETHODIMP BrowserAccessibilityManager::CreateAccessibilityInstance( |
41 REFIID iid, int acc_obj_id, int instance_id, void** interface_ptr) { | 39 REFIID iid, int acc_obj_id, int routing_id, int process_id, |
| 40 HWND parent_hwnd, void** interface_ptr) { |
42 if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid) { | 41 if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid) { |
43 CComObject<BrowserAccessibility>* instance = NULL; | 42 CComObject<BrowserAccessibility>* instance = NULL; |
44 | 43 |
45 HRESULT hr = CComObject<BrowserAccessibility>::CreateInstance(&instance); | 44 HRESULT hr = CComObject<BrowserAccessibility>::CreateInstance(&instance); |
46 DCHECK(SUCCEEDED(hr)); | 45 DCHECK(SUCCEEDED(hr)); |
47 | 46 |
48 if (!instance) | 47 if (!instance) |
49 return E_FAIL; | 48 return E_FAIL; |
50 | 49 |
51 CComPtr<IAccessible> accessibility_instance(instance); | 50 CComPtr<IAccessible> accessibility_instance(instance); |
52 | 51 |
53 // Set unique ids. | 52 // Set class member variables. |
54 instance->set_iaccessible_id(acc_obj_id); | 53 instance->Initialize(acc_obj_id, routing_id, process_id, parent_hwnd); |
55 instance->set_instance_id(instance_id); | |
56 | 54 |
57 // Retrieve the RenderWidgetHost connected to this request. | 55 // Retrieve the RenderViewHost connected to this request. |
58 InstanceMap::iterator it = instance_map_.find(instance_id); | 56 RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id); |
59 | 57 |
60 if (it != instance_map_.end()) { | 58 // Update cache with RenderProcessHost/BrowserAccessibility pair. |
61 UniqueMembers* members = it->second; | 59 if (rvh && rvh->process()) { |
62 | 60 render_process_host_map_.insert( |
63 if (!members || !members->render_widget_host_) | 61 MapEntry(rvh->process()->pid(), instance)); |
64 return E_FAIL; | |
65 | |
66 render_process_host_map_[members->render_widget_host_->process()] = | |
67 instance; | |
68 } else { | 62 } else { |
69 // No RenderProcess active for this instance. | 63 // No RenderProcess active for this instance. |
70 return E_FAIL; | 64 return E_FAIL; |
71 } | 65 } |
72 | 66 |
73 // All is well, assign the temp instance to the output pointer. | 67 // All is well, assign the temp instance to the output pointer. |
74 *interface_ptr = accessibility_instance.Detach(); | 68 *interface_ptr = accessibility_instance.Detach(); |
75 return S_OK; | 69 return S_OK; |
76 } | 70 } |
77 // No supported interface found, return error. | 71 // No supported interface found, return error. |
78 *interface_ptr = NULL; | 72 *interface_ptr = NULL; |
79 return E_NOINTERFACE; | 73 return E_NOINTERFACE; |
80 } | 74 } |
81 | 75 |
82 bool BrowserAccessibilityManager::RequestAccessibilityInfo( | 76 bool BrowserAccessibilityManager::RequestAccessibilityInfo( |
83 int acc_obj_id, int instance_id, int acc_func_id, int child_id, long input1, | 77 WebAccessibility::InParams* in, int routing_id, int process_id) { |
84 long input2) { | |
85 // Create and populate IPC message structure, for retrieval of accessibility | 78 // Create and populate IPC message structure, for retrieval of accessibility |
86 // information from the renderer. | 79 // information from the renderer. |
87 WebAccessibility::InParams in_params; | 80 WebAccessibility::InParams in_params; |
88 in_params.object_id = acc_obj_id; | 81 in_params.object_id = in->object_id; |
89 in_params.function_id = acc_func_id; | 82 in_params.function_id = in->function_id; |
90 in_params.child_id = child_id; | 83 in_params.child_id = in->child_id; |
91 in_params.input_long1 = input1; | 84 in_params.direct_descendant = in->direct_descendant; |
92 in_params.input_long2 = input2; | 85 in_params.input_long1 = in->input_long1; |
| 86 in_params.input_long2 = in->input_long2; |
93 | 87 |
94 // Retrieve the RenderWidgetHost connected to this request. | 88 // Retrieve the RenderViewHost connected to this request. |
95 InstanceMap::iterator it = instance_map_.find(instance_id); | 89 RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id); |
96 | 90 |
97 if (it == instance_map_.end()) { | 91 // Send accessibility information retrieval message to the renderer. |
98 // Id not found. | |
99 return false; | |
100 } | |
101 | |
102 UniqueMembers* members = it->second; | |
103 | |
104 if (!members || !members->render_widget_host_) | |
105 return false; | |
106 | |
107 bool success = false; | 92 bool success = false; |
108 if (members->render_widget_host_->process() && | 93 if (rvh && rvh->process() && rvh->process()->channel()) { |
109 members->render_widget_host_->process()->channel()) { | |
110 IPC::SyncMessage* msg = | 94 IPC::SyncMessage* msg = |
111 new ViewMsg_GetAccessibilityInfo(members->render_widget_host_-> | 95 new ViewMsg_GetAccessibilityInfo(routing_id, in_params, &out_params_); |
112 routing_id(), in_params, &out_params_); | |
113 // Necessary for the send to keep the UI responsive. | 96 // Necessary for the send to keep the UI responsive. |
114 msg->EnableMessagePumping(); | 97 msg->EnableMessagePumping(); |
115 success = members->render_widget_host_->process()->channel()-> | 98 success = rvh->process()->channel()->SendWithTimeout(msg, |
116 SendWithTimeout(msg, kAccessibilityMessageTimeOut); | 99 kAccessibilityMessageTimeOut); |
117 } | 100 } |
118 return success; | 101 return success; |
119 } | 102 } |
120 | 103 |
| 104 bool BrowserAccessibilityManager::ChangeAccessibilityFocus(int acc_obj_id, |
| 105 int process_id, |
| 106 int routing_id) { |
| 107 BrowserAccessibility* browser_acc = |
| 108 GetBrowserAccessibility(process_id, routing_id); |
| 109 if (browser_acc) { |
| 110 // Indicate that the request for child information is referring to a non- |
| 111 // direct descendant of the root. |
| 112 browser_acc->set_direct_descendant(false); |
| 113 |
| 114 // Notify Access Technology that there was a change in keyboard focus. |
| 115 ::NotifyWinEvent(EVENT_OBJECT_FOCUS, browser_acc->parent_hwnd(), |
| 116 OBJID_CLIENT, static_cast<LONG>(acc_obj_id)); |
| 117 return true; |
| 118 } |
| 119 return false; |
| 120 } |
| 121 |
121 const WebAccessibility::OutParams& BrowserAccessibilityManager::response() { | 122 const WebAccessibility::OutParams& BrowserAccessibilityManager::response() { |
122 return out_params_; | 123 return out_params_; |
123 } | 124 } |
124 | 125 |
125 HWND BrowserAccessibilityManager::parent_hwnd(int id) { | 126 BrowserAccessibility* BrowserAccessibilityManager::GetBrowserAccessibility( |
126 // Retrieve the parent HWND connected to the requester's id. | 127 int process_id, int routing_id) { |
127 InstanceMap::iterator it = instance_map_.find(id); | 128 // Retrieve the BrowserAccessibility connected to the requester's id. There |
| 129 // could be multiple BrowserAccessibility connected to the given |process_id|, |
| 130 // but they all have the same parent HWND, so using the first hit is fine. |
| 131 RenderProcessHostMap::iterator it = |
| 132 render_process_host_map_.lower_bound(process_id); |
128 | 133 |
129 if (it == instance_map_.end()) { | 134 RenderProcessHostMap::iterator end_of_matching_objects = |
130 // Id not found. | 135 render_process_host_map_.upper_bound(process_id); |
131 return NULL; | 136 |
| 137 for (; it != end_of_matching_objects; ++it) { |
| 138 if (it->second && it->second->routing_id() == routing_id) |
| 139 return it->second; |
132 } | 140 } |
133 | 141 return NULL; |
134 UniqueMembers* members = it->second; | |
135 | |
136 if (!members || !members->parent_hwnd_) | |
137 return NULL; | |
138 | |
139 return members->parent_hwnd_; | |
140 } | |
141 | |
142 int BrowserAccessibilityManager::SetMembers(BrowserAccessibility* browser_acc, | |
143 HWND parent_hwnd, RenderWidgetHost* render_widget_host) { | |
144 // Set HWND and RenderWidgetHost connected to |browser_acc|. | |
145 instance_map_[instance_id_] = | |
146 new UniqueMembers(parent_hwnd, render_widget_host); | |
147 | |
148 render_process_host_map_[render_widget_host->process()] = browser_acc; | |
149 return instance_id_++; | |
150 } | 142 } |
151 | 143 |
152 void BrowserAccessibilityManager::Observe(NotificationType type, | 144 void BrowserAccessibilityManager::Observe(NotificationType type, |
153 const NotificationSource& source, | 145 const NotificationSource& source, |
154 const NotificationDetails& details) { | 146 const NotificationDetails& details) { |
155 DCHECK(type == NotificationType::RENDERER_PROCESS_TERMINATED); | 147 DCHECK(type == NotificationType::RENDERER_PROCESS_TERMINATED); |
156 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr(); | 148 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr(); |
157 DCHECK(rph); | 149 DCHECK(rph); |
158 RenderProcessHostMap::iterator it = render_process_host_map_.find(rph); | |
159 | 150 |
160 if (it == render_process_host_map_.end() || !it->second) { | 151 RenderProcessHostMap::iterator it = |
161 // RenderProcessHost not associated with any BrowserAccessibility instance. | 152 render_process_host_map_.lower_bound(rph->pid()); |
162 return; | 153 |
| 154 RenderProcessHostMap::iterator end_of_matching_objects = |
| 155 render_process_host_map_.upper_bound(rph->pid()); |
| 156 |
| 157 for (; it != end_of_matching_objects; ++it) { |
| 158 if (it->second) { |
| 159 // Set all matching BrowserAccessibility instances to inactive state. |
| 160 // TODO(klink): Do more active memory cleanup as well. |
| 161 it->second->set_instance_active(false); |
| 162 } |
163 } | 163 } |
164 | |
165 // Set BrowserAccessibility instance to inactive state. | |
166 it->second->set_instance_active(false); | |
167 | |
168 // Delete entry also from InstanceMap. | |
169 InstanceMap::iterator it2 = instance_map_.find(it->second->instance_id()); | |
170 | |
171 if (it2 != instance_map_.end()) | |
172 instance_map_.erase(it2); | |
173 | |
174 // Only delete the first entry once it is no longer in use. | |
175 render_process_host_map_.erase(it); | |
176 } | 164 } |
OLD | NEW |