Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: content/browser/accessibility/accessibility_win_browsertest.cc

Issue 660633002: Fixed IAccessibleText::TextAtOffset with IA2_TEXT_BOUNDARY_WORD to return text that spans from the … (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Implemented testing for special offsets (cursor position and text length). Fixed memory leak when r… Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/browser/accessibility/browser_accessibility.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <vector> 5 #include <vector>
6 6
7 #include "base/memory/scoped_ptr.h" 7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "base/win/scoped_bstr.h" 9 #include "base/win/scoped_bstr.h"
10 #include "base/win/scoped_comptr.h" 10 #include "base/win/scoped_comptr.h"
(...skipping 13 matching lines...) Expand all
24 #include "content/test/accessibility_browser_test_utils.h" 24 #include "content/test/accessibility_browser_test_utils.h"
25 #include "third_party/iaccessible2/ia2_api_all.h" 25 #include "third_party/iaccessible2/ia2_api_all.h"
26 #include "third_party/isimpledom/ISimpleDOMNode.h" 26 #include "third_party/isimpledom/ISimpleDOMNode.h"
27 #include "ui/aura/window.h" 27 #include "ui/aura/window.h"
28 #include "ui/aura/window_tree_host.h" 28 #include "ui/aura/window_tree_host.h"
29 29
30 namespace content { 30 namespace content {
31 31
32 namespace { 32 namespace {
33 33
34 // Helpers -------------------------------------------------------------------- 34 class AccessibleChecker;
35 35
36 base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant( 36
37 IAccessible* parent, 37 // AccessibilityWinBrowserTest ------------------------------------------------
38 VARIANT* var) { 38
39 class AccessibilityWinBrowserTest : public ContentBrowserTest {
40 public:
41 AccessibilityWinBrowserTest();
42 virtual ~AccessibilityWinBrowserTest();
43
44 protected:
45 void LoadInitialAccessibilityTreeFromHtml(const std::string& html);
46 IAccessible* GetRendererAccessible();
47 void ExecuteScript(const std::wstring& script);
48
49 static base::win::ScopedComPtr<IAccessible>
50 AccessibilityWinBrowserTest::GetAccessibleFromVariant(
51 IAccessible* parent, VARIANT* var);
52 static HRESULT QueryIAccessible2(IAccessible* accessible,
53 IAccessible2** accessible2);
dmazzoni 2014/11/06 06:53:30 nit: check indentation
54 static void RecursiveFindNodeInAccessibilityTree(IAccessible* node,
55 int32 expected_role, const std::wstring& expected_name,
56 int32 depth, bool* found);
57 static void CheckTextAtOffset(IAccessibleText* element,
58 LONG offset, IA2TextBoundaryType boundary_type,
59 LONG expected_start_offset, LONG expected_end_offset,
60 const std::wstring& expected_text);
61 static std::vector<base::win::ScopedVariant> GetAllAccessibleChildren(
62 IAccessible* element);
63
64 private:
65 friend class AccessibleChecker;
66 DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest);
67 };
68
69 AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
70 }
71
72 AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {
73 }
74
75 void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
76 const std::string& html) {
77 AccessibilityNotificationWaiter waiter(
78 shell(), AccessibilityModeComplete,
79 ui::AX_EVENT_LOAD_COMPLETE);
80 GURL html_data_url("data:text/html," + html);
81 NavigateToURL(shell(), html_data_url);
82 waiter.WaitForNotification();
83 }
84
85 // Retrieve the MSAA client accessibility object for the Render Widget Host View
86 // of the selected tab.
87 IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() {
88 content::WebContents* web_contents = shell()->web_contents();
89 return web_contents->GetRenderWidgetHostView()->GetNativeViewAccessible();
90 }
91
92 void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) {
93 shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script);
94 }
95
96 // Static helpers ------------------------------------------------
97
98 base::win::ScopedComPtr<IAccessible>
99 AccessibilityWinBrowserTest::GetAccessibleFromVariant(
100 IAccessible* parent, VARIANT* var) {
39 base::win::ScopedComPtr<IAccessible> ptr; 101 base::win::ScopedComPtr<IAccessible> ptr;
40 switch (V_VT(var)) { 102 switch (V_VT(var)) {
41 case VT_DISPATCH: { 103 case VT_DISPATCH: {
42 IDispatch* dispatch = V_DISPATCH(var); 104 IDispatch* dispatch = V_DISPATCH(var);
43 if (dispatch) 105 if (dispatch)
44 ptr.QueryFrom(dispatch); 106 ptr.QueryFrom(dispatch);
45 break; 107 break;
46 } 108 }
47 109
48 case VT_I4: { 110 case VT_I4: {
49 base::win::ScopedComPtr<IDispatch> dispatch; 111 base::win::ScopedComPtr<IDispatch> dispatch;
50 HRESULT hr = parent->get_accChild(*var, dispatch.Receive()); 112 HRESULT hr = parent->get_accChild(*var, dispatch.Receive());
51 EXPECT_TRUE(SUCCEEDED(hr)); 113 EXPECT_TRUE(SUCCEEDED(hr));
52 if (dispatch) 114 if (dispatch)
53 dispatch.QueryInterface(ptr.Receive()); 115 dispatch.QueryInterface(ptr.Receive());
54 break; 116 break;
55 } 117 }
56 } 118 }
57 return ptr; 119 return ptr;
58 } 120 }
59 121
60 HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) { 122 HRESULT AccessibilityWinBrowserTest::QueryIAccessible2(
61 // TODO(ctguil): For some reason querying the IAccessible2 interface from 123 IAccessible* accessible, IAccessible2** accessible2) {
dmazzoni 2014/11/06 06:53:30 I like naming output parameters with an "out_" pre
62 // IAccessible fails. 124 // IA2 Spec dictates that IServiceProvider should be used instead of
125 // QueryInterface when retrieving IAccessible2.
63 base::win::ScopedComPtr<IServiceProvider> service_provider; 126 base::win::ScopedComPtr<IServiceProvider> service_provider;
64 HRESULT hr = accessible->QueryInterface(service_provider.Receive()); 127 HRESULT hr = accessible->QueryInterface(service_provider.Receive());
65 return SUCCEEDED(hr) ? 128 return SUCCEEDED(hr) ?
66 service_provider->QueryService(IID_IAccessible2, accessible2) : hr; 129 service_provider->QueryService(IID_IAccessible2, accessible2) : hr;
67 } 130 }
68 131
69 // Recursively search through all of the descendants reachable from an 132 // Recursively search through all of the descendants reachable from an
70 // IAccessible node and return true if we find one with the given role 133 // IAccessible node and return true if we find one with the given role
71 // and name. 134 // and name.
72 void RecursiveFindNodeInAccessibilityTree(IAccessible* node, 135 void AccessibilityWinBrowserTest::RecursiveFindNodeInAccessibilityTree(
73 int32 expected_role, 136 IAccessible* node, int32 expected_role, const std::wstring& expected_name,
74 const std::wstring& expected_name, 137 int32 depth, bool* found) {
75 int32 depth,
76 bool* found) {
77 base::win::ScopedBstr name_bstr; 138 base::win::ScopedBstr name_bstr;
78 base::win::ScopedVariant childid_self(CHILDID_SELF); 139 base::win::ScopedVariant childid_self(CHILDID_SELF);
79 node->get_accName(childid_self, name_bstr.Receive()); 140 node->get_accName(childid_self, name_bstr.Receive());
80 std::wstring name(name_bstr, name_bstr.Length()); 141 std::wstring name(name_bstr, name_bstr.Length());
81 base::win::ScopedVariant role; 142 base::win::ScopedVariant role;
82 node->get_accRole(childid_self, role.Receive()); 143 node->get_accRole(childid_self, role.Receive());
83 ASSERT_EQ(VT_I4, role.type()); 144 ASSERT_EQ(VT_I4, role.type());
84 145
85 // Print the accessibility tree as we go, because if this test fails 146 // Print the accessibility tree as we go, because if this test fails
86 // on the bots, this is really helpful in figuring out why. 147 // on the bots, this is really helpful in figuring out why.
87 for (int i = 0; i < depth; i++) 148 for (int i = 0; i < depth; i++)
88 printf(" "); 149 printf(" ");
89 printf("role=%s name=%s\n", 150 printf("role=%s name=%s\n",
90 base::WideToUTF8(IAccessibleRoleToString(V_I4(&role))).c_str(), 151 base::WideToUTF8(IAccessibleRoleToString(V_I4(&role))).c_str(),
91 base::WideToUTF8(name).c_str()); 152 base::WideToUTF8(name).c_str());
92 153
93 if (expected_role == V_I4(&role) && expected_name == name) { 154 if (expected_role == V_I4(&role) && expected_name == name) {
94 *found = true; 155 *found = true;
95 return; 156 return;
96 } 157 }
97 158
98 LONG child_count = 0; 159 std::vector<base::win::ScopedVariant> children = GetAllAccessibleChildren(
99 HRESULT hr = node->get_accChildCount(&child_count); 160 node);
100 ASSERT_EQ(S_OK, hr); 161 for (size_t i = 0; i < children.size(); ++i) {
101
102 scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
103 LONG obtained_count = 0;
104 hr = AccessibleChildren(
105 node, 0, child_count, child_array.get(), &obtained_count);
106 ASSERT_EQ(S_OK, hr);
107 ASSERT_EQ(child_count, obtained_count);
108
109 for (int index = 0; index < obtained_count; index++) {
110 base::win::ScopedComPtr<IAccessible> child_accessible( 162 base::win::ScopedComPtr<IAccessible> child_accessible(
111 GetAccessibleFromResultVariant(node, &child_array.get()[index])); 163 GetAccessibleFromVariant(node, children[i].AsInput()));
112 if (child_accessible) { 164 if (child_accessible) {
113 RecursiveFindNodeInAccessibilityTree( 165 RecursiveFindNodeInAccessibilityTree(
114 child_accessible.get(), expected_role, expected_name, depth + 1, 166 child_accessible.get(), expected_role, expected_name, depth + 1,
115 found); 167 found);
116 if (*found) 168 if (*found)
117 return; 169 return;
118 } 170 }
119 } 171 }
120 } 172 }
121 173
174 // Ensures that the text and the start and end offsets retrieved using
175 // get_textAtOffset match the expected values.
176 void AccessibilityWinBrowserTest::CheckTextAtOffset(IAccessibleText* element,
177 LONG offset, IA2TextBoundaryType boundary_type,
178 LONG expected_start_offset, LONG expected_end_offset,
179 const std::wstring& expected_text) {
180 testing::Message message;
181 message << "while checking for " << expected_text << " at " <<
182 expected_start_offset << '-' << expected_end_offset;
183 SCOPED_TRACE(message);
122 184
123 // AccessibilityWinBrowserTest ------------------------------------------------ 185 LONG start_offset = 0;
124 186 LONG end_offset = 0;
125 class AccessibilityWinBrowserTest : public ContentBrowserTest { 187 base::win::ScopedBstr text;
126 public: 188 HRESULT hr = element->get_textAtOffset(
127 AccessibilityWinBrowserTest(); 189 offset, boundary_type,
128 virtual ~AccessibilityWinBrowserTest(); 190 &start_offset, &end_offset, text.Receive());
129 191 EXPECT_EQ(S_OK, hr);
130 protected: 192 EXPECT_EQ(expected_start_offset, start_offset);
131 void LoadInitialAccessibilityTreeFromHtml(const std::string& html); 193 EXPECT_EQ(expected_end_offset, end_offset);
132 IAccessible* GetRendererAccessible(); 194 EXPECT_EQ(expected_text, std::wstring(text, text.Length()));
133 void ExecuteScript(const std::wstring& script);
134
135 private:
136 DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest);
137 };
138
139 AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
140 } 195 }
141 196
142 AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() { 197 std::vector<base::win::ScopedVariant>
143 } 198 AccessibilityWinBrowserTest::GetAllAccessibleChildren(
199 IAccessible* element) {
200 LONG child_count = 0;
201 HRESULT hr = element->get_accChildCount(&child_count);
202 EXPECT_EQ(S_OK, hr);
203 if (child_count <= 0)
204 return std::vector<base::win::ScopedVariant>();
144 205
145 void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml( 206 scoped_ptr<VARIANT[]> children_array(new VARIANT[child_count]);
146 const std::string& html) { 207 LONG obtained_count = 0;
147 AccessibilityNotificationWaiter waiter( 208 hr = AccessibleChildren(
148 shell(), AccessibilityModeComplete, 209 element, 0, child_count, children_array.get(), &obtained_count);
149 ui::AX_EVENT_LOAD_COMPLETE); 210 EXPECT_EQ(S_OK, hr);
150 GURL html_data_url("data:text/html," + html); 211 EXPECT_EQ(child_count, obtained_count);
151 NavigateToURL(shell(), html_data_url);
152 waiter.WaitForNotification();
153 }
154 212
155 // Retrieve the MSAA client accessibility object for the Render Widget Host View 213 std::vector<base::win::ScopedVariant> children(
156 // of the selected tab. 214 static_cast<size_t>(child_count));
157 IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() { 215 for (size_t i = 0; i < children.size(); i++) {
158 content::WebContents* web_contents = shell()->web_contents(); 216 children[i].Reset(children_array[i]);
159 return web_contents->GetRenderWidgetHostView()->GetNativeViewAccessible(); 217 }
160 } 218 return children;
161
162 void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) {
163 shell()->web_contents()->GetMainFrame()->ExecuteJavaScript(script);
164 } 219 }
165 220
166 221
167 // AccessibleChecker ---------------------------------------------------------- 222 // AccessibleChecker ----------------------------------------------------------
168 223
169 class AccessibleChecker { 224 class AccessibleChecker {
170 public: 225 public:
171 // This constructor can be used if the IA2 role will be the same as the MSAA 226 // This constructor can be used if the IA2 role will be the same as the MSAA
172 // role. 227 // role.
173 AccessibleChecker(const std::wstring& expected_name, 228 AccessibleChecker(const std::wstring& expected_name,
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 base::win::ScopedVariant childid_self(CHILDID_SELF); 359 base::win::ScopedVariant childid_self(CHILDID_SELF);
305 HRESULT hr = accessible->get_accRole(childid_self, role.Receive()); 360 HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
306 ASSERT_EQ(S_OK, hr); 361 ASSERT_EQ(S_OK, hr);
307 EXPECT_EQ(0, role_.Compare(role)) 362 EXPECT_EQ(0, role_.Compare(role))
308 << "Expected role: " << RoleVariantToString(role_) 363 << "Expected role: " << RoleVariantToString(role_)
309 << "\nGot role: " << RoleVariantToString(role); 364 << "\nGot role: " << RoleVariantToString(role);
310 } 365 }
311 366
312 void AccessibleChecker::CheckIA2Role(IAccessible* accessible) { 367 void AccessibleChecker::CheckIA2Role(IAccessible* accessible) {
313 base::win::ScopedComPtr<IAccessible2> accessible2; 368 base::win::ScopedComPtr<IAccessible2> accessible2;
314 HRESULT hr = QueryIAccessible2(accessible, accessible2.Receive()); 369 HRESULT hr = AccessibilityWinBrowserTest::QueryIAccessible2(
370 accessible, accessible2.Receive());
315 ASSERT_EQ(S_OK, hr); 371 ASSERT_EQ(S_OK, hr);
316 long ia2_role = 0; 372 long ia2_role = 0;
317 hr = accessible2->role(&ia2_role); 373 hr = accessible2->role(&ia2_role);
318 ASSERT_EQ(S_OK, hr); 374 ASSERT_EQ(S_OK, hr);
319 EXPECT_EQ(ia2_role_, ia2_role) 375 EXPECT_EQ(ia2_role_, ia2_role)
320 << "Expected ia2 role: " << IAccessible2RoleToString(ia2_role_) 376 << "Expected ia2 role: " << IAccessible2RoleToString(ia2_role_)
321 << "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role); 377 << "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role);
322 } 378 }
323 379
324 void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) { 380 void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
(...skipping 29 matching lines...) Expand all
354 // Avoid flakiness. The "offscreen" state depends on whether the browser 410 // Avoid flakiness. The "offscreen" state depends on whether the browser
355 // window is frontmost or not, and "hottracked" depends on whether the 411 // window is frontmost or not, and "hottracked" depends on whether the
356 // mouse cursor happens to be over the element. 412 // mouse cursor happens to be over the element.
357 obj_state &= ~(STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_HOTTRACKED); 413 obj_state &= ~(STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_HOTTRACKED);
358 EXPECT_EQ(state_, obj_state) 414 EXPECT_EQ(state_, obj_state)
359 << "Expected state: " << IAccessibleStateToString(state_) 415 << "Expected state: " << IAccessibleStateToString(state_)
360 << "\nGot state: " << IAccessibleStateToString(obj_state); 416 << "\nGot state: " << IAccessibleStateToString(obj_state);
361 } 417 }
362 418
363 void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) { 419 void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
364 LONG child_count = 0; 420 std::vector<base::win::ScopedVariant> obtained_children =
365 HRESULT hr = parent->get_accChildCount(&child_count); 421 AccessibilityWinBrowserTest::GetAllAccessibleChildren(parent);
366 EXPECT_EQ(S_OK, hr); 422 size_t child_count = obtained_children.size();
367 ASSERT_EQ(child_count, children_.size()); 423 ASSERT_EQ(child_count, children_.size());
368 424
369 scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]); 425 AccessibleCheckerVector::iterator child_checker;
370 LONG obtained_count = 0; 426 std::vector<base::win::ScopedVariant>::iterator child;
371 hr = AccessibleChildren(parent, 0, child_count, 427 for (child_checker = children_.begin(),
372 child_array.get(), &obtained_count); 428 child = obtained_children.begin();
dmazzoni 2014/11/06 06:53:30 I'd indent this 4 more spaces as a continuation of
373 ASSERT_EQ(S_OK, hr); 429 child_checker != children_.end()
374 ASSERT_EQ(child_count, obtained_count); 430 && child != obtained_children.end();
dmazzoni 2014/11/06 06:53:30 same here - indent 4 more.
375
376 VARIANT* child = child_array.get();
377 for (AccessibleCheckerVector::iterator child_checker = children_.begin();
378 child_checker != children_.end();
379 ++child_checker, ++child) { 431 ++child_checker, ++child) {
380 base::win::ScopedComPtr<IAccessible> child_accessible( 432 base::win::ScopedComPtr<IAccessible> child_accessible(
381 GetAccessibleFromResultVariant(parent, child)); 433 AccessibilityWinBrowserTest::GetAccessibleFromVariant(parent,
dmazzoni 2014/11/06 06:53:30 It'd be more readable if you didn't need the Acces
434 child->AsInput()));
dmazzoni 2014/11/06 06:53:30 indent 4 more
382 ASSERT_TRUE(child_accessible.get()); 435 ASSERT_TRUE(child_accessible.get());
383 (*child_checker)->CheckAccessible(child_accessible); 436 (*child_checker)->CheckAccessible(child_accessible);
384 } 437 }
385 } 438 }
386 439
387 base::string16 AccessibleChecker::RoleVariantToString( 440 base::string16 AccessibleChecker::RoleVariantToString(
388 const base::win::ScopedVariant& role) { 441 const base::win::ScopedVariant& role) {
389 if (role.type() == VT_I4) 442 if (role.type() == VT_I4)
390 return IAccessibleRoleToString(V_I4(&role)); 443 return IAccessibleRoleToString(V_I4(&role));
391 if (role.type() == VT_BSTR) 444 if (role.type() == VT_BSTR)
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 std::wstring()); 799 std::wstring());
747 AccessibleChecker grouping2_checker(std::wstring(), ROLE_SYSTEM_GROUPING, 800 AccessibleChecker grouping2_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
748 std::wstring()); 801 std::wstring());
749 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT, 802 AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
750 std::wstring()); 803 std::wstring());
751 document_checker.AppendExpectedChild(&grouping1_checker); 804 document_checker.AppendExpectedChild(&grouping1_checker);
752 document_checker.AppendExpectedChild(&grouping2_checker); 805 document_checker.AppendExpectedChild(&grouping2_checker);
753 document_checker.CheckAccessible(GetRendererAccessible()); 806 document_checker.CheckAccessible(GetRendererAccessible());
754 } 807 }
755 808
809 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, TestTextAtOffset) {
dmazzoni 2014/11/06 06:53:30 Consider splitting this into several smaller tests
810 const std::wstring input_contents(L"Mozilla/5.0 (NT 6.x; WOW64) "
811 L"WebKit (KHTML, like).");
812 const std::wstring textarea_contents(L"Mozilla/5.0 (NT 6.x; WOW64)\n"
813 L"WebKit \n(KHTML, like).");
814 ASSERT_EQ(input_contents.size(), textarea_contents.size());
815 LONG contents_length = static_cast<LONG>(input_contents.size());
816 LoadInitialAccessibilityTreeFromHtml("<!DOCTYPE html>"
817 "<html><body><form>"
818 "<label for='name'>Browser name:</label>"
819 "<input type='text' id='name' name='name' value='"
820 "Mozilla/5.0 (NT 6.x; WOW64) WebKit "
821 "(KHTML, like).'>"
822 "</form><textarea rows='3' cols='60'>"
823 "<b>Moz</b>illa/<i>5.0 (NT</i> 6.x; WOW64)<br>"
824 "WebKit <u><br>(KHTML,</u> like)."
825 "</textarea></body></html>");
826
827 // Retrieve the IAccessible interface for the web page.
828 base::win::ScopedComPtr<IAccessible> document(GetRendererAccessible());
829 std::vector<base::win::ScopedVariant> document_children =
830 GetAllAccessibleChildren(document);
831 ASSERT_EQ(2, document_children.size());
832
833 base::win::ScopedComPtr<IAccessible2> form;
834 HRESULT hr = QueryIAccessible2(GetAccessibleFromVariant(
835 document, document_children[0].AsInput()), form.Receive());
836 ASSERT_EQ(S_OK, hr);
837 std::vector<base::win::ScopedVariant> form_children =
838 GetAllAccessibleChildren(form);
839 ASSERT_EQ(2, form_children.size());
840
841 // Find the two edit fields (simple and text area).
842 base::win::ScopedComPtr<IAccessible2> input;
843 hr = QueryIAccessible2(GetAccessibleFromVariant(
844 form, form_children[1].AsInput()), input.Receive());
845 ASSERT_EQ(S_OK, hr);
846 base::win::ScopedVariant input_role;
847 hr = input->get_accRole(
848 base::win::ScopedVariant(CHILDID_SELF), input_role.Receive());
849 ASSERT_EQ(S_OK, hr);
850 ASSERT_EQ(VT_I4, input_role.type());
851
852 base::win::ScopedComPtr<IAccessible2> textarea;
853 hr = QueryIAccessible2(GetAccessibleFromVariant(
854 document, document_children[1].AsInput()), textarea.Receive());
855 ASSERT_EQ(S_OK, hr);
856 base::win::ScopedVariant textarea_role;
857 hr = textarea->get_accRole(
858 base::win::ScopedVariant(CHILDID_SELF), textarea_role.Receive());
859 ASSERT_EQ(S_OK, hr);
860 ASSERT_EQ(VT_BSTR, textarea_role.type());
861
862 // Retrieve the IAccessibleText interface for both of the fields.
863 base::win::ScopedComPtr<IAccessibleText> input_text;
864 hr = input_text.QueryFrom(input);
865 ASSERT_EQ(S_OK, hr);
866 base::win::ScopedComPtr<IAccessibleText> textarea_text;
867 hr = textarea_text.QueryFrom(textarea);
868 ASSERT_EQ(S_OK, hr);
869 // Set the caret on the last character.
870 LONG caret_offset = 49;
871 hr = input_text->setCaretOffset(49);
872 ASSERT_EQ(S_OK, hr);
873 hr = textarea_text->setCaretOffset(49);
874 ASSERT_EQ(S_OK, hr);
875
876 // Test invalid arguments.
877 hr = input_text->get_textAtOffset(
878 0, IA2_TEXT_BOUNDARY_CHAR, NULL, NULL, NULL);
879 EXPECT_EQ(E_INVALIDARG, hr);
880 hr = textarea_text->get_textAtOffset(
881 0, IA2_TEXT_BOUNDARY_CHAR, NULL, NULL, NULL);
882 EXPECT_EQ(E_INVALIDARG, hr);
883
884 // Test invalid offset.
885 LONG invalid_offset = -5;
886 LONG start_offset = 0;
887 LONG end_offset = 0;
888 base::win::ScopedBstr text;
889 hr = input_text->get_textAtOffset(
890 invalid_offset, IA2_TEXT_BOUNDARY_WORD,
891 &start_offset, &end_offset, text.Receive());
892 EXPECT_EQ(E_FAIL, hr);
893 hr = textarea_text->get_textAtOffset(
894 invalid_offset, IA2_TEXT_BOUNDARY_WORD,
895 &start_offset, &end_offset, text.Receive());
896 EXPECT_EQ(E_FAIL, hr);
897 invalid_offset = contents_length;
898 hr = input_text->get_textAtOffset(
899 invalid_offset, IA2_TEXT_BOUNDARY_WORD,
900 &start_offset, &end_offset, text.Receive());
901 EXPECT_EQ(E_FAIL, hr);
902 hr = textarea_text->get_textAtOffset(
903 invalid_offset, IA2_TEXT_BOUNDARY_WORD,
904 &start_offset, &end_offset, text.Receive());
905 EXPECT_EQ(E_FAIL, hr);
906
907 // Test character navigation.
908 for (LONG offset = 0; offset < contents_length; ++offset) {
909 std::wstring expected_text(textarea_contents[offset], 1);
910 LONG expected_start_offset = offset;
911 LONG expected_end_offset = offset + 1;
912 CheckTextAtOffset(input_text, offset, IA2_TEXT_BOUNDARY_CHAR,
913 expected_start_offset, expected_end_offset, expected_text);
914 }
915 for (LONG offset = contents_length - 1; offset >= 0; --offset) {
916 std::wstring expected_text(textarea_contents[offset], 1);
917 LONG expected_start_offset = offset;
918 LONG expected_end_offset = offset + 1;
919 CheckTextAtOffset(textarea_text, offset, IA2_TEXT_BOUNDARY_CHAR,
920 expected_start_offset, expected_end_offset, expected_text);
921 }
922 // Test special offsets.
923 CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_LENGTH,
924 IA2_TEXT_BOUNDARY_CHAR, 49, contents_length, L".");
925 CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET,
926 IA2_TEXT_BOUNDARY_CHAR, 49, contents_length, L".");
927 CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_LENGTH,
928 IA2_TEXT_BOUNDARY_CHAR, 49, contents_length, L".");
929 CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET,
930 IA2_TEXT_BOUNDARY_CHAR, 49, contents_length, L".");
931
932 // Test word navigation.
933 // (Imitate Firefox behavior.)
934 // Trailing punctuation should be included as part of the previous word.
935 CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_WORD,
936 0, 8, L"Mozilla/");
937 CheckTextAtOffset(textarea_text, 6, IA2_TEXT_BOUNDARY_WORD,
938 0, 8, L"Mozilla/");
939 // If the offset is at the punctuation, it should return
dmazzoni 2014/11/06 06:53:30 Nit: no indentatino for this comment.
940 // the previous word.
941 CheckTextAtOffset(textarea_text, 7, IA2_TEXT_BOUNDARY_WORD,
942 0, 8, L"Mozilla/");
943 // Numbers with a decimal point (U.S), should be treated as two words.
944 CheckTextAtOffset(input_text, 8, IA2_TEXT_BOUNDARY_WORD,
945 8, 10, L"5.");
946 CheckTextAtOffset(textarea_text, 9, IA2_TEXT_BOUNDARY_WORD,
947 8, 10, L"5.");
948 // Also, trailing punctuation that occurs after empty space should not be
949 // part of the word. ("0 " and not "0 (".)
950 CheckTextAtOffset(input_text, 10, IA2_TEXT_BOUNDARY_WORD,
951 10, 12, L"0 ");
952 CheckTextAtOffset(textarea_text, 11, IA2_TEXT_BOUNDARY_WORD,
953 10, 12, L"0 ");
954 // Leading punctuation should be included with the word after it.
955 CheckTextAtOffset(input_text, 12, IA2_TEXT_BOUNDARY_WORD,
956 12, 16, L"(NT ");
957 CheckTextAtOffset(textarea_text, 15, IA2_TEXT_BOUNDARY_WORD,
958 12, 16, L"(NT ");
959 // Numbers separated from letters with trailing punctuation should
960 // behave like decimal numbers above.
961 CheckTextAtOffset(input_text, 16, IA2_TEXT_BOUNDARY_WORD,
962 16, 18, L"6.");
963 CheckTextAtOffset(textarea_text, 19, IA2_TEXT_BOUNDARY_WORD,
964 18, 21, L"x; ");
965 // Words with numbers should be treated like ordinary words.
966 CheckTextAtOffset(input_text, 24, IA2_TEXT_BOUNDARY_WORD,
967 21, 28, L"WOW64) ");
968 CheckTextAtOffset(textarea_text, 26, IA2_TEXT_BOUNDARY_WORD,
969 21, 28, L"WOW64)\n");
970 // Multiple trailing empty spaces should be part of the word preceding it.
971 CheckTextAtOffset(input_text, 30, IA2_TEXT_BOUNDARY_WORD,
972 28, 36, L"WebKit ");
973 CheckTextAtOffset(textarea_text, 35, IA2_TEXT_BOUNDARY_WORD,
974 28, 36, L"WebKit \n");
975 // Test special offsets.
976 CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_LENGTH,
977 IA2_TEXT_BOUNDARY_WORD, 44, contents_length, L"like).");
978 CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET,
979 IA2_TEXT_BOUNDARY_WORD, 44, contents_length, L"like).");
980 CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_LENGTH,
981 IA2_TEXT_BOUNDARY_WORD, 44, contents_length, L"like).");
982 CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET,
983 IA2_TEXT_BOUNDARY_WORD, 44, contents_length, L"like).");
984
985 // Test sentence navigation (not currently implemented).
986 hr = input_text->get_textAtOffset(
987 5, IA2_TEXT_BOUNDARY_SENTENCE,
988 &start_offset, &end_offset, text.Receive());
989 EXPECT_EQ(S_FALSE, hr);
990 hr = textarea_text->get_textAtOffset(
991 25, IA2_TEXT_BOUNDARY_CHAR,
992 &start_offset, &end_offset, text.Receive());
993 EXPECT_EQ(S_FALSE, hr);
994
995 // Test line navigation.
996 CheckTextAtOffset(textarea_text, 0, IA2_TEXT_BOUNDARY_LINE,
997 0, 28, L"Mozilla/5.0 (NT 6.x; WOW64)\n");
998 // If the offset is at the newline, return the line preceding it.
999 CheckTextAtOffset(textarea_text, 35, IA2_TEXT_BOUNDARY_LINE,
1000 28, 36, L"WebKit \n");
1001 // Last line does not have a trailing newline.
1002 CheckTextAtOffset(textarea_text, 36, IA2_TEXT_BOUNDARY_LINE,
1003 36, contents_length, L"(KHTML, like).");
1004 // Test special offsets.
1005 CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_LENGTH,
1006 IA2_TEXT_BOUNDARY_LINE, 36, contents_length, L"(KHTML, like).");
1007 CheckTextAtOffset(input_text, IA2_TEXT_OFFSET_CARET,
1008 IA2_TEXT_BOUNDARY_LINE, 36, contents_length, L"(KHTML, like).");
1009 CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_LENGTH,
1010 IA2_TEXT_BOUNDARY_LINE, 36, contents_length, L"(KHTML, like).");
1011 CheckTextAtOffset(textarea_text, IA2_TEXT_OFFSET_CARET,
1012 IA2_TEXT_BOUNDARY_LINE, 36, contents_length, L"(KHTML, like).");
1013
1014 // Return the whole of the text.
1015 CheckTextAtOffset(input_text, 0, IA2_TEXT_BOUNDARY_ALL,
1016 0, contents_length, input_contents);
1017 CheckTextAtOffset(textarea_text, contents_length - 1, IA2_TEXT_BOUNDARY_ALL,
1018 0, contents_length, textarea_contents);
1019 }
1020
756 } // namespace content 1021 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/browser/accessibility/browser_accessibility.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698