| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/accessibility/browser_accessibility_manager_win.h" | 5 #include "chrome/browser/accessibility/browser_accessibility_manager_win.h" |
| 6 | 6 |
| 7 #include "chrome/browser/accessibility/browser_accessibility_win.h" | 7 #include "chrome/browser/accessibility/browser_accessibility_win.h" |
| 8 #include "chrome/browser/renderer_host/render_process_host.h" | |
| 9 #include "chrome/browser/renderer_host/render_view_host.h" | |
| 10 #include "chrome/common/render_messages.h" | |
| 11 #include "chrome/common/render_messages_params.h" | |
| 12 | 8 |
| 13 using webkit_glue::WebAccessibility; | 9 using webkit_glue::WebAccessibility; |
| 14 | 10 |
| 15 // static | 11 // static |
| 16 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( | 12 BrowserAccessibilityManager* BrowserAccessibilityManager::Create( |
| 17 gfx::NativeWindow parent_window, | 13 gfx::NativeView parent_view, |
| 18 const webkit_glue::WebAccessibility& src, | 14 const WebAccessibility& src, |
| 19 BrowserAccessibilityDelegate* delegate) { | 15 BrowserAccessibilityDelegate* delegate, |
| 16 BrowserAccessibilityFactory* factory) { |
| 20 return new BrowserAccessibilityManagerWin( | 17 return new BrowserAccessibilityManagerWin( |
| 21 parent_window, src, delegate, new BrowserAccessibilityWinFactory()); | 18 parent_view, |
| 19 src, |
| 20 delegate, |
| 21 factory); |
| 22 } | 22 } |
| 23 | 23 |
| 24 // Factory method to create an instance of BrowserAccessibility | 24 // Defining this here instead of in the base implementation file to address link |
| 25 BrowserAccessibilityWin* BrowserAccessibilityWinFactory::Create() { | 25 // errors on the linux shared library build. (linux shlib) |
| 26 CComObject<BrowserAccessibilityWin>* instance; | 26 BrowserAccessibility* BrowserAccessibilityFactory::Create() { |
| 27 HRESULT hr = CComObject<BrowserAccessibilityWin>::CreateInstance(&instance); | 27 return BrowserAccessibility::Create(); |
| 28 DCHECK(SUCCEEDED(hr)); | |
| 29 return instance->NewReference(); | |
| 30 } | 28 } |
| 31 | 29 |
| 32 // static | 30 BrowserAccessibilityManagerWin* |
| 33 // Start child IDs at -1 and decrement each time, because clients use | 31 BrowserAccessibilityManager::toBrowserAccessibilityManagerWin() { |
| 34 // child IDs of 1, 2, 3, ... to access the children of an object by | 32 return static_cast<BrowserAccessibilityManagerWin*>(this); |
| 35 // index, so we use negative IDs to clearly distinguish between indices | 33 } |
| 36 // and unique IDs. | |
| 37 LONG BrowserAccessibilityManagerWin::next_child_id_ = -1; | |
| 38 | 34 |
| 39 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( | 35 BrowserAccessibilityManagerWin::BrowserAccessibilityManagerWin( |
| 40 HWND parent_window, | 36 HWND parent_view, |
| 41 const webkit_glue::WebAccessibility& src, | 37 const WebAccessibility& src, |
| 42 BrowserAccessibilityDelegate* delegate, | 38 BrowserAccessibilityDelegate* delegate, |
| 43 BrowserAccessibilityWinFactory* factory) | 39 BrowserAccessibilityFactory* factory) |
| 44 : BrowserAccessibilityManager(parent_window), | 40 : BrowserAccessibilityManager(parent_view, src, delegate, factory) { |
| 45 delegate_(delegate), | |
| 46 factory_(factory), | |
| 47 focus_(NULL) { | |
| 48 HRESULT hr = ::CreateStdAccessibleObject( | 41 HRESULT hr = ::CreateStdAccessibleObject( |
| 49 parent_window, OBJID_WINDOW, IID_IAccessible, | 42 parent_view, OBJID_WINDOW, IID_IAccessible, |
| 50 reinterpret_cast<void **>(&window_iaccessible_)); | 43 reinterpret_cast<void **>(&window_iaccessible_)); |
| 51 DCHECK(SUCCEEDED(hr)); | 44 DCHECK(SUCCEEDED(hr)); |
| 52 root_ = CreateAccessibilityTree(NULL, GetNextChildID(), src, 0); | |
| 53 if (!focus_) | |
| 54 focus_ = root_; | |
| 55 } | 45 } |
| 56 | 46 |
| 57 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { | 47 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() { |
| 58 // Clients could still hold references to some nodes of the tree, so | |
| 59 // calling Inactivate will make sure that as many nodes as possible are | |
| 60 // released now, and remaining nodes are marked as inactive so that | |
| 61 // calls to any methods on them will return E_FAIL; | |
| 62 root_->InactivateTree(); | |
| 63 root_->Release(); | |
| 64 } | |
| 65 | |
| 66 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetRoot() { | |
| 67 return root_; | |
| 68 } | |
| 69 | |
| 70 void BrowserAccessibilityManagerWin::Remove(LONG child_id) { | |
| 71 child_id_map_.erase(child_id); | |
| 72 } | |
| 73 | |
| 74 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFromChildID( | |
| 75 LONG child_id) { | |
| 76 base::hash_map<LONG, BrowserAccessibilityWin*>::iterator iter = | |
| 77 child_id_map_.find(child_id); | |
| 78 if (iter != child_id_map_.end()) { | |
| 79 return iter->second; | |
| 80 } else { | |
| 81 return NULL; | |
| 82 } | |
| 83 } | 48 } |
| 84 | 49 |
| 85 IAccessible* BrowserAccessibilityManagerWin::GetParentWindowIAccessible() { | 50 IAccessible* BrowserAccessibilityManagerWin::GetParentWindowIAccessible() { |
| 86 return window_iaccessible_; | 51 return window_iaccessible_; |
| 87 } | 52 } |
| 88 | 53 |
| 89 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::GetFocus( | 54 void BrowserAccessibilityManagerWin::NotifyAccessibilityEvent( |
| 90 BrowserAccessibilityWin* root) { | 55 ViewHostMsg_AccessibilityNotification_Params::NotificationType n, |
| 91 if (focus_ && (!root || focus_->IsDescendantOf(root))) | 56 BrowserAccessibility* node) { |
| 92 return focus_; | 57 LONG event_id; |
| 93 | 58 switch (n) { |
| 94 return NULL; | 59 case ViewHostMsg_AccessibilityNotification_Params:: |
| 95 } | 60 NOTIFICATION_TYPE_CHECK_STATE_CHANGED: |
| 96 | 61 event_id = EVENT_OBJECT_STATECHANGE; |
| 97 void BrowserAccessibilityManagerWin::SetFocus( | 62 break; |
| 98 const BrowserAccessibilityWin& node) { | 63 case ViewHostMsg_AccessibilityNotification_Params:: |
| 99 if (delegate_) | 64 NOTIFICATION_TYPE_CHILDREN_CHANGED: |
| 100 delegate_->SetAccessibilityFocus(node.renderer_id()); | 65 event_id = EVENT_OBJECT_REORDER; |
| 101 } | 66 break; |
| 102 | 67 case ViewHostMsg_AccessibilityNotification_Params:: |
| 103 void BrowserAccessibilityManagerWin::DoDefaultAction( | 68 NOTIFICATION_TYPE_FOCUS_CHANGED: |
| 104 const BrowserAccessibilityWin& node) { | 69 event_id = EVENT_OBJECT_FOCUS; |
| 105 if (delegate_) | 70 break; |
| 106 delegate_->AccessibilityDoDefaultAction(node.renderer_id()); | 71 case ViewHostMsg_AccessibilityNotification_Params:: |
| 107 } | 72 NOTIFICATION_TYPE_LOAD_COMPLETE: |
| 108 | 73 event_id = IA2_EVENT_DOCUMENT_LOAD_COMPLETE; |
| 109 bool BrowserAccessibilityManagerWin::CanModifyTreeInPlace( | 74 break; |
| 110 BrowserAccessibilityWin* current_root, | 75 case ViewHostMsg_AccessibilityNotification_Params:: |
| 111 const webkit_glue::WebAccessibility& new_root) { | 76 NOTIFICATION_TYPE_VALUE_CHANGED: |
| 112 if (current_root->renderer_id() != new_root.id) | 77 event_id = EVENT_OBJECT_VALUECHANGE; |
| 113 return false; | 78 break; |
| 114 if (current_root->GetChildCount() != new_root.children.size()) | 79 case ViewHostMsg_AccessibilityNotification_Params:: |
| 115 return false; | 80 NOTIFICATION_TYPE_SELECTED_TEXT_CHANGED: |
| 116 for (unsigned int i = 0; i < current_root->GetChildCount(); i++) { | 81 event_id = IA2_EVENT_TEXT_CARET_MOVED; |
| 117 if (!CanModifyTreeInPlace(current_root->GetChild(i), | |
| 118 new_root.children[i])) { | |
| 119 return false; | |
| 120 } | |
| 121 } | |
| 122 return true; | |
| 123 } | |
| 124 | |
| 125 void BrowserAccessibilityManagerWin::ModifyTreeInPlace( | |
| 126 BrowserAccessibilityWin* current_root, | |
| 127 const webkit_glue::WebAccessibility& new_root) { | |
| 128 DCHECK_EQ(current_root->renderer_id(), new_root.id); | |
| 129 DCHECK_EQ(current_root->GetChildCount(), new_root.children.size()); | |
| 130 for (unsigned int i = 0; i < current_root->GetChildCount(); i++) | |
| 131 ModifyTreeInPlace(current_root->GetChild(i), new_root.children[i]); | |
| 132 current_root->Initialize( | |
| 133 this, | |
| 134 current_root->GetParent(), | |
| 135 current_root->child_id(), | |
| 136 current_root->index_in_parent(), | |
| 137 new_root); | |
| 138 } | |
| 139 | |
| 140 | |
| 141 BrowserAccessibilityWin* BrowserAccessibilityManagerWin::UpdateTree( | |
| 142 const webkit_glue::WebAccessibility& acc_obj) { | |
| 143 base::hash_map<int, LONG>::iterator iter = | |
| 144 renderer_id_to_child_id_map_.find(acc_obj.id); | |
| 145 if (iter == renderer_id_to_child_id_map_.end()) | |
| 146 return NULL; | |
| 147 | |
| 148 LONG child_id = iter->second; | |
| 149 BrowserAccessibilityWin* old_browser_acc = GetFromChildID(child_id); | |
| 150 if (!old_browser_acc) | |
| 151 return NULL; | |
| 152 | |
| 153 if (CanModifyTreeInPlace(old_browser_acc, acc_obj)) { | |
| 154 ModifyTreeInPlace(old_browser_acc, acc_obj); | |
| 155 return old_browser_acc; | |
| 156 } | 82 } |
| 157 | 83 |
| 158 BrowserAccessibilityWin* new_browser_acc = CreateAccessibilityTree( | 84 NotifyWinEvent(event_id, GetParentView(), OBJID_CLIENT, node->child_id()); |
| 159 old_browser_acc->GetParent(), | |
| 160 child_id, | |
| 161 acc_obj, | |
| 162 old_browser_acc->index_in_parent()); | |
| 163 | |
| 164 if (old_browser_acc->GetParent()) { | |
| 165 old_browser_acc->GetParent()->ReplaceChild( | |
| 166 old_browser_acc, | |
| 167 new_browser_acc); | |
| 168 } else { | |
| 169 DCHECK_EQ(old_browser_acc, root_); | |
| 170 root_ = new_browser_acc; | |
| 171 } | |
| 172 old_browser_acc->InactivateTree(); | |
| 173 old_browser_acc->Release(); | |
| 174 child_id_map_[child_id] = new_browser_acc; | |
| 175 | |
| 176 return new_browser_acc; | |
| 177 } | 85 } |
| 178 | |
| 179 void BrowserAccessibilityManagerWin::GotFocus() { | |
| 180 // TODO(ctguil): Remove when tree update logic handles focus changes. | |
| 181 if (!focus_) | |
| 182 return; | |
| 183 | |
| 184 NotifyWinEvent( | |
| 185 EVENT_OBJECT_FOCUS, | |
| 186 GetParentWindow(), | |
| 187 OBJID_CLIENT, | |
| 188 focus_->child_id()); | |
| 189 } | |
| 190 | |
| 191 IAccessible* BrowserAccessibilityManagerWin::GetRootAccessible() { | |
| 192 return root_; | |
| 193 } | |
| 194 | |
| 195 void BrowserAccessibilityManagerWin::OnAccessibilityObjectStateChange( | |
| 196 const webkit_glue::WebAccessibility& acc_obj) { | |
| 197 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
| 198 if (!new_browser_acc) | |
| 199 return; | |
| 200 | |
| 201 LONG child_id = new_browser_acc->child_id(); | |
| 202 NotifyWinEvent( | |
| 203 EVENT_OBJECT_STATECHANGE, GetParentWindow(), OBJID_CLIENT, child_id); | |
| 204 } | |
| 205 | |
| 206 void BrowserAccessibilityManagerWin::OnAccessibilityObjectChildrenChange( | |
| 207 const webkit_glue::WebAccessibility& acc_obj) { | |
| 208 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
| 209 if (!new_browser_acc) | |
| 210 return; | |
| 211 | |
| 212 LONG child_id; | |
| 213 if (root_ != new_browser_acc) { | |
| 214 child_id = new_browser_acc->GetParent()->child_id(); | |
| 215 } else { | |
| 216 child_id = CHILDID_SELF; | |
| 217 } | |
| 218 | |
| 219 NotifyWinEvent( | |
| 220 EVENT_OBJECT_REORDER, GetParentWindow(), OBJID_CLIENT, child_id); | |
| 221 } | |
| 222 | |
| 223 void BrowserAccessibilityManagerWin::OnAccessibilityObjectFocusChange( | |
| 224 const webkit_glue::WebAccessibility& acc_obj) { | |
| 225 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
| 226 if (!new_browser_acc) | |
| 227 return; | |
| 228 | |
| 229 focus_ = new_browser_acc; | |
| 230 LONG child_id = new_browser_acc->child_id(); | |
| 231 if (delegate_ && delegate_->HasFocus()) | |
| 232 GotFocus(); | |
| 233 } | |
| 234 | |
| 235 void BrowserAccessibilityManagerWin::OnAccessibilityObjectLoadComplete( | |
| 236 const webkit_glue::WebAccessibility& acc_obj) { | |
| 237 root_->InactivateTree(); | |
| 238 root_->Release(); | |
| 239 focus_ = NULL; | |
| 240 | |
| 241 root_ = CreateAccessibilityTree(NULL, GetNextChildID(), acc_obj, 0); | |
| 242 if (!focus_) | |
| 243 focus_ = root_; | |
| 244 | |
| 245 NotifyWinEvent( | |
| 246 IA2_EVENT_DOCUMENT_LOAD_COMPLETE, | |
| 247 GetParentWindow(), | |
| 248 OBJID_CLIENT, | |
| 249 root_->child_id()); | |
| 250 if (delegate_ && delegate_->HasFocus()) | |
| 251 GotFocus(); | |
| 252 } | |
| 253 | |
| 254 void BrowserAccessibilityManagerWin::OnAccessibilityObjectValueChange( | |
| 255 const webkit_glue::WebAccessibility& acc_obj) { | |
| 256 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
| 257 if (!new_browser_acc) | |
| 258 return; | |
| 259 | |
| 260 LONG child_id = new_browser_acc->child_id(); | |
| 261 NotifyWinEvent( | |
| 262 EVENT_OBJECT_VALUECHANGE, GetParentWindow(), OBJID_CLIENT, child_id); | |
| 263 } | |
| 264 | |
| 265 void BrowserAccessibilityManagerWin::OnAccessibilityObjectTextChange( | |
| 266 const webkit_glue::WebAccessibility& acc_obj) { | |
| 267 BrowserAccessibilityWin* new_browser_acc = UpdateTree(acc_obj); | |
| 268 if (!new_browser_acc) | |
| 269 return; | |
| 270 | |
| 271 LONG child_id = new_browser_acc->child_id(); | |
| 272 NotifyWinEvent( | |
| 273 IA2_EVENT_TEXT_CARET_MOVED, GetParentWindow(), OBJID_CLIENT, child_id); | |
| 274 } | |
| 275 | |
| 276 LONG BrowserAccessibilityManagerWin::GetNextChildID() { | |
| 277 // Get the next child ID, and wrap around when we get near the end | |
| 278 // of a 32-bit integer range. It's okay to wrap around; we just want | |
| 279 // to avoid it as long as possible because clients may cache the ID of | |
| 280 // an object for a while to determine if they've seen it before. | |
| 281 next_child_id_--; | |
| 282 if (next_child_id_ == -2000000000) | |
| 283 next_child_id_ = -1; | |
| 284 | |
| 285 return next_child_id_; | |
| 286 } | |
| 287 | |
| 288 BrowserAccessibilityWin* | |
| 289 BrowserAccessibilityManagerWin::CreateAccessibilityTree( | |
| 290 BrowserAccessibilityWin* parent, | |
| 291 int child_id, | |
| 292 const webkit_glue::WebAccessibility& src, | |
| 293 int index_in_parent) { | |
| 294 BrowserAccessibilityWin* instance = factory_->Create(); | |
| 295 | |
| 296 instance->Initialize(this, parent, child_id, index_in_parent, src); | |
| 297 child_id_map_[child_id] = instance; | |
| 298 renderer_id_to_child_id_map_[src.id] = child_id; | |
| 299 if ((src.state >> WebAccessibility::STATE_FOCUSED) & 1) | |
| 300 focus_ = instance; | |
| 301 for (int i = 0; i < static_cast<int>(src.children.size()); ++i) { | |
| 302 BrowserAccessibilityWin* child = CreateAccessibilityTree( | |
| 303 instance, GetNextChildID(), src.children[i], i); | |
| 304 instance->AddChild(child); | |
| 305 } | |
| 306 | |
| 307 return instance; | |
| 308 } | |
| OLD | NEW |