OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/memory/scoped_ptr.h" | 5 #include "base/memory/scoped_ptr.h" |
6 #include "base/strings/utf_string_conversions.h" | 6 #include "base/strings/utf_string_conversions.h" |
7 #include "base/win/scoped_bstr.h" | 7 #include "base/win/scoped_bstr.h" |
8 #include "base/win/scoped_comptr.h" | 8 #include "base/win/scoped_comptr.h" |
9 #include "base/win/scoped_variant.h" | 9 #include "base/win/scoped_variant.h" |
10 #include "content/browser/accessibility/browser_accessibility_manager.h" | 10 #include "content/browser/accessibility/browser_accessibility_manager.h" |
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 EXPECT_NE(nullptr, static_cast<BSTR>(attributes)); | 805 EXPECT_NE(nullptr, static_cast<BSTR>(attributes)); |
806 std::wstring attributes_str(attributes, attributes.Length()); | 806 std::wstring attributes_str(attributes, attributes.Length()); |
807 EXPECT_EQ(L"checkable:true;", attributes_str); | 807 EXPECT_EQ(L"checkable:true;", attributes_str); |
808 | 808 |
809 manager.reset(); | 809 manager.reset(); |
810 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); | 810 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); |
811 } | 811 } |
812 | 812 |
813 /** | 813 /** |
814 * Ensures that ui::AX_ATTR_TEXT_SEL_START/END attributes are correctly used to | 814 * Ensures that ui::AX_ATTR_TEXT_SEL_START/END attributes are correctly used to |
815 * determine caret position and text selection in various types of editable | 815 * determine caret position and text selection in simple form fields. |
816 * elements. | |
817 */ | 816 */ |
818 TEST_F(BrowserAccessibilityTest, TestCaretAndTextSelection) { | 817 TEST_F(BrowserAccessibilityTest, TestCaretAndSelectionInSimpleFields) { |
819 ui::AXNodeData root; | 818 ui::AXNodeData root; |
820 root.id = 1; | 819 root.id = 1; |
821 root.role = ui::AX_ROLE_ROOT_WEB_AREA; | 820 root.role = ui::AX_ROLE_ROOT_WEB_AREA; |
822 root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE); | 821 root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE); |
823 | 822 |
824 ui::AXNodeData combo_box; | 823 ui::AXNodeData combo_box; |
825 combo_box.id = 2; | 824 combo_box.id = 2; |
826 combo_box.role = ui::AX_ROLE_COMBO_BOX; | 825 combo_box.role = ui::AX_ROLE_COMBO_BOX; |
827 combo_box.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_FOCUSED); | 826 combo_box.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_FOCUSED); |
828 combo_box.SetValue("Test1"); | 827 combo_box.SetValue("Test1"); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
868 // -2 is never a valid offset. | 867 // -2 is never a valid offset. |
869 LONG caret_offset = -2; | 868 LONG caret_offset = -2; |
870 LONG n_selections = -2; | 869 LONG n_selections = -2; |
871 LONG selection_start = -2; | 870 LONG selection_start = -2; |
872 LONG selection_end = -2; | 871 LONG selection_end = -2; |
873 | 872 |
874 // Test get_caretOffset. | 873 // Test get_caretOffset. |
875 HRESULT hr = combo_box_accessible->get_caretOffset(&caret_offset);; | 874 HRESULT hr = combo_box_accessible->get_caretOffset(&caret_offset);; |
876 EXPECT_EQ(S_OK, hr); | 875 EXPECT_EQ(S_OK, hr); |
877 EXPECT_EQ(1L, caret_offset); | 876 EXPECT_EQ(1L, caret_offset); |
878 // caret_offset should be -1 when the object is not focused. | 877 // The caret should be at the start of the selection. |
879 hr = text_field_accessible->get_caretOffset(&caret_offset);; | 878 hr = text_field_accessible->get_caretOffset(&caret_offset);; |
880 EXPECT_EQ(S_FALSE, hr); | 879 EXPECT_EQ(S_OK, hr); |
881 EXPECT_EQ(-1L, caret_offset); | 880 EXPECT_EQ(1L, caret_offset); |
882 | 881 |
883 // Move the focus to the text field. | 882 // Move the focus to the text field. |
884 combo_box.state &= ~(1 << ui::AX_STATE_FOCUSED); | 883 combo_box.state &= ~(1 << ui::AX_STATE_FOCUSED); |
885 text_field.state |= 1 << ui::AX_STATE_FOCUSED; | 884 text_field.state |= 1 << ui::AX_STATE_FOCUSED; |
886 manager->SetFocus(text_field_accessible, false /* notify */); | 885 manager->SetFocus(text_field_accessible, false /* notify */); |
887 ASSERT_EQ(text_field_accessible, | 886 ASSERT_EQ(text_field_accessible, |
888 manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin()); | 887 manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin()); |
889 | 888 |
890 // The caret should be at the start of the selection. | 889 // The caret should not have moved. |
891 hr = text_field_accessible->get_caretOffset(&caret_offset);; | 890 hr = text_field_accessible->get_caretOffset(&caret_offset);; |
892 EXPECT_EQ(S_OK, hr); | 891 EXPECT_EQ(S_OK, hr); |
893 EXPECT_EQ(1L, caret_offset); | 892 EXPECT_EQ(1L, caret_offset); |
894 | 893 |
895 // Test get_nSelections. | 894 // Test get_nSelections. |
896 hr = combo_box_accessible->get_nSelections(&n_selections);; | 895 hr = combo_box_accessible->get_nSelections(&n_selections);; |
897 EXPECT_EQ(S_OK, hr); | 896 EXPECT_EQ(S_OK, hr); |
898 EXPECT_EQ(0L, n_selections); | 897 EXPECT_EQ(0L, n_selections); |
899 hr = text_field_accessible->get_nSelections(&n_selections);; | 898 hr = text_field_accessible->get_nSelections(&n_selections);; |
900 EXPECT_EQ(S_OK, hr); | 899 EXPECT_EQ(S_OK, hr); |
901 EXPECT_EQ(1L, n_selections); | 900 EXPECT_EQ(1L, n_selections); |
902 | 901 |
903 // Test get_selection. | 902 // Test get_selection. |
904 hr = combo_box_accessible->get_selection( | 903 hr = combo_box_accessible->get_selection( |
905 0L /* selection_index */, &selection_start, &selection_end);; | 904 0L /* selection_index */, &selection_start, &selection_end);; |
906 EXPECT_EQ(E_INVALIDARG, hr); // No selections available. | 905 EXPECT_EQ(E_INVALIDARG, hr); // No selections available. |
907 // Invalid in_args should not modify out_args. | 906 // Invalid in_args should not modify out_args. |
908 EXPECT_EQ(-2L, selection_start); | 907 EXPECT_EQ(-2L, selection_start); |
909 EXPECT_EQ(-2L, selection_end); | 908 EXPECT_EQ(-2L, selection_end); |
910 hr = text_field_accessible->get_selection( | 909 hr = text_field_accessible->get_selection( |
911 0L /* selection_index */, &selection_start, &selection_end);; | 910 0L /* selection_index */, &selection_start, &selection_end);; |
912 EXPECT_EQ(S_OK, hr); | 911 EXPECT_EQ(S_OK, hr); |
913 EXPECT_EQ(1L, selection_start); | 912 EXPECT_EQ(1L, selection_start); |
914 EXPECT_EQ(2L, selection_end); | 913 EXPECT_EQ(2L, selection_end); |
915 | 914 |
916 manager.reset(); | 915 manager.reset(); |
917 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); | 916 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); |
918 } | 917 } |
919 | 918 |
| 919 TEST_F(BrowserAccessibilityTest, DISABLED_TestCaretInContentEditables) { |
| 920 ui::AXNodeData root; |
| 921 root.id = 1; |
| 922 root.role = ui::AX_ROLE_ROOT_WEB_AREA; |
| 923 root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE); |
| 924 |
| 925 ui::AXNodeData div_editable; |
| 926 div_editable.id = 2; |
| 927 div_editable.role = ui::AX_ROLE_DIV; |
| 928 div_editable.state = (1 << ui::AX_STATE_FOCUSABLE); |
| 929 |
| 930 ui::AXNodeData text; |
| 931 text.id = 3; |
| 932 text.role = ui::AX_ROLE_STATIC_TEXT; |
| 933 text.SetName("Click "); |
| 934 |
| 935 ui::AXNodeData link; |
| 936 link.id = 4; |
| 937 link.role = ui::AX_ROLE_LINK; |
| 938 link.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_LINKED); |
| 939 link.SetName("here"); |
| 940 |
| 941 ui::AXNodeData link_text; |
| 942 link_text.id = 5; |
| 943 link_text.role = ui::AX_ROLE_STATIC_TEXT; |
| 944 link_text.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_LINKED); |
| 945 link_text.SetName("here"); |
| 946 |
| 947 // Place the caret between 'h' and 'e'. |
| 948 root.AddIntAttribute(ui::AX_ATTR_ANCHOR_OBJECT_ID, 4); |
| 949 root.AddIntAttribute(ui::AX_ATTR_ANCHOR_OFFSET, 1); |
| 950 root.AddIntAttribute(ui::AX_ATTR_FOCUS_OBJECT_ID, 4); |
| 951 root.AddIntAttribute(ui::AX_ATTR_FOCUS_OFFSET, 1); |
| 952 |
| 953 root.child_ids.push_back(2); |
| 954 div_editable.child_ids.push_back(3); |
| 955 div_editable.child_ids.push_back(4); |
| 956 link.child_ids.push_back(5); |
| 957 |
| 958 CountedBrowserAccessibility::reset(); |
| 959 scoped_ptr<BrowserAccessibilityManager> manager( |
| 960 BrowserAccessibilityManager::Create( |
| 961 MakeAXTreeUpdate(root, div_editable, link, link_text, text), |
| 962 nullptr, new CountedBrowserAccessibilityFactory())); |
| 963 ASSERT_EQ(5, CountedBrowserAccessibility::num_instances()); |
| 964 |
| 965 ASSERT_NE(nullptr, manager->GetRoot()); |
| 966 BrowserAccessibilityWin* root_accessible = |
| 967 manager->GetRoot()->ToBrowserAccessibilityWin(); |
| 968 ASSERT_NE(nullptr, root_accessible); |
| 969 ASSERT_EQ(1, root_accessible->PlatformChildCount()); |
| 970 |
| 971 BrowserAccessibilityWin* div_editable_accessible = |
| 972 root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin(); |
| 973 ASSERT_NE(nullptr, div_editable_accessible); |
| 974 ASSERT_EQ(2, div_editable_accessible->PlatformChildCount()); |
| 975 |
| 976 // -2 is never a valid offset. |
| 977 LONG caret_offset = -2; |
| 978 |
| 979 // The caret should be on the embedded object character. |
| 980 HRESULT hr = div_editable_accessible->get_caretOffset(&caret_offset);; |
| 981 EXPECT_EQ(S_OK, hr); |
| 982 EXPECT_EQ(6L, caret_offset); |
| 983 |
| 984 // Move the focus to the content editable. |
| 985 div_editable.state |= 1 << ui::AX_STATE_FOCUSED; |
| 986 manager->SetFocus(div_editable_accessible, false /* notify */); |
| 987 ASSERT_EQ(div_editable_accessible, |
| 988 manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin()); |
| 989 |
| 990 BrowserAccessibilityWin* text_accessible = |
| 991 div_editable_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin(); |
| 992 ASSERT_NE(nullptr, text_accessible); |
| 993 BrowserAccessibilityWin* link_accessible = |
| 994 div_editable_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin(); |
| 995 ASSERT_NE(nullptr, link_accessible); |
| 996 ASSERT_EQ(1, link_accessible->PlatformChildCount()); |
| 997 |
| 998 BrowserAccessibilityWin* link_text_accessible = |
| 999 link_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin(); |
| 1000 ASSERT_NE(nullptr, link_text_accessible); |
| 1001 |
| 1002 // The caret should not have moved. |
| 1003 hr = div_editable_accessible->get_caretOffset(&caret_offset);; |
| 1004 EXPECT_EQ(S_OK, hr); |
| 1005 EXPECT_EQ(6L, caret_offset); |
| 1006 |
| 1007 hr = link_accessible->get_caretOffset(&caret_offset);; |
| 1008 EXPECT_EQ(S_OK, hr); |
| 1009 EXPECT_EQ(1L, caret_offset); |
| 1010 hr = link_text_accessible->get_caretOffset(&caret_offset);; |
| 1011 EXPECT_EQ(S_OK, hr); |
| 1012 EXPECT_EQ(1L, caret_offset); |
| 1013 |
| 1014 manager.reset(); |
| 1015 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); |
| 1016 } |
| 1017 |
| 1018 TEST_F(BrowserAccessibilityTest, DISABLED_TestSelectionInContentEditables) { |
| 1019 ui::AXNodeData root; |
| 1020 root.id = 1; |
| 1021 root.role = ui::AX_ROLE_ROOT_WEB_AREA; |
| 1022 root.state = (1 << ui::AX_STATE_READ_ONLY) | (1 << ui::AX_STATE_FOCUSABLE); |
| 1023 |
| 1024 ui::AXNodeData div_editable; |
| 1025 div_editable.id = 2; |
| 1026 div_editable.role = ui::AX_ROLE_DIV; |
| 1027 div_editable.state = (1 << ui::AX_STATE_FOCUSABLE); |
| 1028 |
| 1029 ui::AXNodeData text; |
| 1030 text.id = 3; |
| 1031 text.role = ui::AX_ROLE_STATIC_TEXT; |
| 1032 text.SetName("Click "); |
| 1033 |
| 1034 ui::AXNodeData link; |
| 1035 link.id = 4; |
| 1036 link.role = ui::AX_ROLE_LINK; |
| 1037 link.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_LINKED); |
| 1038 link.SetName("here"); |
| 1039 |
| 1040 ui::AXNodeData link_text; |
| 1041 link_text.id = 5; |
| 1042 link_text.role = ui::AX_ROLE_STATIC_TEXT; |
| 1043 link_text.state = (1 << ui::AX_STATE_FOCUSABLE) | (1 << ui::AX_STATE_LINKED); |
| 1044 link_text.SetName("here"); |
| 1045 |
| 1046 // Select the part of the text "lick here". |
| 1047 root.AddIntAttribute(ui::AX_ATTR_ANCHOR_OBJECT_ID, 3); |
| 1048 root.AddIntAttribute(ui::AX_ATTR_ANCHOR_OFFSET, 1); |
| 1049 root.AddIntAttribute(ui::AX_ATTR_FOCUS_OBJECT_ID, 5); |
| 1050 root.AddIntAttribute(ui::AX_ATTR_FOCUS_OFFSET, 4); |
| 1051 |
| 1052 root.child_ids.push_back(2); |
| 1053 div_editable.child_ids.push_back(3); |
| 1054 div_editable.child_ids.push_back(4); |
| 1055 link.child_ids.push_back(5); |
| 1056 |
| 1057 CountedBrowserAccessibility::reset(); |
| 1058 scoped_ptr<BrowserAccessibilityManager> manager( |
| 1059 BrowserAccessibilityManager::Create( |
| 1060 MakeAXTreeUpdate(root, div_editable, link, link_text, text), |
| 1061 nullptr, new CountedBrowserAccessibilityFactory())); |
| 1062 ASSERT_EQ(5, CountedBrowserAccessibility::num_instances()); |
| 1063 |
| 1064 ASSERT_NE(nullptr, manager->GetRoot()); |
| 1065 BrowserAccessibilityWin* root_accessible = |
| 1066 manager->GetRoot()->ToBrowserAccessibilityWin(); |
| 1067 ASSERT_NE(nullptr, root_accessible); |
| 1068 ASSERT_EQ(1, root_accessible->PlatformChildCount()); |
| 1069 |
| 1070 BrowserAccessibilityWin* div_editable_accessible = |
| 1071 root_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin(); |
| 1072 ASSERT_NE(nullptr, div_editable_accessible); |
| 1073 ASSERT_EQ(2, div_editable_accessible->PlatformChildCount()); |
| 1074 |
| 1075 // -2 is never a valid offset. |
| 1076 LONG caret_offset = -2; |
| 1077 LONG n_selections = -2; |
| 1078 LONG selection_start = -2; |
| 1079 LONG selection_end = -2; |
| 1080 |
| 1081 BrowserAccessibilityWin* text_accessible = |
| 1082 div_editable_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin(); |
| 1083 ASSERT_NE(nullptr, text_accessible); |
| 1084 BrowserAccessibilityWin* link_accessible = |
| 1085 div_editable_accessible->PlatformGetChild(1)->ToBrowserAccessibilityWin(); |
| 1086 ASSERT_NE(nullptr, link_accessible); |
| 1087 ASSERT_EQ(1, link_accessible->PlatformChildCount()); |
| 1088 |
| 1089 BrowserAccessibilityWin* link_text_accessible = |
| 1090 link_accessible->PlatformGetChild(0)->ToBrowserAccessibilityWin(); |
| 1091 ASSERT_NE(nullptr, link_text_accessible); |
| 1092 |
| 1093 // get_nSelections should work on all objects. |
| 1094 HRESULT hr = div_editable_accessible->get_nSelections(&n_selections);; |
| 1095 EXPECT_EQ(S_OK, hr); |
| 1096 EXPECT_EQ(1L, n_selections); |
| 1097 hr = text_accessible->get_nSelections(&n_selections);; |
| 1098 EXPECT_EQ(S_OK, hr); |
| 1099 EXPECT_EQ(1L, n_selections); |
| 1100 hr = link_accessible->get_nSelections(&n_selections);; |
| 1101 EXPECT_EQ(S_OK, hr); |
| 1102 EXPECT_EQ(1L, n_selections); |
| 1103 hr = link_text_accessible->get_nSelections(&n_selections);; |
| 1104 EXPECT_EQ(S_OK, hr); |
| 1105 EXPECT_EQ(1L, n_selections); |
| 1106 |
| 1107 // get_selection should be unaffected by focus placement. |
| 1108 hr = div_editable_accessible->get_selection( |
| 1109 0L /* selection_index */, &selection_start, &selection_end);; |
| 1110 EXPECT_EQ(S_OK, hr); |
| 1111 EXPECT_EQ(1L, selection_start); |
| 1112 // selection_end should be after embedded object character. |
| 1113 EXPECT_EQ(7L, selection_end); |
| 1114 |
| 1115 hr = text_accessible->get_selection( |
| 1116 0L /* selection_index */, &selection_start, &selection_end);; |
| 1117 EXPECT_EQ(S_OK, hr); |
| 1118 EXPECT_EQ(1L, selection_start); |
| 1119 // No embedded character on this object, only the first part of the text. |
| 1120 EXPECT_EQ(6L, selection_end); |
| 1121 hr = link_accessible->get_selection( |
| 1122 0L /* selection_index */, &selection_start, &selection_end);; |
| 1123 EXPECT_EQ(S_OK, hr); |
| 1124 EXPECT_EQ(0L, selection_start); |
| 1125 EXPECT_EQ(4L, selection_end); |
| 1126 hr = link_text_accessible->get_selection( |
| 1127 0L /* selection_index */, &selection_start, &selection_end);; |
| 1128 EXPECT_EQ(S_OK, hr); |
| 1129 EXPECT_EQ(0L, selection_start); |
| 1130 EXPECT_EQ(4L, selection_end); |
| 1131 |
| 1132 // The caret should be at the anchor (the start) of the selection. |
| 1133 hr = div_editable_accessible->get_caretOffset(&caret_offset);; |
| 1134 EXPECT_EQ(S_OK, hr); |
| 1135 EXPECT_EQ(1L, caret_offset); |
| 1136 |
| 1137 // Move the focus to the content editable. |
| 1138 div_editable.state |= 1 << ui::AX_STATE_FOCUSED; |
| 1139 manager->SetFocus(div_editable_accessible, false /* notify */); |
| 1140 ASSERT_EQ(div_editable_accessible, |
| 1141 manager->GetFocus(root_accessible)->ToBrowserAccessibilityWin()); |
| 1142 |
| 1143 // The caret should not have moved. |
| 1144 hr = div_editable_accessible->get_caretOffset(&caret_offset);; |
| 1145 EXPECT_EQ(S_OK, hr); |
| 1146 EXPECT_EQ(1L, caret_offset); |
| 1147 |
| 1148 // The HRESULT should be S_FALSE if the caret is not in the given object. |
| 1149 hr = link_accessible->get_caretOffset(&caret_offset);; |
| 1150 EXPECT_EQ(S_FALSE, hr); |
| 1151 EXPECT_EQ(-1L, caret_offset); |
| 1152 hr = link_text_accessible->get_caretOffset(&caret_offset);; |
| 1153 EXPECT_EQ(S_FALSE, hr); |
| 1154 EXPECT_EQ(-1L, caret_offset); |
| 1155 |
| 1156 hr = div_editable_accessible->get_selection( |
| 1157 0L /* selection_index */, &selection_start, &selection_end);; |
| 1158 EXPECT_EQ(S_OK, hr); |
| 1159 EXPECT_EQ(1L, selection_start); |
| 1160 EXPECT_EQ(7L, selection_end); |
| 1161 |
| 1162 manager.reset(); |
| 1163 ASSERT_EQ(0, CountedBrowserAccessibility::num_instances()); |
| 1164 } |
| 1165 |
920 } // namespace content | 1166 } // namespace content |
OLD | NEW |