| 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 "views/accessibility/view_accessibility.h" | 5 #include "views/accessibility/view_accessibility.h" |
| 6 | 6 |
| 7 #include "views/accessibility/view_accessibility_wrapper.h" | 7 #include "views/accessibility/view_accessibility_wrapper.h" |
| 8 #include "views/widget/widget.h" | 8 #include "views/widget/widget.h" |
| 9 | 9 |
| 10 const wchar_t kViewsUninitializeAccessibilityInstance[] = |
| 11 L"Views_Uninitialize_AccessibilityInstance"; |
| 12 |
| 13 const wchar_t kViewsNativeHostPropForAccessibility[] = |
| 14 L"Views_NativeViewHostHWNDForAccessibility"; |
| 15 |
| 16 |
| 10 HRESULT ViewAccessibility::Initialize(views::View* view) { | 17 HRESULT ViewAccessibility::Initialize(views::View* view) { |
| 11 if (!view) { | 18 if (!view) { |
| 12 return E_INVALIDARG; | 19 return E_INVALIDARG; |
| 13 } | 20 } |
| 14 | 21 |
| 15 view_ = view; | 22 view_ = view; |
| 16 return S_OK; | 23 return S_OK; |
| 17 } | 24 } |
| 18 | 25 |
| 19 // TODO(klink): Handle case where child View is not contained by parent. | 26 // TODO(klink): Handle case where child View is not contained by parent. |
| 20 STDMETHODIMP ViewAccessibility::accHitTest(LONG x_left, LONG y_top, | 27 STDMETHODIMP ViewAccessibility::accHitTest(LONG x_left, LONG y_top, |
| 21 VARIANT* child) { | 28 VARIANT* child) { |
| 22 if (!child) { | 29 if (!child) { |
| 23 return E_INVALIDARG; | 30 return E_INVALIDARG; |
| 24 } | 31 } |
| 25 | 32 |
| 33 if (!view_) { |
| 34 return E_FAIL; |
| 35 } |
| 36 |
| 26 gfx::Point pt(x_left, y_top); | 37 gfx::Point pt(x_left, y_top); |
| 27 views::View::ConvertPointToView(NULL, view_, &pt); | 38 views::View::ConvertPointToView(NULL, view_, &pt); |
| 28 | 39 |
| 29 if (!view_->HitTest(pt)) { | 40 if (!view_->HitTest(pt)) { |
| 30 // If containing parent is not hit, return with failure. | 41 // If containing parent is not hit, return with failure. |
| 31 child->vt = VT_EMPTY; | 42 child->vt = VT_EMPTY; |
| 32 return S_FALSE; | 43 return S_FALSE; |
| 33 } | 44 } |
| 34 | 45 |
| 35 int child_count = view_->GetChildViewCount(); | 46 int child_count = view_->GetChildViewCount(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 return S_OK; | 86 return S_OK; |
| 76 } | 87 } |
| 77 | 88 |
| 78 STDMETHODIMP ViewAccessibility::accLocation(LONG* x_left, LONG* y_top, | 89 STDMETHODIMP ViewAccessibility::accLocation(LONG* x_left, LONG* y_top, |
| 79 LONG* width, LONG* height, | 90 LONG* width, LONG* height, |
| 80 VARIANT var_id) { | 91 VARIANT var_id) { |
| 81 if (var_id.vt != VT_I4 || !x_left || !y_top || !width || !height) { | 92 if (var_id.vt != VT_I4 || !x_left || !y_top || !width || !height) { |
| 82 return E_INVALIDARG; | 93 return E_INVALIDARG; |
| 83 } | 94 } |
| 84 | 95 |
| 96 if (!view_) { |
| 97 return E_FAIL; |
| 98 } |
| 99 |
| 85 gfx::Rect view_bounds; | 100 gfx::Rect view_bounds; |
| 86 // Retrieving the parent View to be used for converting from view-to-screen | 101 // Retrieving the parent View to be used for converting from view-to-screen |
| 87 // coordinates. | 102 // coordinates. |
| 88 views::View* parent = view_->GetParent(); | 103 views::View* parent = view_->GetParent(); |
| 89 | 104 |
| 90 if (parent == NULL) { | 105 if (parent == NULL) { |
| 91 // If no parent, remain within the same View. | 106 // If no parent, remain within the same View. |
| 92 parent = view_; | 107 parent = view_; |
| 93 } | 108 } |
| 94 | 109 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 119 } | 134 } |
| 120 return S_OK; | 135 return S_OK; |
| 121 } | 136 } |
| 122 | 137 |
| 123 STDMETHODIMP ViewAccessibility::accNavigate(LONG nav_dir, VARIANT start, | 138 STDMETHODIMP ViewAccessibility::accNavigate(LONG nav_dir, VARIANT start, |
| 124 VARIANT* end) { | 139 VARIANT* end) { |
| 125 if (start.vt != VT_I4 || !end) { | 140 if (start.vt != VT_I4 || !end) { |
| 126 return E_INVALIDARG; | 141 return E_INVALIDARG; |
| 127 } | 142 } |
| 128 | 143 |
| 144 if (!view_) { |
| 145 return E_FAIL; |
| 146 } |
| 147 |
| 129 switch (nav_dir) { | 148 switch (nav_dir) { |
| 130 case NAVDIR_FIRSTCHILD: | 149 case NAVDIR_FIRSTCHILD: |
| 131 case NAVDIR_LASTCHILD: { | 150 case NAVDIR_LASTCHILD: { |
| 132 if (start.lVal != CHILDID_SELF) { | 151 if (start.lVal != CHILDID_SELF) { |
| 133 // Start of navigation must be on the View itself. | 152 // Start of navigation must be on the View itself. |
| 134 return E_INVALIDARG; | 153 return E_INVALIDARG; |
| 135 } else if (view_->GetChildViewCount() == 0) { | 154 } else if (view_->GetChildViewCount() == 0) { |
| 136 // No children found. | 155 // No children found. |
| 137 return S_FALSE; | 156 return S_FALSE; |
| 138 } | 157 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 views::View* parent = view_->GetParent(); | 193 views::View* parent = view_->GetParent(); |
| 175 if (!parent) { | 194 if (!parent) { |
| 176 return E_FAIL; | 195 return E_FAIL; |
| 177 } | 196 } |
| 178 | 197 |
| 179 if (start.lVal == CHILDID_SELF) { | 198 if (start.lVal == CHILDID_SELF) { |
| 180 int view_index = parent->GetChildIndex(view_); | 199 int view_index = parent->GetChildIndex(view_); |
| 181 // Check navigation bounds, adjusting for View child indexing (MSAA | 200 // Check navigation bounds, adjusting for View child indexing (MSAA |
| 182 // child indexing starts with 1, whereas View indexing starts with 0). | 201 // child indexing starts with 1, whereas View indexing starts with 0). |
| 183 if (!IsValidNav(nav_dir, view_index, -1, | 202 if (!IsValidNav(nav_dir, view_index, -1, |
| 184 parent->GetChildViewCount())) { | 203 parent->GetChildViewCount() - 1)) { |
| 185 // Navigation attempted to go out-of-bounds. | 204 // Navigation attempted to go out-of-bounds. |
| 186 end->vt = VT_EMPTY; | 205 end->vt = VT_EMPTY; |
| 187 return S_FALSE; | 206 return S_FALSE; |
| 188 } else { | 207 } else { |
| 189 if (IsNavDirNext(nav_dir)) { | 208 if (IsNavDirNext(nav_dir)) { |
| 190 view_index += 1; | 209 view_index += 1; |
| 191 } else { | 210 } else { |
| 192 view_index -=1; | 211 view_index -=1; |
| 193 } | 212 } |
| 194 } | 213 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 IDispatch** disp_child) { | 273 IDispatch** disp_child) { |
| 255 if (var_child.vt != VT_I4 || !disp_child) { | 274 if (var_child.vt != VT_I4 || !disp_child) { |
| 256 return E_INVALIDARG; | 275 return E_INVALIDARG; |
| 257 } | 276 } |
| 258 | 277 |
| 259 // If var_child is the parent, remain with the same IDispatch. | 278 // If var_child is the parent, remain with the same IDispatch. |
| 260 if (var_child.lVal == CHILDID_SELF) { | 279 if (var_child.lVal == CHILDID_SELF) { |
| 261 return S_OK; | 280 return S_OK; |
| 262 } | 281 } |
| 263 | 282 |
| 283 if (!view_) { |
| 284 return E_FAIL; |
| 285 } |
| 286 |
| 264 views::View* child_view = NULL; | 287 views::View* child_view = NULL; |
| 265 bool get_iaccessible = false; | 288 bool get_iaccessible = false; |
| 266 | 289 |
| 267 // Check to see if child is out-of-bounds. | 290 // Check to see if child is out-of-bounds. |
| 268 if (IsValidChild((var_child.lVal - 1), view_)) { | 291 if (IsValidChild((var_child.lVal - 1), view_)) { |
| 269 child_view = view_->GetChildViewAt(var_child.lVal - 1); | 292 child_view = view_->GetChildViewAt(var_child.lVal - 1); |
| 270 } else { | 293 } else { |
| 271 // Child is located elsewhere in the hierarchy, get ID and adjust for MSAA. | 294 // Child is located elsewhere in the hierarchy, get ID and adjust for MSAA. |
| 272 child_view = view_->GetViewByID(static_cast<int>(var_child.lVal)); | 295 child_view = view_->GetViewByID(static_cast<int>(var_child.lVal)); |
| 273 get_iaccessible = true; | 296 get_iaccessible = true; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 286 GetInstance(IID_IAccessible, | 309 GetInstance(IID_IAccessible, |
| 287 reinterpret_cast<void**>(disp_child)) == S_OK) { | 310 reinterpret_cast<void**>(disp_child)) == S_OK) { |
| 288 // Increment the reference count for the retrieved interface. | 311 // Increment the reference count for the retrieved interface. |
| 289 (*disp_child)->AddRef(); | 312 (*disp_child)->AddRef(); |
| 290 return S_OK; | 313 return S_OK; |
| 291 } else { | 314 } else { |
| 292 // No interface, return failure. | 315 // No interface, return failure. |
| 293 return E_NOINTERFACE; | 316 return E_NOINTERFACE; |
| 294 } | 317 } |
| 295 } else { | 318 } else { |
| 319 if (child_view->GetClassName() == views::NativeViewHost::kViewClassName) { |
| 320 views::NativeViewHost* native_host = |
| 321 static_cast<views::NativeViewHost*>(child_view); |
| 322 if (GetNativeIAccessibleInterface(native_host, disp_child) == S_OK) |
| 323 return S_OK; |
| 324 } |
| 296 // When at a leaf, children are handled by the parent object. | 325 // When at a leaf, children are handled by the parent object. |
| 297 *disp_child = NULL; | 326 *disp_child = NULL; |
| 298 return S_FALSE; | 327 return S_FALSE; |
| 299 } | 328 } |
| 300 } | 329 } |
| 301 | 330 |
| 302 STDMETHODIMP ViewAccessibility::get_accChildCount(LONG* child_count) { | 331 STDMETHODIMP ViewAccessibility::get_accChildCount(LONG* child_count) { |
| 303 if (!child_count || !view_) { | 332 if (!child_count || !view_) { |
| 304 return E_INVALIDARG; | 333 return E_INVALIDARG; |
| 305 } | 334 } |
| 306 | 335 |
| 336 if (!view_) { |
| 337 return E_FAIL; |
| 338 } |
| 339 |
| 307 *child_count = view_->GetChildViewCount(); | 340 *child_count = view_->GetChildViewCount(); |
| 308 return S_OK; | 341 return S_OK; |
| 309 } | 342 } |
| 310 | 343 |
| 311 STDMETHODIMP ViewAccessibility::get_accDefaultAction(VARIANT var_id, | 344 STDMETHODIMP ViewAccessibility::get_accDefaultAction(VARIANT var_id, |
| 312 BSTR* def_action) { | 345 BSTR* def_action) { |
| 313 if (var_id.vt != VT_I4 || !def_action) { | 346 if (var_id.vt != VT_I4 || !def_action) { |
| 314 return E_INVALIDARG; | 347 return E_INVALIDARG; |
| 315 } | 348 } |
| 316 | 349 |
| 350 if (!view_) { |
| 351 return E_FAIL; |
| 352 } |
| 353 |
| 317 std::wstring temp_action; | 354 std::wstring temp_action; |
| 318 | 355 |
| 319 if (var_id.lVal == CHILDID_SELF) { | 356 if (var_id.lVal == CHILDID_SELF) { |
| 320 view_->GetAccessibleDefaultAction(&temp_action); | 357 view_->GetAccessibleDefaultAction(&temp_action); |
| 321 } else { | 358 } else { |
| 322 if (!IsValidChild((var_id.lVal - 1), view_)) { | 359 if (!IsValidChild((var_id.lVal - 1), view_)) { |
| 323 return E_INVALIDARG; | 360 return E_INVALIDARG; |
| 324 } | 361 } |
| 325 view_->GetChildViewAt(var_id.lVal - 1)-> | 362 view_->GetChildViewAt(var_id.lVal - 1)-> |
| 326 GetAccessibleDefaultAction(&temp_action); | 363 GetAccessibleDefaultAction(&temp_action); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 356 } | 393 } |
| 357 | 394 |
| 358 return S_OK; | 395 return S_OK; |
| 359 } | 396 } |
| 360 | 397 |
| 361 STDMETHODIMP ViewAccessibility::get_accFocus(VARIANT* focus_child) { | 398 STDMETHODIMP ViewAccessibility::get_accFocus(VARIANT* focus_child) { |
| 362 if (!focus_child) { | 399 if (!focus_child) { |
| 363 return E_INVALIDARG; | 400 return E_INVALIDARG; |
| 364 } | 401 } |
| 365 | 402 |
| 403 if (!view_) { |
| 404 return E_FAIL; |
| 405 } |
| 406 |
| 366 if (view_->GetChildViewCount() == 0 && view_->HasFocus()) { | 407 if (view_->GetChildViewCount() == 0 && view_->HasFocus()) { |
| 367 // Parent view has focus. | 408 // Parent view has focus. |
| 368 focus_child->vt = VT_I4; | 409 focus_child->vt = VT_I4; |
| 369 focus_child->lVal = CHILDID_SELF; | 410 focus_child->lVal = CHILDID_SELF; |
| 370 } else { | 411 } else { |
| 371 bool has_focus = false; | 412 bool has_focus = false; |
| 372 int child_count = view_->GetChildViewCount(); | 413 int child_count = view_->GetChildViewCount(); |
| 373 // Search for child view with focus. | 414 // Search for child view with focus. |
| 374 for (int child_id = 0; child_id < child_count; ++child_id) { | 415 for (int child_id = 0; child_id < child_count; ++child_id) { |
| 375 if (view_->GetChildViewAt(child_id)->HasFocus()) { | 416 if (view_->GetChildViewAt(child_id)->HasFocus()) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 394 | 435 |
| 395 return S_OK; | 436 return S_OK; |
| 396 } | 437 } |
| 397 | 438 |
| 398 STDMETHODIMP ViewAccessibility::get_accKeyboardShortcut(VARIANT var_id, | 439 STDMETHODIMP ViewAccessibility::get_accKeyboardShortcut(VARIANT var_id, |
| 399 BSTR* acc_key) { | 440 BSTR* acc_key) { |
| 400 if (var_id.vt != VT_I4 || !acc_key) { | 441 if (var_id.vt != VT_I4 || !acc_key) { |
| 401 return E_INVALIDARG; | 442 return E_INVALIDARG; |
| 402 } | 443 } |
| 403 | 444 |
| 445 if (!view_) { |
| 446 return E_FAIL; |
| 447 } |
| 448 |
| 404 std::wstring temp_key; | 449 std::wstring temp_key; |
| 405 | 450 |
| 406 if (var_id.lVal == CHILDID_SELF) { | 451 if (var_id.lVal == CHILDID_SELF) { |
| 407 view_->GetAccessibleKeyboardShortcut(&temp_key); | 452 view_->GetAccessibleKeyboardShortcut(&temp_key); |
| 408 } else { | 453 } else { |
| 409 if (!IsValidChild((var_id.lVal - 1), view_)) { | 454 if (!IsValidChild((var_id.lVal - 1), view_)) { |
| 410 return E_INVALIDARG; | 455 return E_INVALIDARG; |
| 411 } | 456 } |
| 412 view_->GetChildViewAt(var_id.lVal - 1)-> | 457 view_->GetChildViewAt(var_id.lVal - 1)-> |
| 413 GetAccessibleKeyboardShortcut(&temp_key); | 458 GetAccessibleKeyboardShortcut(&temp_key); |
| 414 } | 459 } |
| 415 if (!temp_key.empty()) { | 460 if (!temp_key.empty()) { |
| 416 *acc_key = SysAllocString(temp_key.c_str()); | 461 *acc_key = SysAllocString(temp_key.c_str()); |
| 417 } else { | 462 } else { |
| 418 return S_FALSE; | 463 return S_FALSE; |
| 419 } | 464 } |
| 420 | 465 |
| 421 return S_OK; | 466 return S_OK; |
| 422 } | 467 } |
| 423 | 468 |
| 424 STDMETHODIMP ViewAccessibility::get_accName(VARIANT var_id, BSTR* name) { | 469 STDMETHODIMP ViewAccessibility::get_accName(VARIANT var_id, BSTR* name) { |
| 425 if (var_id.vt != VT_I4 || !name) { | 470 if (var_id.vt != VT_I4 || !name) { |
| 426 return E_INVALIDARG; | 471 return E_INVALIDARG; |
| 427 } | 472 } |
| 428 | 473 |
| 474 if (!view_) { |
| 475 return E_FAIL; |
| 476 } |
| 477 |
| 429 std::wstring temp_name; | 478 std::wstring temp_name; |
| 430 | 479 |
| 431 if (var_id.lVal == CHILDID_SELF) { | 480 if (var_id.lVal == CHILDID_SELF) { |
| 432 // Retrieve the parent view's name. | 481 // Retrieve the parent view's name. |
| 433 view_->GetAccessibleName(&temp_name); | 482 view_->GetAccessibleName(&temp_name); |
| 434 } else { | 483 } else { |
| 435 if (!IsValidChild((var_id.lVal - 1), view_)) { | 484 if (!IsValidChild((var_id.lVal - 1), view_)) { |
| 436 return E_INVALIDARG; | 485 return E_INVALIDARG; |
| 437 } | 486 } |
| 438 // Retrieve the child view's name. | 487 // Retrieve the child view's name. |
| 439 view_->GetChildViewAt(var_id.lVal - 1)->GetAccessibleName(&temp_name); | 488 view_->GetChildViewAt(var_id.lVal - 1)->GetAccessibleName(&temp_name); |
| 440 } | 489 } |
| 441 if (!temp_name.empty()) { | 490 if (!temp_name.empty()) { |
| 442 // Return name retrieved. | 491 // Return name retrieved. |
| 443 *name = SysAllocString(temp_name.c_str()); | 492 *name = SysAllocString(temp_name.c_str()); |
| 444 } else { | 493 } else { |
| 445 // If view has no name, return S_FALSE. | 494 // If view has no name, return S_FALSE. |
| 446 return S_FALSE; | 495 return S_FALSE; |
| 447 } | 496 } |
| 448 | 497 |
| 449 return S_OK; | 498 return S_OK; |
| 450 } | 499 } |
| 451 | 500 |
| 452 STDMETHODIMP ViewAccessibility::get_accParent(IDispatch** disp_parent) { | 501 STDMETHODIMP ViewAccessibility::get_accParent(IDispatch** disp_parent) { |
| 453 if (!disp_parent) { | 502 if (!disp_parent) { |
| 454 return E_INVALIDARG; | 503 return E_INVALIDARG; |
| 455 } | 504 } |
| 456 | 505 |
| 506 if (!view_) { |
| 507 return E_FAIL; |
| 508 } |
| 509 |
| 457 views::View* parent_view = view_->GetParent(); | 510 views::View* parent_view = view_->GetParent(); |
| 458 | 511 |
| 459 if (!parent_view) { | 512 if (!parent_view) { |
| 460 // This function can get called during teardown of WidetWin so we | 513 // This function can get called during teardown of WidetWin so we |
| 461 // should bail out if we fail to get the HWND. | 514 // should bail out if we fail to get the HWND. |
| 462 if (!view_->GetWidget() || !view_->GetWidget()->GetNativeView()) { | 515 if (!view_->GetWidget() || !view_->GetWidget()->GetNativeView()) { |
| 463 *disp_parent = NULL; | 516 *disp_parent = NULL; |
| 464 return S_FALSE; | 517 return S_FALSE; |
| 465 } | 518 } |
| 466 | 519 |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 } | 751 } |
| 699 return E_NOTIMPL; | 752 return E_NOTIMPL; |
| 700 } | 753 } |
| 701 | 754 |
| 702 STDMETHODIMP ViewAccessibility::put_accName(VARIANT var_id, BSTR put_name) { | 755 STDMETHODIMP ViewAccessibility::put_accName(VARIANT var_id, BSTR put_name) { |
| 703 // Deprecated. | 756 // Deprecated. |
| 704 return E_NOTIMPL; | 757 return E_NOTIMPL; |
| 705 } | 758 } |
| 706 | 759 |
| 707 STDMETHODIMP ViewAccessibility::put_accValue(VARIANT var_id, BSTR put_val) { | 760 STDMETHODIMP ViewAccessibility::put_accValue(VARIANT var_id, BSTR put_val) { |
| 761 if (V_VT(&var_id) == VT_BSTR) { |
| 762 if (!lstrcmpi(var_id.bstrVal, kViewsUninitializeAccessibilityInstance)) { |
| 763 view_ = NULL; |
| 764 return S_OK; |
| 765 } |
| 766 } |
| 708 // Deprecated. | 767 // Deprecated. |
| 709 return E_NOTIMPL; | 768 return E_NOTIMPL; |
| 710 } | 769 } |
| 770 |
| 771 HRESULT ViewAccessibility::GetNativeIAccessibleInterface( |
| 772 views::NativeViewHost* native_host, IDispatch** disp_child) { |
| 773 if (!native_host || !disp_child) { |
| 774 return E_INVALIDARG; |
| 775 } |
| 776 |
| 777 HWND render_view_window = |
| 778 static_cast<HWND>(GetProp(native_host->native_view(), |
| 779 kViewsNativeHostPropForAccessibility)); |
| 780 |
| 781 if (IsWindow(render_view_window)) { |
| 782 LRESULT ret = SendMessage(render_view_window, WM_GETOBJECT, 0, |
| 783 OBJID_CLIENT); |
| 784 return ObjectFromLresult(ret, IID_IDispatch, 0, |
| 785 reinterpret_cast<void**>(disp_child)); |
| 786 } |
| 787 |
| 788 return E_FAIL; |
| 789 } |
| OLD | NEW |