| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "ui/accessibility/platform/ax_platform_node.h" | 5 #include "ui/accessibility/platform/ax_platform_node.h" |
| 6 | 6 |
| 7 #include <atlbase.h> | 7 #include <atlbase.h> |
| 8 #include <atlcom.h> | 8 #include <atlcom.h> |
| 9 #include <oleacc.h> | 9 #include <oleacc.h> |
| 10 | 10 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 | 40 |
| 41 void SetUp() override { | 41 void SetUp() override { |
| 42 win::CreateATLModuleIfNeeded(); | 42 win::CreateATLModuleIfNeeded(); |
| 43 } | 43 } |
| 44 | 44 |
| 45 // Initialize given an AXTreeUpdate. | 45 // Initialize given an AXTreeUpdate. |
| 46 void Init(const AXTreeUpdate& initial_state) { | 46 void Init(const AXTreeUpdate& initial_state) { |
| 47 tree_.reset(new AXTree(initial_state)); | 47 tree_.reset(new AXTree(initial_state)); |
| 48 } | 48 } |
| 49 | 49 |
| 50 // Convenience functions to initialize directly from a few AXNodeDatas. | 50 // Convenience functions to initialize directly from a few AXNodeData objects. |
| 51 void Init(const AXNodeData& node1) { | 51 void Init(const AXNodeData& node1) { |
| 52 AXTreeUpdate update; | 52 AXTreeUpdate update; |
| 53 update.root_id = node1.id; | 53 update.root_id = node1.id; |
| 54 update.nodes.push_back(node1); | 54 update.nodes.push_back(node1); |
| 55 Init(update); | 55 Init(update); |
| 56 } | 56 } |
| 57 | 57 |
| 58 void Init(const AXNodeData& node1, | 58 void Init(const AXNodeData& node1, |
| 59 const AXNodeData& node2) { | 59 const AXNodeData& node2) { |
| 60 AXTreeUpdate update; | 60 AXTreeUpdate update; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 76 } | 76 } |
| 77 | 77 |
| 78 protected: | 78 protected: |
| 79 AXNode* GetRootNode() { | 79 AXNode* GetRootNode() { |
| 80 return tree_->root(); | 80 return tree_->root(); |
| 81 } | 81 } |
| 82 | 82 |
| 83 ScopedComPtr<IAccessible> IAccessibleFromNode(AXNode* node) { | 83 ScopedComPtr<IAccessible> IAccessibleFromNode(AXNode* node) { |
| 84 TestAXNodeWrapper* wrapper = | 84 TestAXNodeWrapper* wrapper = |
| 85 TestAXNodeWrapper::GetOrCreate(tree_.get(), node); | 85 TestAXNodeWrapper::GetOrCreate(tree_.get(), node); |
| 86 if (!wrapper) |
| 87 return ScopedComPtr<IAccessible>(); |
| 86 AXPlatformNode* ax_platform_node = wrapper->ax_platform_node(); | 88 AXPlatformNode* ax_platform_node = wrapper->ax_platform_node(); |
| 87 IAccessible* iaccessible = ax_platform_node->GetNativeViewAccessible(); | 89 IAccessible* iaccessible = ax_platform_node->GetNativeViewAccessible(); |
| 88 iaccessible->AddRef(); | |
| 89 return ScopedComPtr<IAccessible>(iaccessible); | 90 return ScopedComPtr<IAccessible>(iaccessible); |
| 90 } | 91 } |
| 91 | 92 |
| 92 ScopedComPtr<IAccessible> GetRootIAccessible() { | 93 ScopedComPtr<IAccessible> GetRootIAccessible() { |
| 93 return IAccessibleFromNode(GetRootNode()); | 94 return IAccessibleFromNode(GetRootNode()); |
| 94 } | 95 } |
| 95 | 96 |
| 96 ScopedComPtr<IAccessible2> ToIAccessible2( | 97 ScopedComPtr<IAccessible2> ToIAccessible2( |
| 97 ScopedComPtr<IAccessible> accessible) { | 98 ScopedComPtr<IAccessible> accessible) { |
| 98 CHECK(accessible.Get()); | 99 CHECK(accessible); |
| 99 ScopedComPtr<IServiceProvider> service_provider; | 100 ScopedComPtr<IServiceProvider> service_provider; |
| 100 service_provider.QueryFrom(accessible.Get()); | 101 service_provider.QueryFrom(accessible.Get()); |
| 101 ScopedComPtr<IAccessible2> result; | 102 ScopedComPtr<IAccessible2> result; |
| 102 CHECK(SUCCEEDED(service_provider->QueryService(IID_IAccessible2, | 103 CHECK(SUCCEEDED(service_provider->QueryService(IID_IAccessible2, |
| 103 result.GetAddressOf()))); | 104 result.GetAddressOf()))); |
| 104 return result; | 105 return result; |
| 105 } | 106 } |
| 106 | 107 |
| 107 std::unique_ptr<AXTree> tree_; | 108 std::unique_ptr<AXTree> tree_; |
| 108 }; | 109 }; |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 LONG index; | 395 LONG index; |
| 395 EXPECT_EQ(E_FAIL, root_iaccessible2->get_indexInParent(&index)); | 396 EXPECT_EQ(E_FAIL, root_iaccessible2->get_indexInParent(&index)); |
| 396 | 397 |
| 397 EXPECT_EQ(S_OK, left_iaccessible2->get_indexInParent(&index)); | 398 EXPECT_EQ(S_OK, left_iaccessible2->get_indexInParent(&index)); |
| 398 EXPECT_EQ(0, index); | 399 EXPECT_EQ(0, index); |
| 399 | 400 |
| 400 EXPECT_EQ(S_OK, right_iaccessible2->get_indexInParent(&index)); | 401 EXPECT_EQ(S_OK, right_iaccessible2->get_indexInParent(&index)); |
| 401 EXPECT_EQ(1, index); | 402 EXPECT_EQ(1, index); |
| 402 } | 403 } |
| 403 | 404 |
| 405 TEST_F(AXPlatformNodeWinTest, TestAccNavigate) { |
| 406 AXNodeData root; |
| 407 root.id = 1; |
| 408 root.role = AX_ROLE_ROOT_WEB_AREA; |
| 409 |
| 410 AXNodeData child1; |
| 411 child1.id = 2; |
| 412 child1.role = AX_ROLE_STATIC_TEXT; |
| 413 root.child_ids.push_back(2); |
| 414 |
| 415 AXNodeData child2; |
| 416 child2.id = 3; |
| 417 child2.role = AX_ROLE_STATIC_TEXT; |
| 418 root.child_ids.push_back(3); |
| 419 |
| 420 Init(root, child1, child2); |
| 421 ScopedComPtr<IAccessible> ia_root(GetRootIAccessible()); |
| 422 ScopedComPtr<IDispatch> disp_root; |
| 423 ASSERT_HRESULT_SUCCEEDED(ia_root.CopyTo(disp_root.GetAddressOf())); |
| 424 ScopedVariant var_root(disp_root.Get()); |
| 425 ScopedComPtr<IAccessible> ia_child1( |
| 426 IAccessibleFromNode(GetRootNode()->children()[0])); |
| 427 ScopedComPtr<IDispatch> disp_child1; |
| 428 ASSERT_HRESULT_SUCCEEDED(ia_child1.CopyTo(disp_child1.GetAddressOf())); |
| 429 ScopedVariant var_child1(disp_child1.Get()); |
| 430 ScopedComPtr<IAccessible> ia_child2( |
| 431 IAccessibleFromNode(GetRootNode()->children()[1])); |
| 432 ScopedComPtr<IDispatch> disp_child2; |
| 433 ASSERT_HRESULT_SUCCEEDED(ia_child2.CopyTo(disp_child2.GetAddressOf())); |
| 434 ScopedVariant var_child2(disp_child2.Get()); |
| 435 ScopedVariant end; |
| 436 |
| 437 // Invalid arguments. |
| 438 EXPECT_EQ( |
| 439 E_INVALIDARG, |
| 440 ia_root->accNavigate(NAVDIR_NEXT, ScopedVariant::kEmptyVariant, nullptr)); |
| 441 EXPECT_EQ(E_INVALIDARG, |
| 442 ia_child1->accNavigate(NAVDIR_NEXT, ScopedVariant::kEmptyVariant, |
| 443 end.AsInput())); |
| 444 EXPECT_EQ(VT_EMPTY, end.type()); |
| 445 |
| 446 // Navigating to first/last child should only be from self. |
| 447 EXPECT_EQ(E_INVALIDARG, |
| 448 ia_root->accNavigate(NAVDIR_FIRSTCHILD, var_root, end.AsInput())); |
| 449 EXPECT_EQ(VT_EMPTY, end.type()); |
| 450 EXPECT_EQ(E_INVALIDARG, |
| 451 ia_root->accNavigate(NAVDIR_LASTCHILD, var_root, end.AsInput())); |
| 452 EXPECT_EQ(VT_EMPTY, end.type()); |
| 453 |
| 454 // Spatial directions are not supported. |
| 455 EXPECT_EQ(E_NOTIMPL, ia_child1->accNavigate(NAVDIR_UP, SELF, end.AsInput())); |
| 456 EXPECT_EQ(E_NOTIMPL, ia_root->accNavigate(NAVDIR_DOWN, SELF, end.AsInput())); |
| 457 EXPECT_EQ(E_NOTIMPL, |
| 458 ia_child1->accNavigate(NAVDIR_RIGHT, SELF, end.AsInput())); |
| 459 EXPECT_EQ(E_NOTIMPL, |
| 460 ia_child2->accNavigate(NAVDIR_LEFT, SELF, end.AsInput())); |
| 461 EXPECT_EQ(VT_EMPTY, end.type()); |
| 462 |
| 463 // Logical directions should be supported. |
| 464 EXPECT_EQ(S_OK, ia_root->accNavigate(NAVDIR_FIRSTCHILD, SELF, end.AsInput())); |
| 465 EXPECT_EQ(0, var_child1.Compare(end)); |
| 466 EXPECT_EQ(S_OK, ia_root->accNavigate(NAVDIR_LASTCHILD, SELF, end.AsInput())); |
| 467 EXPECT_EQ(0, var_child2.Compare(end)); |
| 468 |
| 469 EXPECT_EQ(S_OK, ia_child1->accNavigate(NAVDIR_NEXT, SELF, end.AsInput())); |
| 470 EXPECT_EQ(0, var_child2.Compare(end)); |
| 471 EXPECT_EQ(S_OK, ia_child2->accNavigate(NAVDIR_PREVIOUS, SELF, end.AsInput())); |
| 472 EXPECT_EQ(0, var_child1.Compare(end)); |
| 473 |
| 474 // Child indices can also be passed by variant. |
| 475 // Indices are one-based. |
| 476 EXPECT_EQ(S_OK, |
| 477 ia_root->accNavigate(NAVDIR_NEXT, ScopedVariant(1), end.AsInput())); |
| 478 EXPECT_EQ(0, var_child2.Compare(end)); |
| 479 EXPECT_EQ(S_OK, ia_root->accNavigate(NAVDIR_PREVIOUS, ScopedVariant(2), |
| 480 end.AsInput())); |
| 481 EXPECT_EQ(0, var_child1.Compare(end)); |
| 482 |
| 483 // Test out-of-bounds. |
| 484 EXPECT_EQ(S_FALSE, |
| 485 ia_child1->accNavigate(NAVDIR_PREVIOUS, SELF, end.AsInput())); |
| 486 EXPECT_EQ(VT_EMPTY, end.type()); |
| 487 EXPECT_EQ(S_FALSE, ia_child2->accNavigate(NAVDIR_NEXT, SELF, end.AsInput())); |
| 488 EXPECT_EQ(VT_EMPTY, end.type()); |
| 489 |
| 490 EXPECT_EQ(S_FALSE, ia_root->accNavigate(NAVDIR_PREVIOUS, ScopedVariant(1), |
| 491 end.AsInput())); |
| 492 EXPECT_EQ(VT_EMPTY, end.type()); |
| 493 EXPECT_EQ(S_FALSE, |
| 494 ia_root->accNavigate(NAVDIR_NEXT, ScopedVariant(2), end.AsInput())); |
| 495 EXPECT_EQ(VT_EMPTY, end.type()); |
| 496 } |
| 497 |
| 404 TEST_F(AXPlatformNodeWinTest, TestIAccessible2SetSelection) { | 498 TEST_F(AXPlatformNodeWinTest, TestIAccessible2SetSelection) { |
| 405 AXNodeData text_field_node; | 499 AXNodeData text_field_node; |
| 406 text_field_node.id = 1; | 500 text_field_node.id = 1; |
| 407 text_field_node.role = ui::AX_ROLE_TEXT_FIELD; | 501 text_field_node.role = ui::AX_ROLE_TEXT_FIELD; |
| 408 text_field_node.state = 1 << ui::AX_STATE_EDITABLE; | 502 text_field_node.state = 1 << ui::AX_STATE_EDITABLE; |
| 409 text_field_node.SetValue("Hi"); | 503 text_field_node.SetValue("Hi"); |
| 410 | 504 |
| 411 Init(text_field_node); | 505 Init(text_field_node); |
| 412 ScopedComPtr<IAccessible2> ia2_text_field = | 506 ScopedComPtr<IAccessible2> ia2_text_field = |
| 413 ToIAccessible2(GetRootIAccessible()); | 507 ToIAccessible2(GetRootIAccessible()); |
| 414 ScopedComPtr<IAccessibleText> text_field; | 508 ScopedComPtr<IAccessibleText> text_field; |
| 415 text_field.QueryFrom(ia2_text_field.Get()); | 509 text_field.QueryFrom(ia2_text_field.Get()); |
| 416 ASSERT_NE(nullptr, text_field); | 510 ASSERT_NE(nullptr, text_field); |
| 417 | 511 |
| 418 EXPECT_HRESULT_SUCCEEDED(text_field->setSelection(0, 0, 1)); | 512 EXPECT_HRESULT_SUCCEEDED(text_field->setSelection(0, 0, 1)); |
| 419 EXPECT_HRESULT_SUCCEEDED(text_field->setSelection(0, 1, 0)); | 513 EXPECT_HRESULT_SUCCEEDED(text_field->setSelection(0, 1, 0)); |
| 420 EXPECT_HRESULT_SUCCEEDED(text_field->setSelection(0, 2, 2)); | 514 EXPECT_HRESULT_SUCCEEDED(text_field->setSelection(0, 2, 2)); |
| 421 EXPECT_HRESULT_SUCCEEDED(text_field->setSelection(0, IA2_TEXT_OFFSET_CARET, | 515 EXPECT_HRESULT_SUCCEEDED(text_field->setSelection(0, IA2_TEXT_OFFSET_CARET, |
| 422 IA2_TEXT_OFFSET_LENGTH)); | 516 IA2_TEXT_OFFSET_LENGTH)); |
| 423 | 517 |
| 424 EXPECT_HRESULT_FAILED(text_field->setSelection(1, 0, 0)); | 518 EXPECT_HRESULT_FAILED(text_field->setSelection(1, 0, 0)); |
| 425 EXPECT_HRESULT_FAILED(text_field->setSelection(0, 0, 5)); | 519 EXPECT_HRESULT_FAILED(text_field->setSelection(0, 0, 5)); |
| 426 } | 520 } |
| 427 | 521 |
| 428 } // namespace ui | 522 } // namespace ui |
| OLD | NEW |